Replace values in a 2D array with different random numbers - python

I have a 2D array (image) in which I want to replace array values greater than some threshold with a random number in some range. My attempt was to use numpy.random.uniform, as so
Z[Z > some_value] = uniform(lower_limit,upper_limit)
However I've found that this replaces all values above the threshold with the same random value. I would like to replace all array values above the threshold with a different random value each.
I think this would require some interation over the entire array for which I would need to generate a random value if the condition is met. How would I do this?

You are correct that iteration would be the correct way to go. Let's do a list comprehension.
[uniform(lower_limit, upper_limit) if i > some_value else i
for i in Z]
Let's step through it. Take an individual value. If it is greater than the threshold, use a randomly generated one, otherwise the original value.
uniform(lower_limit, upper_limit) if i > some_value else i
Repeat this for every element in Z
for i in Z
For a 2D array, nest multiple comprehensions. Imagine that the above solution was to hit everything in one row and then repeat it for every row.
[[uniform(lower_limit, upper_limit) if i > some_value else i
for i in row]
for row in Z]

Check the third argument to uniform. Using size=N will yield an array of random values with length N. Thus
z[z>some_value] = np.random.uniform(lower, upper, len(z>some_value))
will do what you want.

Related

How do I remove items from a numpy array?

I have a big array of numbers which contain the data for the flux of a star. I want to remove all the data points below the value of 1. I used the code fluxbelow1=[i for i, j in enumerate(z) if j<1] to get the index for all the data points. I now want to remove these points from the original array and create a smaller array. How would I do that?
Numpy is particularly good at this.
fluxabove1 = z[z >= 1]
The "z >= 1" creates an array of booleans where the value is greater or equal to 1. We then use that to index into z and choose only those elements.

Find the first value that meets criteria, not its index

I have a array with these elements:
array= [21558 43101 64638 86173 107701 129232 150775 172355 193864 215457
237071 258586 280130 301687 23255 344790 366285 387838 409365 430856
452367 473893 495456 516955 538543 560110 581641 603188]
In my program, there is a variable n that is randomly sorted. What I'm trying to achieve is very simple, but I just can't get anything to work.
With the line below, I'll find the index of the first value that is greater than n
value_index=np.where(array > n)[0][0]
What I need is to find the value that it represents, not the index.
Of course, I can simply just insert the value_index variable and call the value in a list, but I'm tryign to be as efficient as possible.
Can anyone help me find the fastest way possible to find this value?
Numpy generally isn't very good at getting the first of something without first computing the rest of the values. There is no equivalent to Pythons's
next(x for x in array if x > n)
Instead, you have to compute the mask of x > n, and get the first index of that. There are better ways to do this than np.where:
ind = np.flatnonzero(array > n)[0]
OR
ind = np.argmax(array > n)[0]
In either case, your best bet to get the value is
array[ind]

Coding an iterated sum of sums in python

