Advanced integer indexing with l x m x n broadcast shape - python

Earlier today I asked this about integer array indexing and I am having trouble taking the answer and applying it to the problem that inspired the question.
In a nutshell, p_stack1 and c_stack1 contain arrays that are derived from an image processing algorithm I am working on. p_stack1 contains probability data and c_stack1 contain integer classifications. I need to find the classification that has the highest probability for every pixel in the image with dimensions 768 x 1024. From the docs for integer array indexing, it provides a way to subset data from higher dimensional arrays using their integer indexes.
The solution of my original question works for a simplified example of n x n x n shaped arrays, but does not seem to work on l x m x n shaped arrays.
#dummy data
p_stack1 = np.reshape(np.random.uniform(0,1,2359296),(3,768,1024))
c_stack1 = np.reshape(np.random.randint(0,4,2359296),(3,768,1024))
#find where max value occurs on axis 0
ind_new=p_stack1.argmax(axis=0)
#Create assending indicies
nx, ny = 768,1024
xx = np.arange(ny)
aa= np.tile(xx,(ny,1))
bb = np.column_stack(tuple(aa))[:nx,:]
aa= np.tile(xx,(ny,1))[:nx,:]
#perform the integer array indexing
print(c_stack1[ind_new, aa,bb])
The last print statement returns the error:
IndexError: index 768 is out of bounds for axis 1 with size 768
I checked the shapes of aa and bb and both are (768, 1024)
What I am I missing?

Looks like you got your dimensions mixed up:
c_stack1.shape # (3, 768, 1024)
aa.max() # 1023
bb.max() # 767
So, when you run
c_stack1[ind_new, aa, bb]
you will be trying to index axis=1 with higher values than available, hence the error
Either turn around aa and bb, or else c_stack1[ind_new, bb, aa] will also do the trick

Related

add column Numpy array python

I am very new to python and am very familiar with R, but my question is very simple using Numpy Arrays:
Observe:
I have one array X of dimension (100,2) of floating point type and I want to add a 3rd column, preferably into a new Numpy array of dimension (100,3) such that the 3rd column = col(1)^2 for every row in array of X.
My understanding is Numpy arrays are generally of fixed dimension so I'm OK with creating a new array of dim 100x3, I just don't know how to do so using Numpy arrays.
Thanks!
One way to do this is by creating a new array and then concatenating it. For instance, say that M is currently your array.
You can compute col(1)^2 as C = M[:,0] ** 2 (which I'm interpreting as column 1 squared, not column 1 to the power of the values in column two). C will now be an array with shape (100, ), so we can reshape it using C = np.expand_dims(C, 1) which will create a new axis of length 1, so our new column now has shape (100, 1). This is important because we want all both of our arrays to have the same number of dimensions when concatenating them.
The last step here is to concatenate them using np.concatenate. In total, our result looks like this
C = M[:, 0] ** 2
C = np.expand_dims(C, 1)
M = np.concatenate([M, C], axis=1) #third row will now be col(1) ^ 2
If you're the kind of person who likes to do things in one line, you have:
M = np.concatenate([M, np.expand_dims(M[:, 0] ** 2, 0)], axis=1)
That being said, I would recommend looking at Pandas, it supports these actions more naturally, in my opinion. In Pandas, it would be
M["your_col_3_name"] = M["your_col_1_name"] ** 2
where M is a pandas dataframe.
Append with axis=1 should work.
a = np.zeros((5,2))
b = np.ones((5,1))
print(np.append(a,b,axis=1))
This should return:
[[0,0,1],
[0,0,1],
[0,0,1],
[0,0,1],
[0,0,1]]
# generate an array with shape (100,2), fill with 2.
a = np.full((100,2),2)
# calcuate the square to first column, this will be a 1-d array.
squared=a[:,0]**2
# concatenate the 1-d array to a,
# first need to convert it to 2-d arry with shape (100,1) by reshape(-1,1)
c = np.concatenate((a,squared.reshape(-1,1)),axis=1)

way to create a 3d matrix of 2 vectors and 1 matrix

Hello i have a question regarding a problem I am facing in python. I was studying about tensors and I saw that each row/column of a tensor must have the same size. Is it possible to create a tensor of perhaps a 3d object or matrix where lets say we have 3 axis : x,y,z
In the x axis I want to create a vector to work as an index. So let x be from 0 to N
Then on the y axis I want to have N random integer vectors of size m (where mm
Is it possible?
My first approach was to create a big vector of Nm and a big matrix of (Nm,Nm) dimensions where i would store all my random vectors and matrices and then if I wanted to change for example the my second vector then i would have to play with the indexes. However is there another way to approach this problem with tensors or numpy that I m unaware of?
Thank you in advance for your advices
First vector, N = 3, [1,2, 3]
Second N vectors with length m, m = 2
[[4,5], [6,7], [7,8]]
So, N matrices of size (m,m)
[[[1,1], [2,2]], [[1,1], [2,2]], [[1,1], [2,2]] ]
Lets create numpy arrays from them.
import numpy as np
N = 3
m = 2
a = np.array([1,2,3])
b = np.random.randn(N, m)
c = np.random.randn(N, m, m)
You see the problem here? The last matrix c has already 3 dimensions according to your definitions.
Your argument can be simplified.
Let's say our final matrix is -
a = np.zeros((3,2,2)) # 3 dimensions, x,y,z
1) For first dimension -
a[0,:,:] = 0 # first axis, first index = 0
a[1,:,:] = 1 # first axis, 2nd index = 1
a[2,:,:] = 2 # first axis, 3rd index = 2
2) Now, we need to fill up the rest of the positions, but dimensions don't match up.
So, it's better to create separate tensors for them.

