Max Taggart
Max Taggart

Reputation: 823

Numpy `resize` gives an unexpected array size when using -1 syntax

I am trying to understand the difference between numpy.resize and numpy.reshape. I know that resize will return a new array and that reshape will maintain the same underlying data and only adjust the size (I'm assuming it does this by changing the stride). However, for both functions I would expect to be able to use the -1 syntax to specify an axis size. However, this appears to only work for reshape. For example, trying to reshape/resize this 1-D array of shape (444,) to an array of shape (4, 111) gives two different results depending on whether you use resize or reshape:

import numpy as np

test = np.arange(0, 444)
print(test.shape)
print(np.resize(test, (4, -1)).shape)
print(np.reshape(test, (4, -1)).shape)

prints

(444,)
(4, 110)
(4, 111)

I'm assuming that I'm missing something about the resize function, but I would expect it to either output a shape that is compatible with (444,) or throw an error.

Upvotes: 2

Views: 447

Answers (2)

Daniel F
Daniel F

Reputation: 14399

Going through the source code of np.resize, you can see what is going on, and that -1 was never intended as an input:

def resize(a, new_shape):
    if isinstance(new_shape, (int, nt.integer)):
        new_shape = (new_shape,)
    a = ravel(a)
    Na = len(a)   # Na = 444
    total_size = um.multiply.reduce(new_shape)   # total_size = 4 * -1 = -4 (?!?)
    if Na == 0 or total_size == 0:
        return mu.zeros(new_shape, a.dtype)

    n_copies = int(total_size / Na)    # n_copies = 0, luckily
    extra = total_size % Na            # -4 % 444 = 440 (this is where the 110 comes from)

    if extra != 0:  # True
        n_copies = n_copies + 1        # n_copies = 1 
        extra = Na - extra             # extra = 444 - 440 = 4

    a = concatenate((a,) * n_copies)   # a stays same
    if extra > 0:                      # True
        a = a[:-extra]                 # a = a[:-4]
    return reshape(a, new_shape)       # this is .reshape(4, -1) which now gives (4, 110)

Upvotes: 2

hpaulj
hpaulj

Reputation: 231375

np.resize behavior with -1 is not documented. But it can be deduced from the Python code, or the following examples:

In [312]: np.resize(np.arange(12),(1,-1))                                       
Out[312]: array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10]])
In [313]: np.resize(np.arange(12),(2,-1))                                       
Out[313]: 
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])
In [314]: np.resize(np.arange(12),(3,-1))                                       
Out[314]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
In [315]: np.resize(np.arange(12),(4,-1))                                       
Out[315]: 
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7]])
# (5,-1) error
In [317]: np.resize(np.arange(12),(6,-1))                                       
Out[317]: 
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5]])

So in general

a = np.arange(n)
np.resize(a, (m,-1))
np.reshape(a[:(n-m)], (m,-1))

that is it clips the input by m elements, and attempts the reshape. Not exactly useful, is it?

In your case test[:-4].reshape(4,-1).

Upvotes: 1

Related Questions