For alpha and k fixed integers with i < k also fixed, I am trying to encode a sum of the form
where all the x and y variables are known beforehand. (this is essentially the alpha coordinate of a big iterated matrix-vector multiplication)
For a normal sum varying over one index I usually create a 1d array A and set A[i] equal to the i indexed entry of the sum then use sum(A), but in the above instance the entries of the innermost sum depend on the indices in the previous sum, which in turn depend on the indices in the sum before that, all the way back out to the first sum which prevents me using this tact in a straightforward manner.
I tried making a 2D array B of appropriate length and width and setting the 0 row to be the entries in the innermost sum, then the 1 row as the entries in the next sum times sum(np.transpose(B),0) and so on, but the value of the first sum (of row 0) needs to vary with each entry in row 1 since that sum still has indices dependent on our position in row 1, so on and so forth all the way up to sum k-i.
A sum which allows for a 'variable' filled in by each position of the array it's summing through would thusly do the trick, but I can't find anything along these lines in numpy and my attempts to hack one together have thus far failed -- my intuition says there is a solution that involves summing along the axes of a k-i dimensional array, but I haven't been able to make this precise yet. Any assistance is greatly appreciated.
One simple attempt to hard-code something like this would be:
for j0 in range(0,n0):
for j1 in range(0,n1):
....
Edit: (a vectorized version)
You could do something like this: (I didn't test it)
temp = np.ones(n[k-i])
for j in range(0,k-i):
temp = x[:n[k-i-1-j],:n[k-i-j]].T#(y[:n[k-i-j]]*temp)
result = x[alpha,:n[0]]#(y[:n[0]]*temp)
The basic idea is that you try to press it into a matrix-vector form. (note that this is python3 syntax)
Edit: You should note that you need to change the "k-1" to where the innermost sum is (I just did it for all sums up to index k-i)
This is 95% identical to #sehigle's answer, but includes a generic N vector:
def nested_sum(XX, Y, N, alpha):
intermediate = np.ones(N[-1], dtype=XX.dtype)
for n1, n2 in zip(N[-2::-1], N[:0:-1]):
intermediate = np.sum(XX[:n1, :n2] * Y[:n2] * intermediate, axis=1)
return np.sum(XX[alpha, :N[0]] * Y[:N[0]] * intermediate)
Similarly, I have no knowledge of the expression, so I'm not sure how to build appropriate tests. But it runs :\

How to check is numpy 2d array "surrounded" by zeros

Is there any neat way to check is numpy array surrounded by zeros.
Example:
[[0,0,0,0],
[0,1,2,0],
[0,0,0,0]]
I know I can iterate it element wise to find out but I wonder is there any nice trick we can use here. The numpy array is of floats, n x m of arbitrary size.
Any ideas are welcome.
You can use numpy.any() to test if there is any non-zero element in numpy array.
Now, to test if a 2D array is surrounded by zeroes, you can get first and last columns as well as first and last rows and test if any of those contains a non-zero number.
def zero_surrounded(array):
return not (array[0,:].any() or array[-1,:].any() or array[:,0].any() or array[:,-1].any())
We can check this by constructing two submatrices:
A[[0,-1]] the first and the last row, including the first and last column; and
A[1:-1,[0,-1]] the first and last column, excluding the first and last row.
All the values of these matrices should be equal to zero, so we can use:
if np.all(A[[0,-1]] == 0) and np.all(A[1:-1,[0,-1]] == 0):
# ...
pass
This works for an arbitrary 2d-array, but not for arrays with arbitrary depth. We can however use a trick for that as well.
For an arbitrary matrix, we can use:
def surrounded_zero_dim(a):
n = a.ndim
sel = ([0,-1],)
sli = (slice(1,-1),)
return all(np.all(a[sli*i+sel] == 0) for i in range(n))
Using the slice is strictly speaking not necessary, but it prevents checking certain values twice.
Not the fastest, but perhaps the shortest (and hence a "neat") way of doing it:
surrounded = np.sum(a[1:-1, 1:-1]**2) == np.sum(a**2)
print(surrounded) # True
Here, a is the array.
This compares the sum of all squared elements to the sum of all squared elements except for those on the boundary. If we left out the squaring, cases where positive and negative boundary values add up to zero would produce the wrong answer.

Increment elements of a subset of elements in a 3d numpy array python

I have a 3d list formed by
myArray = np.array([[[0]*n for i in range(m)] for j in range(o)])
I have a loop that runs over all elements, and increments the value stored in the current element and a number of elements in the neighborhood of the current element:
myArray[xa:xb][ya:yb][za:zb] += 1.
where xa,xb, etc. are generated according to the current element considered in the loop, and not necessarily the same. In other words, I'd like to increment the values of a given sub-triangle in the 3D list.
However, when I try to address myArray[xa:xb][0][0], I get a list with length that is larger than len(myArray[0]). Not to mention myArray[xa:xb][ya:yb][za:zb] += 1 results in more elements to be incremented by 1 than desired.
I could achieve this by using three nested for loops:
for i in range(xa,xb+1):
for j in range(ya,yb+1):
for k in range(za,zb+1):
myArray[i][j][k] += 1
but this slows down the code a lot.
What can I do to achieve this without such a loss of performance?
You were on the right path from the beginning. The following seems to work:
myArray=np.zeros((o,m,n))
myArray[xa:xb+1,ya:yb+1,za:zb+1]+=1
Note that index slicing in arrays uses the same boundaries as range in your for loop, thus you have to +1 your end index. The procedure above replicates your triple for loops results, at a fraction of time.

Categories

Resources