Adding sample results to a list while looping - random

Attempting to build a random walk simulation that counts how many times a level is reached within a given number of steps. The amount is then passed into a list. My issue is that I would like to run multiple samples in a row, adding the individual results to the list. Right now the code produces a list with ten items, but they are all the same.
ie:
"sample" = 10
"steps" = 1000
the code runs 10, one thousand step random walk sessions, each one a sampling, and produces a list with 10 unique results of how many times the level of 100 was reached during each run.
Thanks in advance.
import random
sample = input('Samples : ')
steps = input('Steps : ')
s = 0
a = 0
x = 0
list1 = []
list2 = []
while s < int(sample):
s = s + 1
while a < int(steps):
a = a + 1
r = random.randint(-1,1)
x = x + r
if x == 100:
list1.append(x)
y = len(list1)
list2.append(y)
print(list2)

I think you'd want to reset a and list1 at the start of each sample, no? That is, move their initializations to just before the start of the inner while loop. Since you don't reset a, the inner loop never gets entered after the first sample is done, so y never changes any more, so you keep getting the count from the first sample.
And the only time you append to list1 is when x reaches 100, which is unlikely to happen at all given a limit of 1000 steps. (Why do you need a list, since you only care about the count, and know you'll be appending 100 each time?)

Related

Grouping data using loops (signal processing in MATLAB)

I am working in MATLAB with a signal data that consist of consecutive dips as shown below. I am trying to write a code which sorts the contents of each dip into a separate group. How should the general structure of such a code look like?
The following is my data. I am only interested in the portion of the signal that lies below a certain threshold d (the red line):
And here is the desired grouping:
Here is an unsuccessful attempt:
k=0; % Group number
for i = 1 : length(signal)
if signal(i) < d
k=k+1;
while signal(i) < d
NewSignal(i, k) = signal(i);
i = i + 1;
end
end
end
The code above generated 310 groups instead of the desired 12 groups.
Any explanation would be greatly appreciated.
Taking Benl generated data you can do the following:
%generate data
x=1:1000;
y=sin(x/20);
for ii=1:9
y=y+-10*exp(-(x-ii*100).^2./10);
end
y=awgn(y,4);
%set threshold
t=-4;
%threshold data
Y = char(double(y<t) + '0'); %// convert to string of zeros and ones
%search for start and ends
This idea is taken from here
[s, e] = regexp(Y, '1+', 'start', 'end');
%and now plot and see that each pair of starts and end
% represents a group
plot(x,y)
hold on
for k=1:numel(s)
line(s(k)*ones(2,1),ylim,'Color','k','LineStyle','--')
line(e(k)*ones(2,1),ylim,'Color','k','LineStyle','-')
end
hold off
legend('Data','Starts','Ends')
Comments: First of all I choose an arbitrary threshold, it is up to you to find the "best" one in your data. Additionally I didn't group the data explicitly but rather this approach gives you the start and end of each epoch with a dip (you might call it group). So you could say that each index is the grouping index. Finally I did not debug this approach for corner cases, when dips fall on starts and ends...
In MATLAB you cannot change the loop index of a for loop. A for loop:
for i = array
loops over each column of array in turn. In your code, 1 : length(signal) is an array, each of its elements is visited in turn. Inside this loop there is a while loop that increments i. However, when this while loop ends and the next iteration of the for loop runs, i is reset to the next item in the array.
This code therefore needs two while loops:
i = 1; % Index
k = 0; % Group number
while i <= numel(signal)
if signal(i) < d
k = k + 1;
while signal(i) < d
NewSignal(i,k) = signal(i);
i = i + 1;
end
end
i = i + 1;
end
Easy, the function you're looking for is bwlabel, which when combined with logical indexing makes this simple.
To start I made some fake data which resembled your data
x=1:1000;
y=sin(x/20);
for ii=1:9
y=y+-10*exp(-(x-ii*100).^2./10);
end
y=awgn(y,4);
plot(x,y)
Then set your threshold and use 'bwlabel'
d=-4;% set the threshold
groupid=bwlabel(y<d);
bwlabel labels connected groups in a black and white image, what we've effectively done here is make a black and white (logical 0 & 1) 1D image in the logical vector y<d. bwlabel returns the number of the region at the index of the region. We're not interested in the 0 region, so to get the x values or y values of the nth region, simply use x(groupid==n), for example with my test data
x_4=x(groupid==4)
y_4=y(groupid==4)
x_4 = 398 399 400 401 402
y_4 = -5.5601 -7.8280 -9.1965 -7.9083 -5.8751

A simple Increasing Mathematical Algorithm

I actually tried to search this, I'm sure this basic algorithm is everywhere on internet, CS textbooks etc, but I cannot find the right words to search it.
What I want from this algorithm to do is write "A" and "B" with the limit always increasing by 2. Like I want it to write A 3 times, then B 5 times, then A 7 times, then B 9 times and so on. And I plan to have 100 elements in total.
Like: AAABBBBBAAAAAAABBBBBBBBB...
I only want to use a single "for loop" for the entire 100 elements starting from 1 to 100. And just direct/sort "A" and "B" through "if/else if/ else".
I'm just asking for the basic mathematical algorithm behind it, showing it through any programming language would be better or redirecting me to such topic would also be fine.
You can do something like this:
There might be shorter answers, but I find this one easy to understand.
Basically, you keep a bool variable that will tell you if it's A's turn or Bs. Then we keep a variable switch that will tell us when we should switch between them. times is being updated with the repeated times we need to print the next character.
A_B = true
times = 3 // 3,5,7,9,...
switch = 3 // 3,8,15,24,...
for (i from 1 to 100)
if (A_B)
print 'A'
else
print 'B'
if (i == switch)
times += 2
switch += times
A_B = !A_B
Python:
for n in range(1, 101):
print "BA"[(int(sqrt(n)) % 2)],
The parity of the square roots of the integers follows that pattern. (Think that (n+1)²-n² = 2n+1.)
If you prefer to avoid the square root, it suffices to use an extra variable that represents the integer square root and keep it updated
r= 1
for n in range(1, 101):
if r * r <= n:
r+= 1
print "AB"[r % 2],
Here is the snippet you can test on this page. It is an example for about 500 letters totally, sure you can modify it for 100 letters. It is quite flexible that you can change the constants to produce lot of different strings in the same manner.
var toRepeat = ['A', 'B'];
var result='', j, i=3;
var sum=i;
var counter = 0;
while (sum < 500) {
j = counter % 2;
result = result + toRepeat[j].repeat(i);
sum = sum + i;
i = i + 2;
counter++;
}
document.getElementById('hLetters').innerHTML=result;
console.log(result);
<div id="hLetters"></div>
If you want it to be exactly 500 / 100 letters, just use a substring function to trim off the extra letters from the end.
To get 100 groups of A and B with increasing length of 3, 5, 7 and so on, you can run this Python code:
''.join(('B' if i % 2 else 'A') * (2 * i + 3) for i in range(100))
The output is a string of 10200 characters.
If you want the output to have only 100 characters, you can use:
import math
''.join(('B' if math.ceil(math.sqrt(i)) % 2 else 'A') for i in range(2, 102))
In js you can start with somethink like this :
$res ="";
count2 = 0;
for (i=2;i<100; i = i+2) {
count = 0;
alert(i);
while (count < i ) {
$res = $res.concat(String.fromCharCode(65+count2));
count++;
}
count2++;
}
alert ($res);

How to add in a loop in ruby?

Just started learning about loops in ruby and I'm trying to figure out how to add a number to itself.. Like 1+1+1+1+1...
I've tried variations of
3.times() do
self.+(self)
end
But always get undefined method '+'.
I've done this too
number = 1
3.times() do
number = number.+(number)
end
Although it works, it isn't what I'm really trying to do since it's giving me 8, and I just wanted it to be 4 by adding 1+1 over and over. Also I want to be able to use any number not necessarily always 1.
Using times you can do it like:
number = 1
3.times do
number += number
end
puts number
#=> 3
number += number is just a shortcut for number = number + number
Perhaps having another variable to hold onto the sum could fix your issue. Right now, your number starts as 1. Then your loop runs 3 times and looks like the following:
(number = number.+(number))
Loop 1:
number = 1.+(1) ==> 2
number = 2.+(2) ==> 4
number = 4.+(4) ==> 8
Above youre actually multiplying the number by itself X.times
Instead, store the sum of the numbers in a separate variable like this:
sumOfNumbers = 0
numberToAdd = 1
3.times() do
sumOfNumbers = sumOfNumbers.+(numberToAdd)
end
or better yet
sumOfNumbers += numberToAdd

Fast way of checking if an element is ranked higher than another

I am writing in MATLAB a program that checks whether two elements A and B were exchanged in ranking positions.
Example
Assume the first ranking is:
list1 = [1 2 3 4]
while the second one is:
list2 = [1 2 4 3]
I want to check whether A = 3 and B = 4 have exchanged relative positions in the rankings, which in this case is true, since in the first ranking 3 comes before 4 and in the second ranking 3 comes after 4.
Procedure
In order to do this, I have written the following MATLAB code:
positionA1 = find(list1 == A);
positionB1 = find(list1 == B);
positionA2 = find(list2 == A);
positionB2 = find(list2 == B);
if (positionA1 <= positionB1 && positionA2 >= positionB2) || ...
(positionA1 >= positionB1 && positionA2 <= positionB2)
... do something
end
Unfortunately, I need to run this code a lot of times, and the find function is really slow (but needed to get the element position in the list).
I was wondering if there is a way of speeding up the procedure. I have also tried to write a MEX file that performs in C the find operation, but it did not help.
If the lists don't change within your loop, then you can determine the positions of the items ahead of time.
Assuming that your items are always integers from 1 to N:
[~, positions_1] = sort( list1 );
[~, positions_2] = sort( list2 );
This way you won't need to call find within the loop, you can just do:
positionA1 = positions_1(A);
positionB1 = positions_1(B);
positionA2 = positions_2(A);
positionB2 = positions_2(B);
If your loop is going over all possible combinations of A and B, then you can also vectorize that
Find the elements that exchanged relative ranking:
rank_diff_1 = bsxfun(#minus, positions_1, positions_1');
rank_diff_2 = bsxfun(#minus, positions_2, positions_2');
rel_rank_changed = sign(rank_diff_1) ~= sign(rank_diff_2);
[A_changed, B_changed] = find(rel_rank_changed);
Optional: Throw out half of the results, because if (3,4) is in the list, then (4,3) also will be, and maybe you don't want that:
mask = (A_changed < B_changed);
A_changed = A_changed(mask);
B_changed = B_changed(mask);
Now loop over only those elements that have exchanged relative ranking
for ii = 1:length(A_changed)
A = A_changed(ii);
B = B_changed(ii);
% Do something...
end
Instead of find try to compute something like this
Check if there is any exchanged values.
if logical(sum(abs(list1-list2)))
do something
end;
For specific values A and B:
if (list1(logical((list1-list2)-abs((list1-list2))))==A)&&(list1(logical((list1-list2)+abs((list1-list2))))==B)
do something
end;

More Efficient Alternatives to Max and Min

So, I'm trying to optimize a program I made, and two glaring inefficiencies I have found with the help of the profiler are these:
if (min(image_arr(j,i,:)) > 0.1)
image_arr(j,i,:) = image_arr(j,i,:) - min(image_arr(j,i,:));
end
%"Grounds" the data, making sure the points start close to 0
Called 4990464 times, takes 58.126s total, 21.8% of total compile time.
[max_mag , max_index] = max(image_arr(j, i, :));
%finds the maximum value and its index in the set
Called 4990464 times, takes 50.900s total, 19.1% of total compile time.
Is there any alternative to max and min that I can use here, that would be more efficient?
There is no way to reduce the number of times these lines are called.
Based on the call count, these are probably inside a loop. Both min and max are vectorized (they work on vectors of vectors).
Since you want to find extrema along the third dimension, you can use:
image_arr = bsxfun(#minus, image_arr, min(image_arr, [], 3));
and
[max_mag , max_index] = max(image_arr, [], 3);
It seems like:
if (min(image_arr(j,i,:)) > 0.1)
image_arr(j,i,:) = image_arr(j,i,:) - min(image_arr(j,i,:));
end
could be rewritten like this:
data = image_arr(j,i,:);
mn = min(data);
if (mn > 0.1)
image_arr(j,i,:) = data - mn;
end
which seems like the inner loop of something that could be written like:
minarr = min(image_arr)
[a,b] = find(minarr > 0.1);
image_arr(a,b,:) = image_arr(a,b,:) - minarr(a,b)
Rename your i and j.
Those names have meaning to MATLAB, and every time it sees them it has to check whether you have your own definition or they mean sqrt(-1).
The first part can be done without loops using bsxfun.
m = min(image_arr,[],3);
image_arr = bsxfun(#minus, image_arr, m.*(m>0.1));

Resources