2

I have three matrices W H and V. I want to get keep which stores elementwise multiplication between all column of V and each column of W and do sum by row.

(V has 6 rows, W also has 6 rows. Each column of W (which has 6 elements) multiplies with 6 elements of every column of Vcolumn-by-column. Then sum the results by row)

W = np.random.randint(4,6, size=(6, 4))
H = np.random.randint(1,3, size=(4, 5))
V = np.dot(W,H) + 1    
keep = np.array([]).reshape(0,6)

print W
>>[[4 4 5 5]
 [4 4 4 4]
 [4 5 5 4]
 [4 5 5 5]
 [5 4 4 5]
 [5 4 4 5]]
print V
>>[[28 33 32 37 24]
 [25 29 29 33 21]
 [28 33 33 37 24]
 [30 35 34 39 25]
 [28 32 32 37 23]
 [28 32 32 37 23]]

# I want the result from only two from four rows of W
group = 2
for k in xrange(group):
    # multiply all of each column of V by k-th column of W and sum in row
    keep = np.vstack([keep, sum(V[:,:].T*W[:,k])])

print keep, keep.shape
>>[[ 616.  548.  620.  652.  760.  760.]
  [ 616.  548.  775.  815.  608.  608.]] (2L, 6L)

I wonder this can be done without for loop? Like sum(V[:,:].T*W[:,0:1] Although, I don't think it is possible because each column of W has to multiplies matrix V in stepwise, I am sure someone has better idea (or confirm it can't).

I try to avoid for loop as this is a part of long algorithm and I hope it can be super fast when group is up to hundreds.

Divakar
  • 218,885
  • 19
  • 262
  • 358
Jan
  • 1,389
  • 4
  • 17
  • 43

1 Answers1

2

Seems like a perfect fit for np.einsum, as we need to the keep the first axis aligned between the two inputs and keep it in the output -

np.einsum('ij,ik->ki',V,W)

Sample run -

In [2]: W = np.random.randint(4,6, size=(6, 4))
   ...: H = np.random.randint(1,3, size=(4, 5))
   ...: V = np.dot(W,H) + 1    
   ...: keep = np.array([]).reshape(0,6)
   ...: 

In [5]: group = W.shape[1]
   ...: for k in xrange(group):
   ...:     # multiply all of each column of V by k-th column of W and sum in row
   ...:     keep = np.vstack([keep, sum(V[:,:].T*W[:,k])])
   ...:     

In [6]: np.allclose(keep, np.einsum('ij,ik->ki',V,W))
Out[6]: True
Divakar
  • 218,885
  • 19
  • 262
  • 358
  • 1
    Wow! Never knew this before. Do you mind explain about arrow between subscript a bit? And if I don't want to use all matrix, I just define like `np.einsum('ij,ik->ki',V,W[:,0:2])`? – Jan Aug 28 '17 at 05:45
  • 1
    @Jan [`This comment`](https://stackoverflow.com/questions/45896939/using-python-numpy-einsum-to-obtain-dot-product-between-2-matrices/45896957#comment78752868_45896957) might help on understanding the subscript notation. Yes, that `np.einsum('ij,ik->ki',V,W[:,0:2])` should work if you are only with the first 2 cols of `W`. – Divakar Aug 28 '17 at 05:48
  • Thanks so much. Let me ask one more thing. If before `sum` in `keep`, I have a denominator; `keep = np.vstack([keep, sum((V.T*W[:,k]).T/deno)])` where `deno = np.dot(W,H)` (`keep` has to be changed to `keep = np.array([]).reshape(0,5)`). How to input the denominator in the `np.einsum`? Or I have to use something else if I have division? – Jan Aug 28 '17 at 06:39
  • 1
    @Jan Just do : `np.einsum('ij,ik->kj',V/deno,W)`. – Divakar Aug 28 '17 at 06:51