Python equivalent of (matrix)*(vector) in R

Viewed 358

In R, when I execute the code below:

> X=matrix(1,2,3)
> c=c(1,2,3)
> X*c

R gives out the following output:

     [,1] [,2] [,3]
[1,]    1    3    2
[2,]    2    1    3

But when I do the below on Python:

>>> import numpy as np
>>> X=np.array([[1,1,1],[1,1,1]]) 
>>> c=np.array([1,2,3])
>>> X*c

the Python code above gives the following output:

array([[1, 2, 3],
       [1, 2, 3]])

Is there any way that I can make the Python to come up with the identical output as R? I think I somehow have to tell Python that I want the numpy to multiply each element of the matrix X by each element of the vector c along the column, instead of along the row, but I am not sure how to go about this.

2 Answers
In [18]: np.reshape([1,2,3]*2,(2,3),order='F')                                  
Out[18]: 
array([[1, 3, 2],
       [2, 1, 3]])

This starts with a list multiply, which is replication:

In [19]: [1,2,3]*2                                                              
Out[19]: [1, 2, 3, 1, 2, 3]

The rest uses numpy to reshape it into a (2,3) array, but with consecutive values going down, 'F' order.

Not knowning R, and in particular the c(1,2,3) expression, I can't say that's what's going on in R.

===

You talk about rows with columns, but I don't see how that works in your example. That said, we can easily perform outer like products

===

This reproduces your R_Product (at least in a few test cases):

In [138]: def foo(X,c): 
     ...:     X1 = X.ravel() 
     ...:     Y = np.resize(c,X1.shape)*X1 
     ...:     return Y.reshape(X.shape, order='F') 
     ...:                                                                       
In [139]: foo(np.ones((2,3)),np.arange(1,4))                                    
Out[139]: 
array([[1., 3., 2.],
       [2., 1., 3.]])
In [140]: foo(np.arange(6).reshape(2,3),np.arange(1,4))                         
Out[140]: 
array([[ 0,  6,  8],
       [ 2,  3, 15]])

I'm using the resize function to replicate c to match the total number of elements of X. And order F to stack them in the desired column order. The default for numpy is order C.

In numpy replicating an array to match another is not common, at least not in this sense. Replicating by row or column, as in broadcasting is common. And of course reshaping.

I am the OP. I was looking for a quick and easy solution, but I guess there is no straightforward functionality in Python that allows us to do this. So, I had to make a function that multiplies a matrix with a vector in the same manner that R does:

def R_product(X,c):

"""
Computes the regular R product 
(not same as the matrix product) between 
a 2D Numpy Array X, and a numpy vector c.

Args:
   X: 2D Numpy Array
   c: A Numpy vector

Returns: the output of X*c in R. 
         (This is different than X/*/c in R)
"""
    X_nrow = X.shape[0]
    X_ncol = X.shape[1]
    X_dummy = np.zeros(shape=((X_nrow * X_ncol),1))
    nrow = X_dummy.shape[0]
    nc = nrow // len(c)
    Y = np.zeros(shape=(nrow,1))

    for j in range(X_ncol):
        for u in range(X_nrow):
            X_element = X[u,j]
                
            if u == X_nrow - 1:
                idx = X_nrow * (j+1) - 1 
            else:
                idx = X_nrow * j + (u+1) - 1
                    
            X_dummy[idx,0] = X_element

    for i in range(nc):
        for j in range(len(c)):
            Y[(i*len(c)+j):(i*len(c)+j+1),:] = (X_dummy[(i*len(c)+j):(i*len(c)+j+1),:]) * c[j]
     
    for z in range(nrow-nc*len(c)):
        Y[(nc*len(c)+z):(nc*len(c)+z+1),:] = (X_dummy[(nc*len(c)+z):(nc*len(c)+z+1),:]) * c[z]

    return Y.reshape(X_ncol, X_nrow).transpose() # the answer I am looking for

Should work.

Related