The task is to create 361x721x11 copies of ll
as fast as possible preferably using the functions in numpy. The following code works
ll = ones((13,25)) # used ones() for illustration purposes. My real array isn't actually just a bunch of ones
ll_ijk = np.repeat(np.repeat(np.repeat(ll[...,None,None,None],361,axis = 2),721,axis = 3),11,axis = 4)
where I used nested calls of the repeat function for each new dimension, but it took about 4-5 seconds to complete. Is there a more/most efficient way of doing this?
The result of your code is an array of shape (13, 25, 361, 721, 11)
in which each slice ll_ijk[:, :, i, j, k]
(for valid indices i
, j
, and j
) has the same shape and all elements equal to your original ll
.
If you do not need to modify these values (and just need the array to have a shape compatible with your other arrays), broadcasting should be fine for you. In that case:
shape = (13, 25, 361, 721, 11)
ll_ijk = np.broadcast_to(ll[:, :, None, None, None], shape)
will be your fastest and most memory efficient option by far. Instead of copying the elements, each slice ll_ijk[:, :, i, j, k]
refers to your original array ll
. As a demonstration, you could change your original array ll
, and note that ll_ijk
changes, too.
ll[0, 0] = 10
ll_ijk[0, 0, 0, 0, 0] # np.float64(10.0)
ll_ijk[0, 0, 0, 0, 1] # np.float64(10.0)
You seemed to be happy with a solution that resulted in a different output shape in which each slice ll_ijk[i, j, k]
is equal to your original ll
. In that case, you do not need to add the extra dimensions to ll
because they will be prepended automatically according to NumPy's standard broadcasting rules. You would write:
shape = (361, 721, 11, 13, 25)
ll_ijk = np.broadcast_to(ll, shape)
But in that case, you probably wouldn't need the explicit broadcasting with np.broadcast_to
. Broadcasting would typically happen automatically whenever you perform an operation with arrays of compatible shapes.
I found it interesting that on my machine, if a copy were required, the solutions with output shape (13, 25, 361, 721, 11)
(your original shape) were much faster than solutions with shape (361, 721, 11, 13, 25)
. This can probably be explained easily in terms of array contiguity, but it's a bit too late for that sort of thought.
np.tile
, which is the function that should be ideal for this purpose, is the slowest of the lot.
ll_ijk = np.tile(ll[:, :, None, None, None], (1, 1, 361, 721, 11))
# 2.5153203749941895
ll_ijk = np.tile(ll, (361, 721, 11, 1, 1))
# 6.901196416001767
One of the solutions in the comments was:
ll_ijk = np.empty((13, 25, 361, 721, 11))
ll_ijk[...] = ll[:, :, None, None, None] # 1.6792952079995302
ll_ijk = np.empty((361, 721, 11, 13, 25))
ll_ijk[...] = ll # 4.837824542002636
Broadcasting with np.broadcast_to
followed by copying is a little faster for me, but YMMV:
ll_ijk = np.broadcast_to(ll[:, :, None, None, None], (13, 25, 361, 721, 11)).copy()
# 1.5269727080012672
ll_ijk = np.broadcast_to(ll, (361, 721, 11, 13, 25)).copy()
# 3.9539862910023658