Numpy: select along axis of 3d array using 2d array - python

I've been struggling with this for a few hours and can't quite get my head around it. The setup is something like this:
A.shape # (T,N,K)
B.shape # (L,K) L < N
Each of the K columns of the 2D B array index one of the N columns along that same K row. I can grab along any specific k slice easily via
A[:,B[:,k],k].shape # (T,L)
However, looping over K isn't ideal because A is a very large matrix
I'm sure someone has a really simple answer, but I am stumped.
Edit: I should also add that I need to preserve the 3D structure of the A matrix. I figured out how to grab the individual values, but only in a (TxLxK,) array.

You can use np.take_along_axis
np.take_along_axis(A,B[None,...],axis=1)
For example,
A = np.linspace(1,24,24).reshape(3,4,2)
B = np.repeat([[0,1]],3,axis=0)
np.take_along_axis(A,B[None,...],axis=1)
the result is
array([[[ 1., 4.],
[ 1., 4.],
[ 1., 4.]],
[[ 9., 12.],
[ 9., 12.],
[ 9., 12.]],
[[17., 20.],
[17., 20.],
[17., 20.]]])

Related

Change elements of boolean matrix to True based on value from another array

I'm trying to update the values of False elements in my boolean matrix to True based on the index value of that row which is contained in another numpy array.
Here is my array, change, that identifies the element that needs to be changed in the matrix, mask_matrix:
import numpy as np
mask_matrix = np.zeros((20, 25), dtype=bool)
change = np.array([ 6., 22., 22., 22., 22., 21., 22., 21., 17., 21., 22., 21., 22.,
21., 22., 12., 7., 7., 12., 17.])
So every item in change tells which element to change in mask_matrix. E.g. change[0] = 6. should change the first row and 6th column to a 6 in the mask_matrix
I know I can change items like this,
mask[0,:][6] = True
But I need to find a more efficient way of doing this.
Does anybody have any advice as to how to do this? Preferably vectorised.
This should help:
mask_matrix[np.arange(change.size),change]=True
Which is basically using advanced indexing in numpy to call row-column elements of an array.

Operation between ndarray and heterogeneous ndarray

I've been trying to come uo with a way to add these two ndarrays, one of them with a different amount of elements in each row:
a = np.array([np.array([0, 1]), np.array([4, 5, 6])])
z = np.zeros((3,3))
Expected output:
array([[0., 1., 0.],
[4., 5., 6.]])
Can anyone think of a way to do this using numpy?
I don't think there is a 'numpy-fast' solution for this. I think you will need to loop over a with a for loop and add every line individually.
for i in range(len(a)):
z[i,:len(a[i])] = z[i,:len(a[i])] + a[i]

python how to get proper distance value out of scipy condensed distance matrix

I am using python 2.7 with scipy to calculate a distance matrix for an array.
I don't get how to find the wanted distance values in the returned condensed matrix.
See example
from scipy.spatial.distance import pdist
import numpy as np
a = np.array([[1],[4],[0],[5]])
print a
print pdist(a)
will print
[ 3. 1. 4. 4. 1. 5.]
I found here that the ij entry in the condensed matrix should store the distance between the i and j entries where ithread wondering if they mean ij as i*j or str.join(i,j) e.g 1,2 -> 2 or 12.
I can't find a consistent way to know the wanted index.
see my example, you should expect that all of the distances from entry 0 to anywhere else will be stored in entry 0 if the first option is valid.
can anyone shed some light on how can i extract my wanted distance from entry x to entry y? which index am i looking for?
Thanks!
This vector is in condensed form. It enumerates all pairs of indices in a natural order (in your example 0,1 0,2 0,3 0,4 1,2 1,3 1,4 2,3 2,4 ) and yields the distance between the elements at these array entries.
There is also the squareform function, which transforms the condensed form into a square matrix form (and vice versa). The square matrix form is exactly what you expect, i.e. at entry ij (row i, column j), it stores the distance between the i-th and j-th entry. For example, if you add print squareform(d) at the end of you code, the output will be:
array([[ 0., 3., 1., 4.],
[ 3., 0., 4., 1.],
[ 1., 4., 0., 5.],
[ 4., 1., 5., 0.]])

