How to select values in an array until a threshold value? - arrays

I will explain my problem. I have a 1x1701 sampled array "resampled_WF", once I found the max value of this array ("peak_WF"), I set a threshold 0.7*peak_WF, and I would like to select the farthest value in the array that gets nearer to this threshold.
Example:
power_vs_time_threshold
As you can see, I was able to select ony the first value that resembles... but I would like to get the last one (around t=2 sec).
I tried to flip the array with "flip" function:
WF_threshold_input = 0.7*peak_WF;
flip_resampled_WF = flip(resampled_WF);
diff_peak_threshold = peak_WF - WF_threshold_input; %power loss at 70% power reduction
diff_peak_WF = peak_WF - flip_resampled_WF;
min_diff_threshold = min(abs(diff_peak_WF-diff_peak_threshold));
Doing that, MATLAB computes minimum difference on the whole array, I would like to stop at the first value, not considering further values.
I tried to select values with values <= WF_threshold_input, but again it selects over the whole dataset.
How can I select the value properly?
Thanks!!

Using operations on the matrix will call the operation on every element in the matrix. What you want to do is use a loop so that you can control exactly what elements are examined and then break out of the loop.
index = length(resampled_WF);
your_threshold = ...
while resampled_WF(index) < your_threshold
index = index - 1;
end
The while loop will continue iteration until it reaches a value that is outside of your defined threshold.
After execution, the value of index will be the index of the furthest value in the array which is outside of your threshold. You can access the furthest value outside the threshold by looking at resampled_wf(index) after execution of the code.
We don't have to worry about the values of index leaving the bounds of the array, ie <1, since the condition resampled_wf < your_threshold is guaranteed to be met by the maximal value that you originally generated the threshold with.

Related

Python: Finding the row index of a value in 2D array when a condition is met

I have a 2D array PointAndTangent of dimension 8500 x 5. The data is row-wise with 8500 data rows and 5 data values for each row. I need to extract the row index of an element in 4th column when this condition is met, for any s:
abs(PointAndTangent[:,3] - s) <= 0.005
I just need the row index of the first match for the above condition. I tried using the following:
index = np.all([[abs(s - PointAndTangent[:, 3])<= 0.005], [abs(s - PointAndTangent[:, 3]) <= 0.005]], axis=0)
i = int(np.where(np.squeeze(index))[0])
which doesn't work. I get the follwing error:
i = int(np.where(np.squeeze(index))[0])
TypeError: only size-1 arrays can be converted to Python scalars
I am not so proficient with NumPy in Python. Any suggestions would be great. I am trying to avoid using for loop as this is small part of a huge simulation that I am trying.
Thanks!
Possible Solution
I used the following
idx = (np.abs(PointAndTangent[:,3] - s)).argmin()
It seems to work. It returns the row index of the nearest value to s in the 4th column.
You were almost there. np.where is one of the most abused functions in numpy. Half the time, you really want np.nonzero, and the other half, you want to use the boolean mask directly. In your case, you want np.flatnonzero or np.argmax:
mask = abs(PointAndTangent[:,3] - s) <= 0.005
mask is a 1D array with ones where the condition is met, and zeros elsewhere. You can get the indices of all the ones with flatnonzero and select the first one:
index = np.flatnonzero(mask)[0]
Alternatively, you can select the first one directly with argmax:
index = np.argmax(mask)
The solutions behave differently in the case when there are no rows meeting your condition. Three former does indexing, so will raise an error. The latter will return zero, which can also be a real result.
Both can be written as a one-liner by replacing mask with the expression that was assigned to it.

Changing the values of array by the distance of the indexes (c)