python np.dot vectorization

I'm trying to get rid of some for loops when multiplying matrices. aa represents a 3x3 transformation matrix, bb represents point coords nx3, where n is the number of points.
With:
aa = np.matrix([[1,2,3],[1,2,3],[1,2,3]])
bb = np.matrix([[1,1,1],[2,2,2],[3,3,3]])
np.tile(aa,(3,1))*bb.ravel().T
I get:
ValueError: shapes (9,3) and (9,1) not aligned: 3(dim 1) != 9 (dim 0)
Expected output in this case would be long column matrix [[6],[6],[6],[12],[12],[12],[18],[18],[18]]. Which final shape should be in this case 3x3: [[6,6,6],[12,12,12],[18,18,18]].
Edit: going away from generalized description.
There is n number of points, and only one 3x3 matrix.Its a vectorization problem of something like:
points = bb
T = aa
pointsNewPos = []
for point in points:
pointNewPosition = T*point.T
pointsNewPos.append(pointNewPosition.T)
This at least gives the output that you want in this case. Hard to make sure that it's general without more information.
import numpy as np
aa = np.array([[1,2,3],[1,2,3],[1,2,3]])
bb = np.array([[1,1,1],[2,2,2],[3,3,3],[4,4,4]])
result = b.dot(aa.T)
This sounds like a job for np.einsum which lets you do matrix multiplications using arbitrary dimensions of the input matrices.
Assuming you want to use each row of bb as a column vector and left multiply it (in row major fashion) by aa then give this a whirl:
cc = np.einsum('ij,kj -> ki', bb, aa)

Numpy 2D spatial mask to be filled with specific values from a 2D array to form a 3D structure

I'm quite new to programming in general, but I could not figure this problem out until now.
I've got a two-dimensional numpy array mask, lets say mask.shape is (3800,3500)which is filled with 0s and 1s representing a spatial resolution of a 2D image, where a 1 represents a visible pixel and 0 represents background.
I've got a second two-dimensional array data of data.shape is (909,x) where x is exactly the amount of 1s in the first array. I now want to replace each 1 in the first array with a vector of length 909 from the second array. Resulting in a final 3D array of shape(3800,3500,909) which is basically a 2D x by y image where select pixels have a spectrum of 909 values in z direction.
I tried
mask_vector = mask.flatten
ones = np.ones((909,1))
mask_909 = mask_vector.dot(ones) #results in a 13300000 by 909 2d array
count = 0
for i in mask_vector:
if i == 1:
mask_909[i,:] = data[:,count]
count += 1
result = mask_909.reshape((3800,3500,909))
This results in a viable 3D array giving a 2D picture when doing plt.imshow(result.mean(axis=2))
But the values are still only 1s and 0s not the wanted spectral data in z direction.
I also tried using np.where but broadcasting fails as the two 2D arrays have clearly different shapes.
Has anybody got a solution? I am sure that there must be an easy way...
Basically, you simply need to use np.where to locate the 1s in your mask array. Then initialize your result array to zero and replace the third dimension with your data using the outputs of np.where:
import numpy as np
m, n, k = 380, 350, 91
mask = np.round(np.random.rand(m, n))
x = np.sum(mask == 1)
data = np.random.rand(k, x)
result = np.zeros((m, n, k))
row, col = np.where(mask == 1)
result[row,col] = data.transpose()

Python- list with arrays shape issues

I'm creating a code to run a perceptron algorithm and I can't create a random matrix the way I need it:
from random import choice
from numpy import array, dot, random
unit_step = lambda x: -1 if x < 0 else 1
import numpy as np
m=3 #this will be the number of rows
allys=[]
for j in range(m):
aa=np.random.rand(1,3)
tt=np.random.rand(3)
yy=dot(aa,tt)
ally = [aa, yy]
allys.append(ally)
print "allys", allys
w = random.rand(3)
errors = []
eta = 0.2
n = 10
x=[1,3]
for i in xrange(n):
print i
x, expected = choice(allys)
print "x", x
And I get the problem here:
result = dot(x,w)
error = expected - unit_step(result)
errors.append(error)
w += eta * error * x
print x, expected, w, error, result, errors
The log says
w += eta * error * x
ValueError: non-broadcastable output operand with shape (3,) doesn't
match the broadcast shape (1,3)
The idea is to get result looping randomly over the "table" allys.
How can I solve this? What is shape(3,)?
Thanks!
The error message actually tells you what is wrong. The result of your multiplication is a (1,3) array (2D array, one row, three columns), whereas you try to add it into a 3-element vector.
Both arrays have three elements in a row, so if you do this:
w = w + eta * error * x
there will be no error on that line, but the resulting vector will actually be a (1,3) array. That is unwanted, because then your dot does not work.
There are several ways to fix the problem, but possibly the easiest to read is to reshape x for the calculation to be a 3-element vector (1D array):
w += eta * error * x.reshape(3,)
Possibly a cleaner solution would be to define w as a (1,3) 2D array, as well, and then transpose w for the dot. This is really a matter of taste.
For numpy arrays, shape attribute returns array's dimensionality. In your case, w.shape is (3,). This means that w is a one-dimensional array with 3 elements. In turn, x.shape is (1,3), which means that x is a two-dimensional array with one row and 3 columns. You are getting an error, because the interpreter is confused on how to match the shapes. I am not sure what you are trying to do, so it's hard to suggest the solution. But you might want to try reshaping one of the arrays. For example, x = x.reshape((3,)) for adapting the shape of x to w.

Categories

Resources