Create a numpy array according to another array along with indices array

I have a numpy array(eg., a = np.array([ 8., 2.])), and another array which stores the indices I would like to get from the former array. (eg., b = np.array([ 0., 1., 1., 0., 0.]).
What I would like to do is to create another array from these 2 arrays, in this case, it should be: array([ 8., 2., 2., 8., 8.])
of course, I can always use a for loop to achieve this goal:
for i in range(5):
c[i] = a[b[i]]
I wonder if there is a more elegant method to create this array. Something like c = a[b[0:5]] (well, this apparently doesn't work)
Only integer arrays can be used for indexing, and you've created b as a float64 array. You can get what you're looking for if you explicitly convert to integer:
bi = np.array(b, dtype=int)
c = a[bi[0:5]]

Does filter2D in opencv really do its job?

I am doing something about convolving images in Python and for sake of speed I chose opencv 2.4.9.
Opencv offers a way called filter2D to do this and here's its docs: http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=filter2d#filter2d
In docs, it says:
Convolves an image with the kernel.
But I have doubts(caused by something else) so I make some experiments on it:
First, I make a normal 3x3 matrix a using numpy as:
[[ 1., 5., 0.],
[ 7., 2., 9.],
[ 2., 3., 4.]]
Then, I make a 2x2 matrix b as the kernel as:
>>> b
[[ 1., 2.],
[ 3., 4.]]
Finally, in order to make it clear to see difference between convolve and correlate, rotate b by 180 degree and b will look like:
[[ 4., 3.],
[ 2., 1.]]
Now, All pre-work is done. We could begin the experiment.
Step 1. Use scipy.ndimage.convolve: ndconv = ndimage.convolve(a, b, mode = 'constant') and ndconv is:
[[ 35., 33., 18.],
[ 41., 45., 44.],
[ 17., 24., 16.]]
Convolution op will rotate b by 180 degree and do correlation using b on a. So ndconv[0][0] = 4*1+3*5+2*7+1*2 = 35, and ndconv[2][2] = 4*4+3*0+2*0+1*0 = 16
This result is correct.
Step 2. Use scipy.ndimage.correlate: ndcorr = ndimage.correlate(a, b, mode = 'constant') and ndcorr is:
[[ 4., 23., 15.],
[ 30., 40., 47.],
[ 22., 29., 45.]]
According to correlation's definition, ndcorr[0][0] = 1*0+2*0+3*0+4*1 = 4 because the border will expand by 0.
(Someone may be confused by the expandation's difference between conv and corr.
It seems convolve expand image in directions right and down while correlate in directions left and up.)
But this is not the point.
Step 3. Use cv2.filter2D: cvfilter = cv2.filter2D(a, -1, b) and cvfilter is:
[[ 35., 34., 35.],
[ 41., 40., 47.],
[ 33., 29., 45.]]
If we ignore the border cases, we will find that what cv2.filter2D did is actually a correlation other than a convolution! How could I say that?
because cvfilter[1..2][1..2] == ndcorr[1..2][1..2].
WEIRD, isn't it?
Could anyone be able to tell the real thing that cv2.filter2D do? Thanks a lot.
If you read a bit further down in the description in the OpenCV documentation:
The function does actually compute correlation, not the convolution:
That is, the kernel is not mirrored around the anchor point. If you need a real convolution, flip the kernel using flip() and set the new anchor to (kernel.cols - anchor.x - 1, kernel.rows - anchor.y - 1).
Well I think that's true for OpenCV. If you want real convolution according to Digital Image Processing theory, you should manually reverse the kernel prior to applying cv2.filter2D.

Categories

Resources