How to correctly vectorise a function using numpy? - arrays

I'm new to numpy and I must be doing something stupid here, but all I want is to generate an array of 4-dimention probability distributions. I don't understand why my vectorised function is returning this weird object which claims to be of type np.ndarray but doesn't print like one. Also, it returns error when I call self.inputSpace[:,0].
Here's the entire content of test.py:
import numpy as np
def generateDist(i,j,k):
return np.squeeze(np.array([i*j,i*(1-j),(1-i)*k,(1-i)*(1-k)]))
generateDist = np.vectorize(generateDist,otypes=[np.ndarray])
class distributionSpace():
def __init__(self):
self.grid = 3 # set to 3 for simplicity
self.inputSpace = np.array([])
def generateDistribution(self):
alpha = np.linspace(0.,1.,self.grid)
beta = np.linspace(0.,1.,self.grid)
gamma = np.linspace(0.,1.,self.grid)
i , j , k = np.meshgrid(alpha,beta,gamma)
i = np.squeeze(i.flatten())
j = np.squeeze(j.flatten())
k = np.squeeze(k.flatten())
self.inputSpace = generateDist(i,j,k)
print(self.inputSpace)
return self
if __name__ == '__main__':
distributionSpace().generateDistribution()
And here's the result I got:
$ python3 test.py
[array([ 0., 0., 0., 1.]) array([ 0. , 0. , 0.5, 0.5])
array([ 0., 0., 1., 0.]) array([ 0. , 0.5, 0. , 0.5])
array([ 0. , 0.5 , 0.25, 0.25]) array([ 0. , 0.5, 0.5, 0. ])
array([ 0., 1., 0., 0.]) array([ 0., 1., 0., 0.])
array([ 0., 1., 0., 0.]) array([ 0., 0., 0., 1.])
array([ 0. , 0. , 0.5, 0.5]) array([ 0., 0., 1., 0.])
array([ 0.25, 0.25, 0. , 0.5 ]) array([ 0.25, 0.25, 0.25, 0.25])
array([ 0.25, 0.25, 0.5 , 0. ]) array([ 0.5, 0.5, 0. , 0. ])
array([ 0.5, 0.5, 0. , 0. ]) array([ 0.5, 0.5, 0. , 0. ])
array([ 0., 0., 0., 1.]) array([ 0. , 0. , 0.5, 0.5])
array([ 0., 0., 1., 0.]) array([ 0.5, 0. , 0. , 0.5])
array([ 0.5 , 0. , 0.25, 0.25]) array([ 0.5, 0. , 0.5, 0. ])
array([ 1., 0., 0., 0.]) array([ 1., 0., 0., 0.])
array([ 1., 0., 0., 0.])]

Found an answer here for people who are searching :
Using Numpy Vectorize on Functions that Return Vectors
tl;dr:
self.inputSpace = np.array(generateDist(i,j,k).tolist())

Related

How to explain in Numpy indexing an array with a list?

I've been trying to use Python lists as part of indices into Numpy arrays, and I'm seeing behavior that I don't understand.
The first example:
>>> a=np.zeros((5,5))
>>> a[0,[2,4]]=1
>>> a
array([[0., 0., 1., 0., 1.]
[0., 0., 0., 0., 0.]
[0., 0., 0., 0., 0.]
[0., 0., 0., 0., 0.]
[0., 0., 0., 0., 0.]])
The second example:
>>> a=np.zeros((5,5))
>>> a[[1,3],[2,4]]=1
>>> a
array([[0., 0., 0., 0., 0.]
[0., 0., 1., 0., 0.]
[0., 0., 0., 0., 0.]
[0., 0., 0., 0., 1.]
[0., 0., 0., 0., 0.]])
In the first example a[0,[2,4]], the first index is a scalar 0, the second a list.
It appears to me that the first index is treated as a specification of row, the second as column, and the first gets broadcast over the second to yield two row/column addresses [0,2] and [0,4].
In the second example a[[1,3],[2,4]], the first index is a list of rows, the second index is a list of columns, and they appear to be combined (broadcast?) to yield two row/column addresses [1,2] and [3,4].
Can someone help me better understand how Numpy array addressing works? I'm not sure what to Google for.

cv.fillPoly generating zero arrays, not reading inputs

