Rich
Rich

Reputation: 12663

How to make a `numpy` array view that repeats

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

Answers (3)

Raymond
Raymond

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

hpaulj
hpaulj

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

user2357112
user2357112

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

Related Questions