numpy element-wise multiplication of an array and a vector - python

I want to do something like this:
a = # multi-dimensional numpy array
ares = # multi-dim array, same shape as a
a.shape
>>> (45, 72, 37, 24) # the relevant point is that all dimension are different
v = # 1D numpy array, i.e. a vector
v.shape
>>> (37) # note that v has the same length as the 3rd dimension of a
for i in range(37):
ares[:,:,i,:] = a[:,:,i,:]*v[i]
I'm thinking there has to be a more compact way to do this with numpy, but I haven't figured it out. I guess I could replicate v and then calculate a*v, but I am guessing there is something better than that too. So I need to do element wise multiplication "over a given axis", so to speak. Anyone know how I can do this? Thanks. (BTW, I did find a close duplicate question, but because of the nature of the OP's particular problem there, the discussion was very short and got tracked into other issues.)

Here is one more:
b = a * v.reshape(-1, 1)
IMHO, this is more readable than transpose, einsum and maybe even v[:, None], but pick the one that suits your style.

You can automatically broadcast the vector against the outermost axis of an array. So, you can transpose the array to swap the axis you want to the outside, multiply, then transpose it back:
ares = (a.transpose(0,1,3,2) * v).transpose(0,1,3,2)

You can do this with Einstein summation notation using numpy's einsum function:
ares = np.einsum('ijkl,k->ijkl', a, v)

I tend to do something like
b = a * v[None, None, :, None]
where I think I'm officially supposed to write np.newaxis instead of None.
For example:
>>> import numpy as np
>>> a0 = np.random.random((45,72,37,24))
>>> a = a0.copy()
>>> v = np.random.random(37)
>>> for i in range(len(v)):
... a[:,:,i,:] *= v[i]
...
>>> b = a0 * v[None,None,:,None]
>>>
>>> np.allclose(a,b)
True

Related

Efficiently compute multiple dot products with numpy

I am trying to compute many dot products efficiently. This post gets really close to what I am trying to do, but I can't quite get it to work. I have a large list of matrices (a), and a list of vectors (b). I want to do a series of dot product operations between them. This is what works now:
import numpy as np
a # shape (15000,4,4)
b # shape (15000,4)
out = np.empty((15000,4))
for i in range(15000):
out[i] = np.dot(a[i],b[i])
All my attempts to adapt np.tensordot or np.einsum from the linked post have failed to give me what I want. If anyone sees how to do this I would really appreciate it.
Einstein summation works just fine:
>>> a = np.random.randn(100, 4, 4)
>>> b = np.random.randn(100, 4)
>>> foo = np.einsum('ijk,ik->ij', a, b)
>>> bar = np.zeros_like(foo)
>>> for i, (ai, bi) in enumerate(zip(a, b)):
bar[i] = np.dot(ai, bi)
>>> np.allclose(foo, bar)
True
To explain the summation a bit, note that you're contracting the last axis of b. So you can think about doing each inner product as if by np.einsum('jk,k->j', a[0], b[0]). But we're doing one for each element of a and b, thus the inclusion of the first axis, which is not contracted. Hence, ijk,ik->ij.

Apply a function to each row of a numpy matrix w.r.t. its index

I have a numpy matrix A of shape [n,m] and an array b of length n. What I need is to take sum of b[i] least elements of the i'th row of A.
So the code might look like this:
A = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
b = np.array([2,3,1])
sums = magic_function() #sums = [3, 15, 7]
I've considered np.apply_along_axis() function but it seems that your function can only depend on the row itself in this case.
Vectorized approach making use of NumPy broadcasting to create the mask of valid ones along each row and then perform sum-reduction -
mask = b[:,None] > np.arange(A.shape[1])
out = (A*mask).sum(1)
Alternatively, with np.einsum to get the reduction -
out = np.einsum('ij,ij->i',A,mask)
We can also use np.matmul/# notation on Python 3.x -
out = (A[:,None] # mask[...,None]).squeeze()

Row.T * Row dot product of a matrix

I am searching for a faster and maybe more elegant way to compute the following:
I have a matrix A and I want to compute the row-wise dot product of A. Herby I want to compute Ai.T * Ai, whereby index i indicates the ith row of matrix A.
import numpy as np
A=np.arange(40).reshape(20,2)
sol=[np.dot(A[ii,:].reshape(1,2).T,A[ii,:].reshape(1,2)) for ii in range(20)]
This results in a matrix of shape np.shape(sol) #=(20,2,2)
I already had a look at np.einsum, but could not make it work so far.
If there only exists a solution, where all 20 2x2 matrices are summed, this is also okay, since I want to sum it anyway in the end :)
Thanks
Using np.dot -
A.T.dot(A)
Using np.einsum -
np.einsum('ij,ik->jk',A,A)
Sample run -
>>> A=np.arange(40).reshape(20,2)
>>> sol=[np.dot(A[ii,:].reshape(1,2).T,A[ii,:].reshape(1,2)) for ii in range(20)]
>>> sol = np.array(sol)
>>> sol.sum(0)
array([[ 9880, 10260],
[10260, 10660]])
>>> A.T.dot(A)
array([[ 9880, 10260],
[10260, 10660]])
>>> np.einsum('ij,ik->jk',A,A)
array([[ 9880, 10260],
[10260, 10660]])
If the result must be a 20 element array, I think you need -
np.einsum('ij,ik->i',A,A)

Joining np.arrays Python with a padding

Analogous to:
"True".join(['False','False'])
I'd like to join numpy arrays, e.g.
arr = np.zeros((15,10), dtype=bool)
joiner = np.ones((15,1), dtype=bool)
result = np.hstack((arr, joiner, arr))
result.shape
(15, 21)
That is, I'd like to join a variable amount of arrays with a truth vector in between each of them.
arr, joiner, arr, joiner, arr, ...
How to extend the above for any number of arrays?
We can assume that they all have the same shape.
I came up with a simple quite silly appending method (I expect it to be really slow compared to some solutions out there):
def mergeArrays(*args):
if args:
joiner = np.ones((args[0].shape[0], 1))
new = []
for x in args[:-1]:
new.append(x)
new.append(joiner)
new.append(args[-1])
return np.hstack(new)

Converting list of 2-D arrays into a 3-D array, adding elements along "fast" axes

I have a list of 2d numpy arrays. As a test, consider the following list:
lst = [np.arange(10).reshape(5,2)]*10
Now I can get at a particular data element by:
lst[k][j,i]
I would like to convert this to a numpy array so that I can index it:
array[k,j,i]
i.e., the shape should be (10, 5, 2).
This seems to work, but seems completely unnecessary:
z = np.empty((10,5,2))
for i,x in enumerate(z):
x[:,:] = lst[i]
These don't work:
np.hstack(lst)
np.vstack(lst)
np.dstack(lst) #this is closest, but gives wrong shape (5, 2, 10)
I suppose I could pair a np.dstack with a np.rollaxis, but again, that doesn't seem quite right ...
Is there a good way to do this with numpy?
I've looked at this very related post, but I can't quite seem to work it out.
This should work simply by calling the array constructor, i.e. np.array(lst).
>>> l = [np.arange(10).reshape((5,2)) for i in range(10)]
>>> np.array(l).shape
(10, 5, 2)
Do you mean like
>>> lst = [np.arange(10).reshape(5,2)]*10
>>> arr = np.array(lst)
>>> arr.shape
(10, 5, 2)
?

Categories