Reputation: 12663
How can I slice a numpy
array beyond its shape such that values in the array are repeated without having to store the entire array in memory? Here's what I'd like to do:
x = numpy.array([[1, 2], [3, 4]])
x[0:3, 0:3]
->
[[1, 2, 1, 2],
[3, 4, 3, 4],
[1, 2, 1, 2],
[3, 4, 3, 4]]
I am aware of numpy.repeat
and numpy.tile
but both of these make a copy of the array, and I would like to slice my array like x[1238123:1238143,5328932:5328941]
without needing to make millions of copies of the smaller array.
Upvotes: 2
Views: 415
Reputation: 41
Use numpy.ndarray.take
twice for 2D array (triple for 3D array, etc.). Each time you'd specify a different axis. For the case you required:
x.take(range(0, 4), mode='wrap', axis = 0).take(range(0, 4), mode='wrap', axis = 1)
which would produce
array([[1, 2, 1, 2],
[3, 4, 3, 4],
[1, 2, 1, 2],
[3, 4, 3, 4]])
Upvotes: 0
Reputation: 231605
With strides
tricks we can make an 4d view:
In [18]: x = numpy.array([[1, 2], [3, 4]])
In [19]: as_strided = np.lib.stride_tricks.as_strided
In [20]: X = as_strided(x, shape=(2,2,2,2), strides=(0,16,0,8))
In [21]: X
Out[21]:
array([[[[1, 2],
[1, 2]],
[[3, 4],
[3, 4]]],
[[[1, 2],
[1, 2]],
[[3, 4],
[3, 4]]]])
Which can be reshaped into your desired array:
In [22]: X.reshape(4,4)
Out[22]:
array([[1, 2, 1, 2],
[3, 4, 3, 4],
[1, 2, 1, 2],
[3, 4, 3, 4]])
But that reshaping will create a copy of X
.
That (2,2) array can be used in calculations as (1,1,2,2) array, which if needed is expanded to (2,2,2,2):
In [25]: x[None,None,:,:]
Out[25]:
array([[[[1, 2],
[3, 4]]]])
In [26]: np.broadcast_to(x,(2,2,2,2))
Out[26]:
array([[[[1, 2],
[3, 4]],
[[1, 2],
[3, 4]]],
[[[1, 2],
[3, 4]],
[[1, 2],
[3, 4]]]])
Thus broadcasting lets us use a view of an array in larger calculations.
Upvotes: 4
Reputation: 281683
NumPy arrays don't support that. An array has to have a consistent stride in each dimension, and the array you want wouldn't have that.
You could implement your own custom type for the result, but it wouldn't work at NumPy speed, and it wouldn't be directly compatible with NumPy - at best, any NumPy function you tried to call would have to build a real array out of your object first.
If your use case only needs small slices, as with your x[1238123:1238143,5328932:5328941]
example, your best bet is probably to adjust the slice endpoints down to equivalent, smaller values, then tile and slice.
Upvotes: 2