I'm having hard time with this one:
I need to write a function in C that recieving a binary array and his size, and the function should calculate and replace the current values with the distance (by indexes) of each 1 to the closest 0.
for example: if the function recieve that array {1,1,0,1,1,1,0,1} then the new values of the array should be {2,1,0,1,2,1,0,1}. It is known that the input has atleast 1 zero.
So the first step I tought about was to locate pair of zeros (or just 1 if there is only 1) and set them as 2 indexes (z1, z2). Then I set another index i
that check everytime which zero is the closest to him (absolute value) and then the diffrence between i and z1 or z2 would be the new value.
I have the plan but things are not going exactly as I planned. Basicly I deleted the code (it wasn't good anyway) so I would appreciate any help. thanks!
This problem is based on two things
Keep an array left[i] which has the distance of nearest 0 from index i from left to right.
Keep an array right[i] which has the distance of nearest 0 from index i from right to left.
Both can be calculate in single loop iteration. O(n).
Then for each position get the minimum value of left[i] and right[i]. That will be the answer for 1 staying in position i.
Overall the time complexity is O(n).

Why should this be a while statement and not an if statement?

Did a test for class.. and they provided a sample test. One of the questions gave the following code which calculates the average of the items in a list , they then asked us to find all the errors:
# brightness levels –maximum is 100
shape_brightness = [15,92,38,42]
item_no = 0
total = 0
if (item_no < len(shape_brightness):
total = shape_brightness[item_no]
item_no = item_no + 1
average = total / item_no
print(“The average brightness level is “+str(averge))
However, in the solution they said the biggest error was that it should actually be a while statement .. and i dont understand why? Any explanation as to why??
You need to iterate over all elements to calculate the average. The if statement only visits the first element in this array.
When your code accesses shape_brightness[item_no], item_no is the index, so as it is 0, shape_brightness[item_no] is just the number 15. In order to include all the other values of shape_brightness in your average calculation, you want to access them as well, so to do that you increase your index item_no as many times as the number of elements you want to access by using a loop.
A while loop would be one way of iterating over all elements, and changing the 'if' to 'while' would be the fastest correction to this code, but a for loop, with additional changes, would also work. E.g.
for item in range(len(shape_brightness)):
execute
in which case the item_no counter becomes unnecessary.
Simple:
Because you need to iterate an array. That tranlates: you need some form of looping!
And if statement does not have that repetitive part required here!
You need to use a while loop because for calculating the sum and number of values for average. You need to repetitively add the values of shape brightness until you have added all the values. Currently, you are using an if block which is considering only first value of shape_brightness array. You need to put
total = shape_brightness[item_no]
item_no = item_no + 1
inside while loop
while(item_no < len(shape_brightness))

Randomize matrix elements between two values while keeping row and column sums fixed (MATLAB)

I have a bit of a technical issue, but I feel like it should be possible with MATLAB's powerful toolset.
What I have is a random n by n matrix of 0's and w's, say generated with
A=w*(rand(n,n)<p);
A typical value of w would be 3000, but that should not matter too much.
Now, this matrix has two important quantities, the vectors
c = sum(A,1);
r = sum(A,2)';
These are two row vectors, the first denotes the sum of each column and the second the sum of each row.
What I want to do next is randomize each value of w, for example between 0.5 and 2. This I would do as
rand_M = (0.5-2).*rand(n,n) + 0.5
A_rand = rand_M.*A;
However, I don't want to just pick these random numbers: I want them to be such that for every column and row, the sums are still equal to the elements of c and r. So to clean up the notation a bit, say we define
A_rand_c = sum(A_rand,1);
A_rand_r = sum(A_rand,2)';
I want that for all j = 1:n, A_rand_c(j) = c(j) and A_rand_r(j) = r(j).
What I'm looking for is a way to redraw the elements of rand_M in a sort of algorithmic fashion I suppose, so that these demands are finally satisfied.
Now of course, unless I have infinite amounts of time this might not really happen. I therefore accept these quantities to fall into a specific range: A_rand_c(j) has to be an element of [(1-e)*c(j),(1+e)*c(j)] and A_rand_r(j) of [(1-e)*r(j),(1+e)*r(j)]. This e I define beforehand, say like 0.001 or something.
Would anyone be able to help me in the process of finding a way to do this? I've tried an approach where I just randomly repick the numbers, but this really isn't getting me anywhere. It does not have to be crazy efficient either, I just need it to work in finite time for networks of size, say, n = 50.
To be clear, the final output is the matrix A_rand that satisfies these constraints.
Edit:
Alright, so after thinking a bit I suppose it might be doable with some while statement, that goes through every element of the matrix. The difficult part is that there are four possibilities: if you are in a specific element A_rand(i,j), it could be that A_rand_c(j) and A_rand_r(i) are both too small, both too large, or opposite. The first two cases are good, because then you can just redraw the random number until it is smaller than the current value and improve the situation. But the other two cases are problematic, as you will improve one situation but not the other. I guess it would have to look at which criteria is less satisfied, so that it tries to fix the one that is worse. But this is not trivial I would say..
You can take advantage of the fact that rows/columns with a single non-zero entry in A automatically give you results for that same entry in A_rand. If A(2,5) = w and it is the only non-zero entry in its column, then A_rand(2,5) = w as well. What else could it be?
You can alternate between finding these single-entry rows/cols, and assigning random numbers to entries where the value doesn't matter.
Here's a skeleton for the process:
A_rand=zeros(size(A)) is the matrix you are going to fill
entries_left = A>0 is a binary matrix showing which entries in A_rand you still need to fill
col_totals=sum(A,1) is the amount you still need to add in every column of A_rand
row_totals=sum(A,2) is the amount you still need to add in every row of A_rand
while sum( entries_left(:) ) > 0
% STEP 1:
% function to fill entries in A_rand if entries_left has rows/cols with one nonzero entry
% you will need to keep looping over this function until nothing changes
% update() A_rand, entries_left, row_totals, col_totals every time you loop
% STEP 2:
% let (i,j) be the indeces of the next non-zero entry in entries_left
% assign a random number to A_rand(i,j) <= col_totals(j) and <= row_totals(i)
% update() A_rand, entries_left, row_totals, col_totals
end
update()
A_rand(i,j) = random_value;
entries_left(i,j) = 0;
col_totals(j) = col_totals(j) - random_value;
row_totals(i) = row_totals(i) - random_value;
end
Picking the range for random_value might be a little tricky. The best I can think of is to draw it from a relatively narrow distribution centered around N*w*p where p is the probability of an entry in A being nonzero (this would be the average value of row/column totals).
This doesn't scale well to large matrices as it will grow with n^2 complexity. I tested it for a 200 by 200 matrix and it worked in about 20 seconds.

Setting elements of a 3d array to zero in matlab

I do have a three dimensional array A(m,n,t), (8 x 60 x 8), filled with positive numbers.
What I am trying to do is to set every element of this array to zero if the third index (t) is smaller than the first (m).
So for examle A(5,42,3) should be set to 0 as m=5 > t=3. However A(5,13,7) should not be changed, hence m=5 <= t=7.
If one would look at squeeze(A(:,val,:)) where val is any number from 1 to 60, then what I am trying to do is to set the lower triangular matrix to zero.
My approach was a loop over the first index doing
for ii=2:8
A(ii,:,1:ii-1)=0;
end
However this uses a loop and I am almost certain there should be a (smart) way without it.
So how does one do this without the use of a loop?
try this:
[xg,yg,zg]=ndgrid(1:size(arr,1),1:size(arr,2),1:size(arr,3));
arr(xg>zg)=0;

Resources