MarkII
MarkII

Reputation: 892

Numpy matrix sum without looping

Trying to build a numpy matrix without double for loops

if i have a matrix:

x = [val, val, val]
    [val, val, val]
    [val, val, val]

and I want to subtract each row's items with the other two rows while simultaneously extrapolating to a larger matrix with final result. Each row substraction (in this example) is 3 elements. (I'm doing it with larger matrices though)

new = [row 1 - 2,      0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
      [row 1 - 3,      0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
      [0.0, 0.0, 0.0,  row 2 - 1,     0.0, 0.0, 0.0]
      [0.0, 0.0, 0.0,  row 2 - 3,     0.0, 0.0, 0.0]
      [0.0, 0.0, 0.0,  0.0, 0.0, 0.0  row 3 - 1]
      [0.0, 0.0, 0.0,  0.0, 0.0, 0.0  row 3 - 2]

And then similar but with the columns instead except the items are filled in horizontally, if that makes sense (each item is a single value vs above)

new = [col 1 - 2, 0.0, 0.0, col 1 - 2, 0.0, 0.0, col 1 - 2, 0.0, 0.0]
      [col 1 - 3, 0.0, 0.0, col 1 - 3, 0.0, 0.0, col 1 - 3, 0.0, 0.0]
      [0.0, col 2 - 1, 0.0, 0.0, col 2 - 1, 0.0, 0.0, col 2 - 1, 0.0]
      [0.0, col 2 - 3, 0.0, 0.0, col 2 - 3, 0.0, 0.0, col 2 - 3, 0.0]
      [0.0, 0.0, col 3 - 1, 0.0, 0.0, col 3 - 1, 0.0, 0.0, col 3 - 1]
      [0.0, 0.0, col 3 - 2, 0.0, 0.0, col 3 - 2, 0.0, 0.0, col 3 - 2]

If someone has the numpy magic to figure this, I'll lose it ha.

Edit: better example with small matrix:

x = [[.5, 0.], 
     [.1, 1.2]]

turns into

new = [[ 0.4, -1.2,  0.,   0. ],
       [ 0.,   0.,  -0.4,  1.2]]

and for column version

y = [[.2, .9], 
     [.6, .1]]

turns into

new = [[-0.7,  0.,   0.5,  0. ],
       [ 0.,   0.7,  0.,  -0.5]]

Upvotes: 2

Views: 205

Answers (1)

Paul Panzer
Paul Panzer

Reputation: 53029

Here is some indexing madness which I believe does what you are asking for:

>>> def magic(data):
...     n, m = data.shape
...     assert n==m
...     rows = np.zeros((n, n-1, n, n), data.dtype)
...     cols = np.zeros((n, n-1, n, n), data.dtype)
...     idx = np.argsort(np.identity(n), kind='mergesort', axis=1)
...     self = idx[:, -1] # should be just 0, 1, 2, 3, ...
...     other = idx[:, :-1]
...     rows[self, :, self, :] = data[:, None, :] - data[other[..., None], self]
...     cols[self, ..., self] = data.T[:, None, :] - data.T[other[..., None], self] 
...     return rows.reshape(-1, n*n), cols.reshape(-1, n*n)
... 
>>> magic(np.array([[.5,0], [.1,1.2]]))
(array([[ 0.4, -1.2,  0. ,  0. ],
       [ 0. ,  0. , -0.4,  1.2]]), array([[ 0.5,  0. , -1.1,  0. ],
       [ 0. , -0.5,  0. ,  1.1]]))
>>> magic(np.array([[.2,.9], [.6,.1]]))
(array([[-0.4,  0.8,  0. ,  0. ],
       [ 0. ,  0. ,  0.4, -0.8]]), array([[-0.7,  0. ,  0.5,  0. ],
       [ 0. ,  0.7,  0. , -0.5]]))

Upvotes: 3

Related Questions