Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

adding numpy arrays of differing shapes

Tags:

python

numpy

I'd like to add two numpy arrays of different shapes, but without broadcasting, rather the "missing" values are treated as zeros. Probably easiest with an example like

[1, 2, 3] + [2] -> [3, 2, 3]

or

[1, 2, 3] + [[2], [1]] -> [[3, 2, 3], [1, 0, 0]]

I do not know the shapes in advance.

I'm messing around with the output of np.shape for each, trying to find the smallest shape which holds both of them, embedding each in a zero-ed array of that shape and then adding them. But it seems rather a lot of work, is there an easier way?

Thanks in advance!

edit: by "a lot of work" I meant "a lot of work for me" rather than for the machine, I seek elegance rather than efficiency: my effort getting the smallest shape holding them both is

def pad(a, b) :
    sa, sb = map(np.shape, [a, b])
    N = np.max([len(sa),len(sb)])
    sap, sbp = map(lambda x : x + (1,)*(N-len(x)), [sa, sb])
    sp = np.amax( np.array([ tuple(sap), tuple(sbp) ]), 1)

not pretty :-/

like image 475
n00b Avatar asked Apr 23 '13 23:04

n00b


2 Answers

I'm messing around with the output of np.shape for each, trying to find the smallest shape which holds both of them, embedding each in a zero-ed array of that shape and then adding them. But it seems rather a lot of work, is there an easier way?

Getting the np.shape is trivial, finding the smallest shape that holds both is very easy, and of course adding is trivial, so the only "a lot of work" part is the "embedding each in a zero-ed array of that shape".

And yes, you can eliminate that, by just calling the resize method (or the resize function, if you want to make copies instead of changing them in-place). As the docs explain:

Enlarging an array: … missing entries are filled with zeros

For example, if you know the dimensionality statically:

>>> a1 = np.array([[1, 2, 3], [4, 5, 6]])
>>> a2 = np.array([[2], [2]])
>>> shape = [max(a.shape[axis] for a in (a1, a2)) for axis in range(2)]
>>> a1.resize(shape)
>>> a2.resize(shape)
>>> print(a1 + a2)
array([[3, 4, 3],
       [4, 5, 6]])
like image 155
abarnert Avatar answered Sep 23 '22 08:09

abarnert


This is the best I could come up with:

import numpy as np

def magic_add(*args):
    n = max(a.ndim for a in args)
    args = [a.reshape((n - a.ndim)*(1,) + a.shape) for a in args]
    shape = np.max([a.shape for a in args], 0)
    result = np.zeros(shape)

    for a in args:
        idx = tuple(slice(i) for i in a.shape)
        result[idx] += a
    return result

You can clean up the for loop a little if you know how many dimensions you expect on result, something like:

for a in args:
    i, j = a.shape
    result[:i, :j] += a
like image 34
Bi Rico Avatar answered Sep 22 '22 08:09

Bi Rico