numpy.broadcasting allows to perform basic operations (additions, multiplication, etc.) with arrays of different shapes (under certain conditions on these shapes). For example:
>>> a = np.array([0.0, 10.0, 20.0, 30.0])
>>> b = np.array([1.0, 2.0, 3.0])
>>> a[:, np.newaxis] + b
array([[ 1., 2., 3.],
[11., 12., 13.],
[21., 22., 23.],
[31., 32., 33.]])
Each element of the output array is the addition of the elements in the input arrays. This can be described as an 'outer addition operation'.
Is there a simple way to do this with the concatenation operator instead? In other words, is there a simple way to perform an 'outer concatenation operation'? Which means that, with the previous example, the output array should be:
array([[[ 0., 1.],
[ 0., 2.],
[ 0., 3.]],
[[10., 1.],
[10., 2.],
[10., 3.]],
[[20., 1.],
[20., 2.],
[20., 3.]],
[[30., 1.],
[30., 2.],
[30., 3.]]])
With few tries, I came up with this solution using numpy.meshgrid but it looks quite under-optimized to me and might be improved:
>>> a = np.array([0.0, 10.0, 20.0, 30.0])
>>> b = np.array([1.0, 2.0, 3.0])
>>> c,d = np.meshgrid(a,b)
>>> np.concatenate((c.T[..., None], d.T[..., None]), axis=-1)
array([[[ 0., 1.],
[ 0., 2.],
[ 0., 3.]],
[[10., 1.],
[10., 2.],
[10., 3.]],
[[20., 1.],
[20., 2.],
[20., 3.]],
[[30., 1.],
[30., 2.],
[30., 3.]]])
Is there a more 'pythonic' way to do this?
I added a fast broadcasted assignment solution at the end.
What does it mean to be more 'pythonic' (or in this case more 'numpy-onic')?
If it runs and produces the desire result, is that enough? 'one liners' are stylish in
perl, but notpython.broadcastingis a valid concept when using operators like+, butconcatenateisn't an operator.In sense then we are left with comparing speeds. But all speed tests need to be qualified by the size of the arrays.
Anyways for your test case:
The
broadcast_arraysapproach produces two arrays, similar tomeshgrid(actually just their transpose):Speed is slightly better, but not an 'order of magnitude':
But we can construct the same
broadcastedarrays withrepeat(that's a good compiled numpy method):And surprise, it's faster:
So which is more 'pythonic'? For this small example the repeat is faster, even if it is 'wordier'. My guess is that for much larger arrays, the
broadcast_arrayswill scale better.broadcasting code
Someone found and down-voted my answer to a previous broadcasting question
what happens under the hood of broadcasting a numpy array
Comments suggest looking at the source code found in
np.lib.stride_tricks.broadcast_arrayis python code, and uses_broadcast_to. That in turn usesnp.nditer. That's known to be slow, at least in the python interface version.The arrays produced by
meshgridand myrepeatsare copies. But the arrays produced bybroadcast_arrays(Out[34]), are views, created fromaandbby playing with theshapeandstrides. Normally making a view is fast since it doesn't have to copy thebasevalues. But my guess is that the setup code for thestride_tricksfunctions is time consuming.As suggested by the module name,
stride_tricks, using thisbroadcast_arraysfunction is a nice, cute trick, but not essential to understanding or usingnumpy, and especially not the normal use ofbroadcastingwith operators.broadcasted assignment
Here's an even better version. Instead of using concatenate, it makes the target array directly, and fills it in with values from
aandb:This does utilize
broadcasting, as can be seen with an erronious assignment:broadcastingis not just used by binary operators, it is also used duringadvanced indexing, and as shown here when assigning values to a slice of an array.Here a (4,1)
acan fit the (4,3) slot, and (3,)bcan also fit that size slot.