How do numpy block matrices work? - python

The outcome of this code doesn't make any sense to me:
a = np.zeros((2, 2))
b = np.bmat([[a, a], [a, a]])
print(b.shape, b.dot(np.zeros(4)).shape)
How can a matrix with shape (4, 4) when doing a sum-product over its final axis return a matrix of shape (1, 4)?

bmat returns a numpy.matrix instance, as in those things you should never use because they cause all kinds of weird incompatibilities. numpy.matrix always tries to preserve at least two dimensions, so b.dot(np.zeros(4)) is 2D instead of 1D.
Make a numpy.array:
b = np.bmat([[a, a], [a, a]]).A
# ^
Or as of NumPy 1.13,
b = np.block([[a, a], [a, a]])

bmat doesn't do anything exotic or fancy; basically it's just a couple of levels on concatenation:
In [308]: np.bmat([[a,a],[a,a]]).A
Out[308]:
array([[0, 1, 0, 1],
[2, 3, 2, 3],
[0, 1, 0, 1],
[2, 3, 2, 3]])
In [309]: alist = [[a,a],[a,a]]
In [310]: np.concatenate([np.concatenate(sublist, axis=1) for sublist in alist], axis=0)
Out[310]:
array([[0, 1, 0, 1],
[2, 3, 2, 3],
[0, 1, 0, 1],
[2, 3, 2, 3]])

Related

How would I achieve this "row in A * all rows in B by col in A" multiplication in NumPy without a loop?

Say I have two matrices, A and B:
A = np.array([[1, 3, 2],
[2, 2, 3],
[3, 1, 1]])
B = np.array([[0, 1, 0],
[1, 1, 0],
[1, 1, 1]])
I want to take one column in A and multiply it by each column in B element-wise, then proceed to the next column in A. So, using just one column as an example, I will use A[:,0] (values 1,2,3), and multiply it by each column in B to get this:
array([[0, 1, 0],
[2, 2, 0],
[3, 3, 3]])
I've implemented this using np.einsum like so:
np.einsum('i,ij->ij',A[:,0],B)
I then want to generate a 3D matrix with the depth dimension corresponding to the multiplication by each column in A, which I implemented using a for loop:
np.stack([np.einsum('i,ij->ij',A[:,i],B) for i in range(0,A.shape[1])])
This returns my desired array:
array([[[0, 1, 0],
[2, 2, 0],
[3, 3, 3]],
[[0, 3, 0],
[2, 2, 0],
[1, 1, 1]],
[[0, 2, 0],
[3, 3, 0],
[1, 1, 1]]])
How would I go about doing this without the loop? Can this be done purely with np.einsum? Is there another function in NumPy that will do this more simply?
Here's a simple way:
A.T[:,:,None]*B
adding the last None in indexing creates a new axis which is then used for broadcasting the elementwise multiplication.
How about this code?
A.T.reshape(3, 3, 1) * B
Reshaping ndarray can make doing many things...
Keeping with your usage of einsum:
np.einsum('ij,ik->jik', A, B)

Converting a list of numpy array to a single int numpy array

I have a list of numpy arrays, that I want to convert into a single int numpy array.
For example if I have 46 4 x 4 numpy arrays in a list of dimension 2 x 23, I want to convert it into a single integer numpy array of 2 x 23 x 4 x 4 dimension. I have found a way to do this by going through every single element and using numpy.stack(). Is there any better way?
You can simply use np.asarray like so
import numpy as np
list_of_lists = [[np.random.normal(0, 1, (4, 4)) for _ in range(23)]
for _ in range(2)]
a = np.asarray(list_of_lists)
a.shape
The function will infer the shape of the list of lists for you and create an appropriate array.
Stack works for me:
In [191]: A,B,C = np.zeros((2,2),int),np.ones((2,2),int),np.arange(4).reshape(2,
...: 2)
In [192]: x = [[A,B,C],[C,B,A]]
In [193]:
In [193]: x
Out[193]:
[[array([[0, 0],
[0, 0]]), array([[1, 1],
[1, 1]]), array([[0, 1],
[2, 3]])], [array([[0, 1],
[2, 3]]), array([[1, 1],
[1, 1]]), array([[0, 0],
[0, 0]])]]
In [194]: np.stack(x)
Out[194]:
array([[[[0, 0],
[0, 0]],
[[1, 1],
[1, 1]],
[[0, 1],
[2, 3]]],
[[[0, 1],
[2, 3]],
[[1, 1],
[1, 1]],
[[0, 0],
[0, 0]]]])
In [195]: _.shape
Out[195]: (2, 3, 2, 2)
stack views x as a list of 2 items, and applies np.asarray to each.
In [198]: np.array(x[0]).shape
Out[198]: (3, 2, 2)
Then adds a dimension, (1,3,2,2), and concatenates on the first axis.
In this case np.array(x) works just as well
In [201]: np.array(x).shape
Out[201]: (2, 3, 2, 2)

