7

If you have a sparse matrix X:

>> X = csr_matrix([[0,2,0,2],[0,2,0,1]])
>> print type(X)    
>> print X.todense()    
<class 'scipy.sparse.csr.csr_matrix'>
[[0 2 0 2]
 [0 2 0 1]]

And a matrix Y:

>> print type(Y)
>> print text_scores
<class 'numpy.matrixlib.defmatrix.matrix'>
[[8]
 [5]]

...How can you multiply each element of X by the rows of Y. For example:

[[0*8 2*8 0*8 2*8]
 [0*5 2*5 0*5 1*5]]

or:

[[0 16 0 16]
 [0 10 0 5]]

I've tired this but obviously it doesn't work as the dimensions dont match: Z = X.data * Y

3 Answers 3

9

Unfortunatly the .multiply method of the CSR matrix seems to densify the matrix if the other one is dense. So this would be one way avoiding that:

# Assuming that Y is 1D, might need to do Y = Y.A.ravel() or such...

# just to make the point that this works only with CSR:
if not isinstance(X, scipy.sparse.csr_matrix):
    raise ValueError('Matrix must be CSR.')

Z = X.copy()
# simply repeat each value in Y by the number of nnz elements in each row: 
Z.data *= Y.repeat(np.diff(Z.indptr))

This does create some temporaries, but at least its fully vectorized, and it does not densify the sparse matrix.


For a COO matrix the equivalent is:

Z.data *= Y[Z.row] # you can use np.take which is faster then indexing.

For a CSC matrix the equivalent would be:

Z.data *= Y[Z.indices]
Sign up to request clarification or add additional context in comments.

3 Comments

No, for COO, you would need to do Z.data *= Y[Z.row] I think, or np.take instead of indexing if you care about speed.
That works. It does that without densifying the matrix right?
I think I will add it to the answer. Like the other one it only makes Y as large as the nonzero elements of Z, it does not densify Z.
1

Something I use to perform row-wise (resp. column-wise) multiplication is to use matrix multiplication with a diagonal matrix on the left (resp. on the right):

import numpy as np
import scipy.sparse as sp

X = sp.csr_matrix([[0,2,0,2],
                   [0,2,0,1]])
Y = np.array([8, 5])

D = sp.diags(Y) # produces a diagonal matrix which entries are the values of Y
Z = D.dot(X) # performs D @ X, multiplication on the left for row-wise action

Sparsity is preserved (in CSR format):

print(type(Z))
>>> <class 'scipy.sparse.csr.csr_matrix'>

And the output is also correct:

print(Z.toarray()) # Z is still sparse and gives the right output
>>> print(Z.toarray()) # Z is still sparse and gives the right output
[[ 0. 16.  0. 16.]
 [ 0. 10.  0.  5.]]

Comments

0

I had same problem. Personally I didn't find the documentation of scipy.sparse very helpful, neither found function that handles it directly. So I tried to write it myself and this solved for me:

Z = X.copy()
for row_y_idx in range(Y.shape[0]):
    Z.data[Z.indptr[row_y_idx]:Z.indptr[row_y_idx+1]] *= Y[row_y_idx, 0]

The idea is: for each element of Y in position row_y_idx-th, perform a scalar multiplication with the row_y_idx-th row of X. More info about accessing elements in CSR matrices here (where data is A, IA is indptr).

Given X and Y as you defined:

import numpy as np
import scipy.sparse as sps

X = sps.csr_matrix([[0,2,0,2],[0,2,0,1]])
Y = np.matrix([[8], [5]])

Z = X.copy()
for row_y_idx in range(Y.shape[0]):
    Z.data[Z.indptr[row_y_idx]:Z.indptr[row_y_idx+1]] *= Y[row_y_idx, 0]

print(type(Z))
print(Z.todense())

The output is the same as yours:

<class 'scipy.sparse.csr.csr_matrix'>
 [[ 0 16  0 16]
  [ 0 10  0  5]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.