I have
blank = np.zeros(shape = im.shape, dtype = np.float32)
which generates
array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
I have [label2poly[label]] which is dtype('int32')
[array([[ 716, 1],
[ 710, 281],
[ 727, 322],
[ 756, 369],
[ 793, 399],
[ 863, 406],
[ 952, 416],
[ 978, 412],
[ 416, 1]])]
When I try cv2.fillPoly(blank, [label2poly[label]], 255) it outputs
array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]], dtype=float32)`
where it should have been something like
array([[ 0., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 255., ..., 0., 0., 0.],
[ 0., 0., 255., ..., 0., 0., 0.],
...,
[ 0., 255., 255., ..., 255., 255., 255.],
[ 0., 255., 255., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
I am trying to create multiple masks. Would appreciate any help.
Initialization of blank:
blank = np.zeros(shape=[5, 5], dtype=np.float32)
print(blank)
Output:
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
Initialization of label followed by a call to fillPoly() which uses is as a mask to fill blank with 255 at specific positions:
label = np.array([[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]], dtype=np.int32)
cv2.fillPoly(blank, [label], 255)
print(blank)
Output:
[[ 0. 0. 0. 0. 0.]
[ 0. 255. 255. 255. 0.]
[ 0. 255. 255. 255. 0.]
[ 0. 255. 255. 255. 0.]
[ 0. 0. 0. 0. 0.]]

Finding the first and last rows that contain a black pixel, in a numpy array

I have a black and white image of a triangle (it contains only 0 and 255 pixel values).
I've converted it to a numpy array called myArray
Currently, I can find the width of the bottom of the triangle (the number of black pixels) by using this code:
width = (max(numpy.where(myArray == 0)[1])) - (min(numpy.where(myArray == 0)[1]))
If the triangle was flipped upside-down, width would then apply to the top of the upside-down triangle.
What i'm trying to do is determine if the triangle is pointing up or down.
I could do this by finding the first row that contains a black pixel, and counting the number of black pixels in that row, calling this firstRow
and finding the last row that contains a black pixel, and counting the number of black pixels in that row, calling that lastRow
Then, if firstRow < lastRow, the triangle is pointing up.
What is the best way to calculate firstRow and lastRow?
With myArray with 255 for black pixel such as
array([[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 255., 0., 0., 0., 0.],
[ 0., 0., 0., 255., 255., 255., 0., 0., 0.],
[ 0., 0., 255., 255., 255., 255., 255., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
you can get all the rows with at least one black pixel with np.where after using sum on axis=1:
print (np.where(myArray.sum(axis=1)))
(array([3, 4, 5], dtype=int64),)
If you want to get the row with the maximum number of black pixels, you can use np.argmax still after sum on axis=1:
print (np.argmax(myArray.sum(axis=1)))
5
To know if the triangle is up or down, one way is to check if the argmax is the np.max element in the np.where(myArray.sum(axis=1)), then it would be up.
myArray_sum = myArray.sum(axis=1)
if np.max(np.where(myArray_sum)) == np.argmax(myArray_sum):
print ('up')
else:
print ('down')
If you want the first and last row, here is one way but it is related to the value of the black pixel.
myArray_sum = myArray.sum(axis=1)
firstRow = np.argmax(myArray_sum == 255)
lastRow = np.argmax(myArray_sum)

plot selected rows of numpy array

Consider a small numpy array:
array([[ 0., 1., 0., 1., 0., 0., 0., 0., 0., 1.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 18., 15., 25., 0., 0., 0.],
[ 0., 0., 0., 23., 19., 20., 20., 0., 0., 0.],
[ 0., 0., 20., 22., 26., 23., 18., 0., 0., 0.],
[ 0., 0., 0., 23., 16., 20., 13., 0., 0., 0.],
[ 0., 0., 0., 0., 18., 20., 18., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 1., 0., 0., 1., 0., 0., 0., 0., 0.]])
I would like to plot, let say from the row number 3 to the row number 6, i.e. a section of my numpy array(I am coming from matlab backgroud). How could I loop this? or How could I plot multiple rows of my numpy array in the same graph?
So far I have tried; I define an arbitrary x:
x = np.arange(0,10)
then If I use
plt.plot(x,data[3,:])
to plot the third row and It does fine. The problem arises if I try:
plt.plot(x,data[3:4,:])
I get the error "x and y must have same first dimension", which I understand because he stacks row number 3 and row number 4 together, so that x and y do not have the same dimension. How can I overcome that?
Thank you
As the error implies, your data.shape = (1,10) is inconsistent with your input x.shape = (10,). To solve this problem you can just transpose your data using .T, i.e.
plt.plot(x, data[3:4,:].T)
Also, keep in mind that data[3:4,:] is the same as data[3,:], you will need to use data[3:5,:] to get the 3rd and 4th rows, for example.
Just a better application of psuedocubi's answer.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10,10)
y = np.array(YOUR DATA HERE)
plt.plot(x,a[3:4].T,'r--',label="x vs y1") #CONTAINS YOUR 3RD ROW
plt.plot(x,a[4:5].T,'g--',label="x vs y2") #CONTAINS YOUR 4TH ROW
plt.plot(x,a[5:6].T,'b--',label="x vs y3") #CONTAINS YOUR 5TH ROW
plt.legend(loc='best')
plt.xlabel("x")
plt.ylabel("y")
plt.show()
The x here as been plotted with your own data!
You can try:
for i in range(3):
plt.plot( x , data[ i , : ] )
plt.show()
If you want a range of rows ,for example from 3 to 6 , you can use:
range(3,7,1) , where 1 is the step , 3 is the starting row and 7 is the last row we want to plot (6 ) plus one

Pick up elements of a numpy array for defined intervals

I have two 1-D arrays of array objects (DATA and DEGREE) of the same size. Both arrays are collection of 8 other arrays :
DATA = array([array([ 22.]),
array([ 26., 16., 23., 0., 20., 23., 0., 19.]),
array([ 0., 0., 0., 0., 20., 0., 0., 18., 18., 0., 0.,
0., 23., 20., 20., 15.]),
array([ 20., 0., 0., 18., 0., 13., 0., 0., 0., 0., 0.,
0., 25., 18., 0., 0., 0., 0., 0., 0.]),
array([ 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 1., 0.]),
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0.]),
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0.]),
array([ 1., 0.])], dtype=object)
DEGREE = array([array([0]),
array([ 0, 45, 90, 135, 180, -90, -135, -45]),
array([-153, -90, -116, -135, 26, 116, 90, -63, 63, 180, 153,
135, 0, -26, 45, -45]),
array([ -18, 123, 56, 0, 161, 18, 180, 90, -56, -161, 71,
146, -33, 33, -123, -146, 108, -108, -71, -90]),
array([ 14, -104, -116, -90, 75, 135, -75, -63, 45, 63, -14,
26, -135, -45, 0, 90, -26, 116, 104]),
array([ 30, 53, 45, 126, 36, -126, 21, -53, 11, -45, 0,
-36, -11, -30, -21]),
array([-38, -26, 26, -18, -9, 38, 0, 9, 18]),
array([-33, 33])], dtype=object)
I would like to pick up the elements of DATA array corresponding to those of the DEGREE array defining a certain "alpha" angle interval. For example, for -90<=alpha<-70 I should get the Output array reported below. When no angles are found for a certain angle interval the algorithms should return zero, for example in the case of the first array of the Output.
Output = array([array([0]),
array([23]),
array([0]),
array([0]),
array([1,0]),
array([0]),
array([0]),
array([0])], dtype=object)
The idea would be to have alpha varying between -90 and +90 with steps of 20 degrees, i.e. -90<=alpha<-70, -70<=alpha<-50, -50<=alpha<-30 and so on to have finally 9 Output arrays. How could I do that? Thank you in advance
I think your best bet is to use list comprehensions and masks. The following should do the trick:
import numpy as np
def val_check(val_in):
''' Check for non-zero values in numpy array '''
if val_in.any():
return val_in
else:
return np.array([0])
# Set tuples of desired ranges
angles = []
angle = -90
while angle < 90:
angles.append((angle, angle + 20))
angle = angle + 20
out = []
for ang in angles:
# List comprehensions to get masks for elements in desired range per array
mask = [(arr >= ang[0]) * (arr < ang[1]) for arr in DEGREE]
mask_index = [np.where(m) for m in mask]
# Include data corresponding to masks
out_temp = [dat[mi[0]] for (dat, mi) in zip(DATA, mask_index)]
# Replace empty elements with np.array([0])
out_temp = np.array([val_check(ot) for ot in out_temp])
out.append(out_temp)
If you want the output as an array instead of a list, include one final line out = np.array(out)

Resources