gather(params, indices) does the following
output[i, ..., j, :, ... :] = params[indices[i, ..., j], :, ..., :]
so if you have 4-dimensional params and 2-dimensional indices, you end up having 5-dimensional array as a result
the question is how to do
output[i, ..., j, :, ... :] = params[indices[i, :], ..., indices[j, :], :, ..., :]
so that it acts as numpy's
output = params[indices[0], indices[1], .. , :]
(the #206 ticket on github is regarding different issue: it is about numpy-like api, not gathering in general)
one possible way is to use gather_nd, but (as far as I understand) if we want to gather_nd over not all dimensions, we still have to create indices for them, e.g. if we have 10-dimensional array A and we want to index first two dimensions with 2-dimensional array B, like A[B[0], B[1], :] our indices matrix would have to have 11 columns (with 8 redundant).
--- old indices ---- new index
0 0 <all rows of length 8> 0
1 1 <all rows of length 8> 1
...
There's an update on #206 that #ebrevdo is working on generalizing slicing.
Meanwhile, you could flatten your array, construct linear indices for the elements you want, use gather, then reshape back, like was done in another answer by mrry. That's probably not much worse in efficiency than a native implementation
Related
Consider the following code:
X = rand.rand(10, 2)
differences = X[:, np.newaxis, :] - X[np.newaxis, :, :]
differences = X[:, np.newaxis, :] - X[np.newaxis, :, :]
sq_differences = differences ** 2
dist_sq = sq_differences.sum(-1)
In this code, we're calculating the squared distance between the points in the cartesian plane (points are stored in the array X). Please explain the last step in this code, especially that -1 parameter in the sum method.
When Numpy.sum() is used to sum a multi dimenstional array it allows you to specify a dimension. For example dimension = 0 works along the column while dimemen =1 works along the row.
This is explained better here Numpy.sum
Now why -1 is used took a little more digging but is a very simple and sensible answer when you find it.
When you pass dimensions as -1 it means to pick the last dimension in the array. Such that in a 2D array this would be column
So I have two ndarrays:
A with shape (N,a,a), a stack of N arrays of shape (a,a) basically
B with shape (8,M,a,a), a matrix of 8 x M arrays of shape (a,a)
I need to subtract B from A (A-B) such that the resulting array is of shape (8,M*N,a,a).
More verbosely each (M total) of the 8 arrays of B needs to be subtracted from each array in A, resulting in 8*M*N subtractions between (a,a) shape arrays.
How can I do this in a vectorized manner without loops?
This thread does something similar but in lower dimensions and I can't figure out how to extend it.
A = np.arange(8).reshape(2,2,2)
B = np.ones(shape=(8,4,2,2))
General broadcasting works if dimensions are the same or if one dimension is 1, so we do this;
a = A[np.newaxis, :, np.newaxis, :, :]
b = B[:, np.newaxis, :, :, :]
a.shape # <- (1,2,1,2,2)
b.shape # <- (8,1,4,2,2)
Now when you can do broadcasting
c = a - b
c.shape # <- (8,2,4,2,2)
And when you reshape the (2x4=8) components get aligned.
c.reshape(8,-1,2,2)
The ordering of the new axes dictates the reshaping, so be careful with that.
Trying to understand how numpy selects elements when indexing in more than 2 dimensions.
import numpy as np
x = np.arange(24).reshape(2,3,4)
x[:,:,0].shape #(2, 3)
In writing x[:,:,0] I am selecting all the elements along the "depth", all the "rows" and the first column. When thinking about this visually I would have thought numpy would return something with a shape of (2,3,1) but instead the last dimension is dropped. This is reasonable but how does numpy populate the result? Ie in this example, why does x[:,:,0] result in the elements [0,12] forming the first column. Just trying to figure out the general logic which for some reason I am not comprehending at the moment.
General NumPy indexing is complicated, but this is still the easy case. I've always felt that it helps to think in terms of how indexing the result corresponds to indexing the original array.
The result of x[:, :, 0] is an array such that for any indices i and j,
result[i, j] == x[i, j, 0]
Similarly, if you index a 5D array a as a[:, 1, :, 2, :], the result is such that
result[i, j, k] == a[i, 1, j, 2, k]
I have some 3D numpy arrays that need to be transformed in various ways. E.g.:
x.shape = (4, 17, 17)
This array is 1 sample of 4 planes, each of size 17x17. What is the most efficient way to transform each plane: flipud, fliplr, and rot90? Is there a better way than using a for loop? Thanks!
for p in range(4):
x[p, :, :] = np.fliplr(x[p, :, :])
Look at the code of these functions:
def fliplr(...):
....
return m[:, ::-1]
In other words it returns a view with reverse slicing on the 2nd dimension
Your x[p, :, :] = np.fliplr(x[p, :, :] applies that reverse slicing to the last dimension, so the equivalent for the whole array should be
x[:, :, ::-1]
flipping the 2nd axis would be
x[:, ::-1, :]
etc.
np.rot90 has 4 case (k); for k=1 it is
return fliplr(m).swapaxes(0, 1)
in other words m[:, ::-1].swapaxes(0,1)
To work on your planes you would do something like
m[:, :,::-1].swapaxes(1,2)
or you could do the swapaxes/transpose first
m.transpose(0,2,1)[:, :, ::-1]
Does that give you enough tools to transform the plane's in what ever way you want?
As I discussed in another recent question, https://stackoverflow.com/a/41291462/901925, the flip... returns a view, but the rot90, with both flip and swap, will, most likely return a copy. Either way, numpy will be giving you the most efficient version.
I encountered a quite weird problem when indexing a numpy ndarray. You can produce the result with following code. I don't understand why the result of indexing a is somehow transposed while the result of 2d array b is normal. Thanks.
In [1]: a = np.array(range(6)).reshape((1,2,3))
In [2]: mask = np.array([True, True, True])
In [3]: a
Out[3]:
array([[[0, 1, 2],
[3, 4, 5]]])
In [4]: a[0, :, mask]
Out[4]:
array([[0, 3],
[1, 4],
[2, 5]])
In [5]: a[0, :, mask].shape
Out[5]: (3, 2)
In [6]: b = np.array(range(6)).reshape((2,3))
In [7]: b[:, mask].shape
Out[7]: (2, 3)
a[0, :, mask] mixes advanced indexing with slicing. The : is a "slice index", while the 0 (for this purpose) and mask are consider "advanced indexes".
The rules governing the behavior of indexing when both advanced indexing and slicing are combined state:
There are two parts to the indexing operation, the subspace defined by the basic indexing (excluding integers) and the subspace from the advanced indexing part. Two cases of index combination need to be distinguished:
The advanced indexes are separated by a slice, ellipsis or newaxis. For example x[arr1, :, arr2].
The advanced indexes are all next to each other. For example x[..., arr1, arr2, :] but not x[arr1, :, 1] since 1 is an advanced index in this regard.
In the first case, the dimensions resulting from the advanced indexing operation come first in the result array, and the subspace dimensions after that. In the second case, the dimensions from the advanced indexing operations are inserted into the result array at the same spot as they were in the initial array (the latter logic is what makes simple advanced indexing behave just like slicing).
So since a[0, :, mask] has advanced indexes separated by a slice (the first case), the shape of the resulting array has the axes associated to the advanced indexes pushed to the front and the axes associated with the slice pushed tho the end. Thus the shape is (3, 2) since the mask is associated with the axis of length 3, and the slice, :, associated with the axis of length 2. (The 0 index in effect removes the axis of length 1 from the resultant array so it plays no role in the resultant shape.)
In contrast, b[:, mask] has all the advanced indexes together (the second case). So the shape of the resulting array keeps the axes in place. b[:, mask].shape is thus (2, 3).