Advanced indexing in Numpy - python

I have two arrays: A such that A.shape = (N, M, K) and index such that index.shape = (N, M). As a result I want to get such array B that B[i, j] = A[i, j, index[i, j]]. How to achieve that in the simplest way?
One solution that comes to my mind is that we can do it like this:
B = A.reshape(-1, K)[np.arange(N * M), index.reshape(-1)].reshape(N, M). I wonder if there are any other solutions?

You could use 2D extended range array for the first axis that aligns with the shape of the indexing array index and hence use advanced-indexing, like so -
B = A[np.arange(N)[:,None], np.arange(M), index]

Related

Numpy broadcast 3-d matrix and 1d vector

I have a matrix A of the shape (N, N, T). Then I have a vector of V shape (N,). I want to perform the following operation A[i, j, ...] = A[i, j, ...]*V[i]/V[j]. I'm doing this with the following loop, but sure there is a way to do it with broadcast.
A = np.random.randint(0, 5, (2, 2, 3))
V = np.array([2, 3])
for i in range(2):
for j in range(2):
A[i, j, ...] *= V[i]
A[i, j, ...] /= V[j]
I've thought about doing it with element-wise multiplication and broadcast of numpy, and I try approaches like A * V[:, None, None] but always got an error.
Is there a more efficient way to do it?
Here's one way to do it -
(A*V[:,None,None])/V[:,None]
Alternatively, in two steps -
A *= V[:,None,None]
A /= V[:,None]
Leverage multi-cores with numexpr -
import numexpr as ne
ne.evaluate('A*V3D/V2D',{'V3D':V[:,None,None],'V2D':V[:,None]})
Note that you might be getting error because you might be doing edits into an int array with float results. So, either convert to float array at the start or write to a new array with the one-step approaches.

Numpy - Multiple Outer Products

I was wondering if there's a way to compute multiple outer products and stack the results in a single operation.
Say I have an Nx1 vector and take the outer product with a 1xM vector, the result will be an NxM matrix.
What if I had an NxR matrix A, and an RxM matrix B. Is it possible to construct an NxMxR matrix where each layer of the output matrix is the outer product of the corresponding column of A and row of B?
I know it's really easy to do this in a single for loop over R, but I wanted to know if there's a faster way using numpy builtins (as there usually is when numpy is concerned).
I haven't been able to figure out a set of indices that work with einsum (and I'm not even sure if einsum is the right approach, since there is no summation involved here)
Yes, of course, using broadcasting or Einsum (the fact that there is no summation does not matter)
N, M, R = 8, 9, 16
A = numpy.random.rand(N)
B = numpy.random.rand(M)
C = A[:, None] * B[None, :]
D = numpy.einsum('a,b->ab', A, B)
numpy.allclose(C, D)
# True
C.shape
# (8, 9)
A = numpy.random.rand(N, R)
B = numpy.random.rand(M, R)
C = A[:, None, :] * B[None, :, :]
D = numpy.einsum('ar,br->abr', A, B)
numpy.allclose(C, D)
# True
C.shape
# (8, 9, 16)

pairwise subtraction of arrays in python

I have two matrices, A of shape 512*3 and B of shape 1024*3
I want to calculate pairwise subtraction between their rows, so the result would be of shape 512*1024*3
(they are actually arrays of 3D point coordinates : x , y , z and I eventually want to find k nearest points from B to every point in A)
and I can't use for loops. is there any pythonic way to do this?
thank u.
From the reference I linked in my previous comment:
http://scipy.github.io/old-wiki/pages/EricsBroadcastingDoc
You are trying to do this.
Just follow the example, as in:
import numpy as np
np.random.seed(123)
a = np.random.uniform(size=(8,3)) # or (512,3)
b = np.random.uniform(size=(16,3)) # or (1024,3)
diff = a[np.newaxis,:,:]-b[:,np.newaxis,:]
dist = np.sqrt(np.sum(diff**2,axis=-1))
The difference:
diff = A[:, np.newaxis] - B[np.newaxis, :]
The closest k points in B for each point in A:
k = 5
dists = np.sum(np.square(A[:, np.newaxis] - B[np.newaxis, :]), axis=-1)
top_k = np.argpartition(dists, k, axis=1)[:, :k]
That top_k is not sorted by distance, though. You can sort it later or do instead:
top_k = np.argsort(dists, axis=1)[:, :k]
Which is less efficient but simpler.

Index numpy nd array along last dimension

Is there an easy way to index a numpy multidimensional array along the last dimension, using an array of indices? For example, take an array a of shape (10, 10, 20). Let's assume I have an array of indices b, of shape (10, 10) so that the result would be c[i, j] = a[i, j, b[i, j]].
I've tried the following example:
a = np.ones((10, 10, 20))
b = np.tile(np.arange(10) + 10, (10, 1))
c = a[b]
However, this doesn't work because it then tries to index like a[b[i, j], b[i, j]], which is not the same as a[i, j, b[i, j]]. And so on. Is there an easy way to do this without resorting to a loop?
There are several ways to do this. Let's first generate some test data:
In [1]: a = np.random.rand(10, 10, 20)
In [2]: b = np.random.randint(20, size=(10,10)) # random integers in range 0..19
One way to solve the question would be to create two index vectors, where one is a row vector and the other a column vector of 0..9 using meshgrid:
In [3]: i1, i0 = np.meshgrid(range(10), range(10), sparse=True)
In [4]: c = a[i0, i1, b]
This works because i0, i1 and b will all be broadcasted to 10x10 matrices. Quick test for correctness:
In [5]: all(c[i, j] == a[i, j, b[i, j]] for i in range(10) for j in range(10))
Out[5]: True
Another way would be to use choose and rollaxis:
# choose needs a sequence of length 20, so move last axis to front
In [22]: aa = np.rollaxis(a, -1)
In [23]: c = np.choose(b, aa)
In [24]: all(c[i, j] == a[i, j, b[i, j]] for i in range(10) for j in range(10))
Out[24]: True

Numpy array and column extracted from a matrix, different shape

I'm trying to do an integration with numpy:
A = n.trapz(B,C)
but I have some issues with B and C shapes
B is a filled array inizialized with numpy zeros function
B=np.zeros((N,1))
C is a column extracted from a matrix, always inizialized with numpy:
C = D[:,0]
D = np.zeros((N,2))
the problem is that:
n.shape(B) # (N,1)
n.shape(C) # (N,)
how can I manage this?
Try
B = np.zeros(N)
np.trapz(B, C)
Also, you np.trapz accepts multi-dimensional arrays, so arrays of shape (N, 1) are ok; you just need to specify an axis to handle it properly.
B = np.zeros((N, 1))
C = D[:, 0]
np.trapz(B, C.reshape(N, 1), axis=1)

Categories

Resources