Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numpy matrix subtraction over each column of another matrix

Tags:

python

numpy

I know in numpy if you have a matrix A and I subtract a vector v by performing A - v, v will be broadcasted so that v becomes the same dimension as A and an elementwise subtraction will be performed.

I was wondering if I had to perform the above operation many times with the same A but with different v, would I be able to do it using vectorization.

A naive implementation would be as follow

def foo(A, V):
   """
   @params: A, V
   A - an n by m matrix
   V - a list of n by 1 column vectors
   @returns: result
   """

   result = []
   for v in V:
      result.append(A-v)
   return result

I know that I could pass in V as a n by p matrix where each column represents a v. However, I couldn't think of any way of describing the above operation in terms of linear algebra

For example if

 A = [[1 2 3], 
      [1 2 3]]

 V = [[1 4], 
      [1 4]]  

the output should be two matrices

[
  [[0 1 2], 
  [0,1,2]], 

  [[-3 -2 -1], 
  [-3 -2, -1]]
]
like image 652
coderhk Avatar asked Oct 24 '25 05:10

coderhk


2 Answers

a = np.zeros((4,3)) + [1,2,3]
V = [np.ones(3),np.ones(3)*2,np.ones(3)*3]

Your desired is

>>> a-V[0]
array([[0., 1., 2.],
       [0., 1., 2.],
       [0., 1., 2.],
       [0., 1., 2.]])
>>> a-V[1] 
array([[-1.,  0.,  1.],
       [-1.,  0.,  1.],
       [-1.,  0.,  1.],
       [-1.,  0.,  1.]])
>>> a-V[2]
array([[-2., -1.,  0.],
       [-2., -1.,  0.],
       [-2., -1.,  0.],
       [-2., -1.,  0.]])

Stack the vectors in V then add a dimension to subtract.

>>> W = np.vstack(V)
>>> a - W[:,None,:]
array([[[ 0.,  1.,  2.],
        [ 0.,  1.,  2.],
        [ 0.,  1.,  2.],
        [ 0.,  1.,  2.]],

       [[-1.,  0.,  1.],
        [-1.,  0.,  1.],
        [-1.,  0.,  1.],
        [-1.,  0.,  1.]],

       [[-2., -1.,  0.],
        [-2., -1.,  0.],
        [-2., -1.,  0.],
        [-2., -1.,  0.]]])

Try it again adjusting for (n,m) is (4,3)

a = np.zeros((4,3)) + [1,2,3]       # (n.m) = (4,3)
V = [np.ones(4),np.ones(4)*2,np.ones(4)*3]  # three (nx1) vectors
W = np.vstack(V)

>>> a.shape
(4, 3)
>>> W.shape
(3, 4)
>>> Z = a - W[...,None] 
>>> Z[0]
array([[0., 1., 2.],
       [0., 1., 2.],
       [0., 1., 2.],
       [0., 1., 2.]])
>>> Z[1]
array([[-1.,  0.,  1.],
       [-1.,  0.,  1.],
       [-1.,  0.,  1.],
       [-1.,  0.,  1.]])
>>> Z[2]
array([[-2., -1.,  0.],
       [-2., -1.,  0.],
       [-2., -1.,  0.],
       [-2., -1.,  0.]])
>>> Z.shape             
(3, 4, 3)
like image 169
wwii Avatar answered Oct 25 '25 18:10

wwii


In [104]:  A = [[1, 2, 3],
     ...:       [1, 2, 3]]
     ...: 
     ...:  V = [[1, 4],
     ...:       [1, 4]]
In [105]: A=np.array(A);V=np.array(V)
In [106]: A              # (n,m)
Out[106]: 
array([[1, 2, 3],
       [1, 2, 3]])
In [107]: V               # (n,p)
Out[107]: 
array([[1, 4],
       [1, 4]])

The iterative subtraction; [0] used to make the array (2,1) (which broadcasts with (2,3) A:

In [108]: [A-V[:,[0]], A-V[:,[1]]]
Out[108]: 
[array([[0, 1, 2],
        [0, 1, 2]]),
 array([[-3, -2, -1],
        [-3, -2, -1]])]

Lets try whole array broadcasting:

In [109]: A[None,:,:]-V[:,:,None]
Out[109]: 
array([[[ 0,  1,  2],
        [-3, -2, -1]],

       [[ 0,  1,  2],
        [-3, -2, -1]]])

Oops, wrong mix; try again, changing V to (p,n). That would have been clearer is V wasn't (2,2):

In [110]: A[None,:,:]-V.T[:,:,None]
Out[110]: 
array([[[ 0,  1,  2],
        [ 0,  1,  2]],

       [[-3, -2, -1],
        [-3, -2, -1]]])

With (2,4) V:

In [112]: V1=np.hstack((V,V))
In [113]: V1.shape
Out[113]: (2, 4)
In [114]: (A[None,:,:]-V1.T[:,:,None]).shape
Out[114]: (4, 2, 3)
In [115]: (A-V1.T[:,:,None]).shape
Out[115]: (4, 2, 3)
like image 32
hpaulj Avatar answered Oct 25 '25 17:10

hpaulj



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!