[Numpy-discussion] "upsample" or scale an array

Robin Kraft rkraft4 at gmail.com
Sat Dec 3 13:06:22 EST 2011


Ha! I knew it had to be possible! Thanks Derek. So for and N = 2 (now on my laptop):

In [70]: M = 1200
In [69]: N = 2
In [71]: a = np.random.randint(0, 255, (M**2)).reshape(M,-1)

In [76]: timeit np.rollaxis(np.tile(a, N**2).reshape(M,N,-1), 2, 1).reshape(M*N,-1)
10 loops, best of 3: 99.1 ms per loop

In [78]: timeit a.repeat(2, axis=0).repeat(2, axis=1)
10 loops, best of 3: 85.6 ms per loop

In [79]: timeit np.kron(a, np.ones((2,2), 'uint8'))
1 loops, best of 3: 521 ms per loop

It turns out np.kron and repeat are pretty straightforward for multi-dimensional data too - scaling or stretching a stacked array representing pixel data over time, for example. Nothing changes for np.kron - it handles the additional dimensionality by itself. With repeat you just tell it to operate on the last two dimensions.

So to sum up:

1) np.kron is cool for the simplicity of the code and simple scaling to N dimensions. It's also handy if you want to scale the array elements themselves too.
2) repeat() along the last N axes is a bit more intuitive (i.e. less magical) to me and has a better performance profile. 
3) Derek's reshape/rolling solution is almost as fast but it gives me a headache trying to visualize what it's actually doing. I don't want to think about adding another dimension ...

Thanks for the help folks. Here's scaling of a hypothetical time series (i.e. 3 axes), where each sub-array represents a month.


In [26]: print a
[[[1 2]
  [3 4]]

 [[1 2]
  [3 4]]

 [[1 2]
  [3 4]]]

In [27]: np.kron(a, np.ones((2,2), dtype='uint8'))
Out[27]: 
array([[[1, 1, 2, 2],
        [1, 1, 2, 2],
        [3, 3, 4, 4],
        [3, 3, 4, 4]],

       [[1, 1, 2, 2],
        [1, 1, 2, 2],
        [3, 3, 4, 4],
        [3, 3, 4, 4]],

       [[1, 1, 2, 2],
        [1, 1, 2, 2],
        [3, 3, 4, 4],
        [3, 3, 4, 4]]])

In [64]: a.repeat(2, axis=1).repeat(2, axis=2)
Out[64]: 
array([[[1, 1, 2, 2],
        [1, 1, 2, 2],
        [3, 3, 4, 4],
        [3, 3, 4, 4]],

       [[1, 1, 2, 2],
        [1, 1, 2, 2],
        [3, 3, 4, 4],
        [3, 3, 4, 4]],

       [[1, 1, 2, 2],
        [1, 1, 2, 2],
        [3, 3, 4, 4],
        [3, 3, 4, 4]]])

On Dec. 3, 2011, at 12:50PM, Derek Homeier wrote:

> On 03.12.2011, at 6:22PM, Robin Kraft wrote:
> 
> > That does repeat the elements, but doesn't get them into the desired order.
> > 
> > In [4]: print a
> > [[1 2]
> >  [3 4]]
> > 
> > In [7]: np.tile(a, 4)
> > Out[7]: 
> > array([[1, 2, 1, 2, 1, 2, 1, 2],
> >        [3, 4, 3, 4, 3, 4, 3, 4]])
> > 
> > In [8]: np.tile(a, 4).reshape(4,4)
> > Out[8]: 
> > array([[1, 2, 1, 2],
> >        [1, 2, 1, 2],
> >        [3, 4, 3, 4],
> >        [3, 4, 3, 4]])
> > 
> > It's close, but I want to repeat the elements along the two axes, effectively stretching it by the lower right corner:
> > 
> > array([[1, 1, 2, 2],
> >        [1, 1, 2, 2],
> >        [3, 3, 4, 4],
> >        [3, 3, 4, 4]])
> > 
> > It would take some more reshaping/axis rolling to get there, but it seems doable.
> > 
> > Anyone know what combination of manipulations would work with the result of np.tile?
> > 
> Rolling was the keyword:
> 
> np.rollaxis(np.tile(a, 4).reshape(2,2,-1), 2, 1).reshape(4,4))
> [[1 1 2 2]
>  [1 1 2 2]
>  [3 3 4 4]
>  [3 3 4 4]]
> 
> I leave the generalisation and timing up to you, but it seems for 
> a = np.arange(M**2).reshape(M,-1)
> 
> np.rollaxis(np.tile(a, N**2).reshape(M,N,-1), 2, 1).reshape(M*N,-1) 
> 
> should do the trick.
> 
> Cheers,
> 						Derek
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20111203/0dc9ce04/attachment.html>


More information about the NumPy-Discussion mailing list