How to get a value from every column in a Numpy matrix

I'd like to get the index of a value for every column in a matrix M. For example:
M = matrix([[0, 1, 0],
[4, 2, 4],
[3, 4, 1],
[1, 3, 2],
[2, 0, 3]])
In pseudocode, I'd like to do something like this:
for col in M:
idx = numpy.where(M[col]==0) # Only for columns!
and have idx be 0, 4, 0 for each column.
I have tried to use where, but I don't understand the return value, which is a tuple of matrices.
The tuple of matrices is a collection of items suited for indexing. The output will have the shape of the indexing matrices (or arrays), and each item in the output will be selected from the original array using the first array as the index of the first dimension, the second as the index of the second dimension, and so on. In other words, this:
>>> numpy.where(M == 0)
(matrix([[0, 0, 4]]), matrix([[0, 2, 1]]))
>>> row, col = numpy.where(M == 0)
>>> M[row, col]
matrix([[0, 0, 0]])
>>> M[numpy.where(M == 0)] = 1000
>>> M
matrix([[1000, 1, 1000],
[ 4, 2, 4],
[ 3, 4, 1],
[ 1, 3, 2],
[ 2, 1000, 3]])
The sequence may be what's confusing you. It proceeds in flattened order -- so M[0,2] appears second, not third. If you need to reorder them, you could do this:
>>> row[0,col.argsort()]
matrix([[0, 4, 0]])
You also might be better off using arrays instead of matrices. That way you can manipulate the shape of the arrays, which is often useful! Also note ajcr's transpose-based trick, which is probably preferable to using argsort.
Finally, there is also a nonzero method that does the same thing as where in this case. Using the transpose trick now:
>>> (M == 0).T.nonzero()
(matrix([[0, 1, 2]]), matrix([[0, 4, 0]]))
As an alternative to np.where, you could perhaps use np.argwhere to return an array of indexes where the array meets the condition:
>>> np.argwhere(M == 0)
array([[[0, 0]],
[[0, 2]],
[[4, 1]]])
This tells you each the indexes in the format [row, column] where the condition was met.
If you'd prefer the format of this output array to be grouped by column rather than row, (that is, [column, row]), just use the method on the transpose of the array:
>>> np.argwhere(M.T == 0).squeeze()
array([[0, 0],
[1, 4],
[2, 0]])
I also used np.squeeze here to get rid of axis 1, so that we are left with a 2D array. The sequence you want is the second column, i.e. np.argwhere(M.T == 0).squeeze()[:, 1].
The result of where(M == 0) would look something like this
(matrix([[0, 0, 4]]), matrix([[0, 2, 1]])) First matrix tells you the rows where 0s are and second matrix tells you the columns where 0s are.
Out[4]:
matrix([[0, 1, 0],
[4, 2, 4],
[3, 4, 1],
[1, 3, 2],
[2, 0, 3]])
In [5]: np.where(M == 0)
Out[5]: (matrix([[0, 0, 4]]), matrix([[0, 2, 1]]))
In [6]: M[0,0]
Out[6]: 0
In [7]: M[0,2] #0th row 2nd column
Out[7]: 0
In [8]: M[4,1] #4th row 1st column
Out[8]: 0
This isn't anything new on what's been already suggested, but a one-line solution is:
>>> np.where(np.array(M.T)==0)[-1]
array([0, 4, 0])
(I agree that NumPy matrix objects are more trouble than they're worth).
>>> M = np.array([[0, 1, 0],
... [4, 2, 4],
... [3, 4, 1],
... [1, 3, 2],
... [2, 0, 3]])
>>> [np.where(M[:,i]==0)[0][0] for i in range(M.shape[1])]
[0, 4, 0]

Re-Meshing ("use output of meshgrid in order to create new meshgrid")

say I have three grids,
a = arange(0,5)
b = arange(0,3)
c = arange(10,12)
And for some reason, in my code, I first need to mesh
A, B = meshgrid(a,b,indexing='ij')
Is there a short way in which I could do
A, B, C = remeshgrid(A, B, c, indexing='ij)
such that A, B, C all correspond to meshgrid(a,b,c, indexing='ij')?
The scenario is the following.
- I first have a, b and mesh A, B
- Later on, I generate c
- At this point, I need to remesh everything containing c. But the code does not have a,b at disposal anymore.
So now it's a tradeoff of adjusting code in order to pass over a, b - if remeshing A,B is not possible or too inefficient.
Do you guys have any thoughts on this?
Building on Davidmh's idea, you could use A[:,0] and B[0,:]. This will work even if A or B contains duplicate values; and taking a slice is faster than calling np.unique.
In [71]: A[:,0]
Out[71]: array([0, 1, 2, 3, 4])
In [72]: B[0,:]
Out[72]: array([0, 1, 2])
In [73]: A, B, C = np.meshgrid(A[:,0], B[0,:], c, indexing='ij')
You can reconstruct a and b taking the unique elements:
print A
array([[0, 0, 0],
[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 4, 4]])
print B
array([[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2]])
np.unique(A)
array([0, 1, 2, 3, 4])
np.unique(B)
array([0, 1, 2])

Increment given indices in a matrix

Briefly: there is a similar question and the best answer suggests using numpy.bincount. I need the same thing, but for a matrix.
I've got two arrays:
array([1, 2, 1, 1, 2])
array([2, 1, 1, 1, 1])
together they make indices that should be incremented:
>>> np.array([a, b]).T
array([[1, 2],
[2, 1],
[1, 1],
[1, 1],
[2, 1]])
I want to get this matrix:
array([[0, 0, 0],
[0, 2, 1], # (1,1) twice, (1,2) once
[0, 2, 0]]) # (2,1) twice
The matrix will be small (like, 5×5), and the number of indices will be large (somewhere near 10^3 or 10^5).
So, is there anything better (faster) than a for-loop?
You can still use bincount(). The trick is to convert a and b into a single 1D array of flat indices.
If the matrix is nxm, you could apply bincount() to a * m + b, and construct the matrix from the result.
To take the example in your question:
In [15]: a = np.array([1, 2, 1, 1, 2])
In [16]: b = np.array([2, 1, 1, 1, 1])
In [17]: cnt = np.bincount(a * 3 + b)
In [18]: cnt.resize((3, 3))
In [19]: cnt
Out[19]:
array([[0, 0, 0],
[0, 2, 1],
[0, 2, 0]])
If the shape of the array is more complicated, it might be easier to use np.ravel_multi_index() instead of computing flat indices by hand:
In [20]: cnt = np.bincount(np.ravel_multi_index(np.vstack((a, b)), (3, 3)))
In [21]: np.resize(cnt, (3, 3))
Out[21]:
array([[0, 0, 0],
[0, 2, 1],
[0, 2, 0]])
(Hat tip #Jaime for pointing out ravel_multi_index.)
m1 = m.view(numpy.ndarray) # Create view
m1.shape = -1 # Make one-dimensional array
m1 += np.bincount(a+m.shape[1]*b, minlength=m1.size)

Categories