0

I am trying to convert a list into a numpy array with a specified number of columns. I can get the code to work outside the function as follows:

import numpy as np

ls = np.linspace(1,100,100) # Data Sample
ls = np.array(ls) # list --> array

# resize | outside function
ls.resize(ls.shape[0]//2,2)
print(ls)

>> [[   1.    2.]
    [   3.    4.]
           .
           .
           .
    [  97.   98.]
    [  99.  100.]]

I do not understand my error when trying to throw the routine in a function. My attempt is as follows:

# resize | inside function
def shapeshift(mylist, num_col):
    num_col = int(num_col)
    return mylist.resize(mylist.shape[0]//num_col,num_col)

ls = shapeshift(ls,2)
print(ls)

>> None

I want to define the original function in this way because I want another function, consisting of the same inputs and a third input to loop over rows when extracting values, to call this original function for each loop over rows.

  • I suspect that `resize` works in-place and returns `None`. Try returning `mylist` itself one line later. – Paul Panzer Mar 30 '17 at 03:02
  • Returning `mylist` one line later makes no difference in the function output. If the `resize` works in-place, is there a more efficient and convenient method of achieving this without for loops? Ultimately, I'd like to define another function with the same inputs and a third input, so that I can call the function above and loop over each row. –  Mar 30 '17 at 03:09
  • Apparently the function form (i.e. `np.resize(a, new_shp)` as opposed to the method form `a.resize(new_shp)`) does not work in-place and creates a new array. So you could try using that instead. – Paul Panzer Mar 30 '17 at 03:14
  • I tried that method but it only returns the first `new_shp` elements. If `new_shp=2`, then it returns `[1,2]`. I suppose I could make the function argument a list of even values from `2` to `100` for this sample case, but I am still hopeful that there is a more efficient way to do this. –  Mar 30 '17 at 03:19
  • You can use a tuple for `new_shp`; like `np.reshape(a, (m, n))`. In your example `m=50, n=2`. – Paul Panzer Mar 30 '17 at 03:25
  • That works perfectly, thank you. I can mark it correct if you post it as an answer. –  Mar 30 '17 at 03:29

2 Answers2

2
In [402]: ls = np.linspace(1,100,10)
In [403]: ls
Out[403]: array([   1.,   12.,   23.,   34.,   45.,   56.,   67.,   78.,   89.,  100.])
In [404]: ls.shape
Out[404]: (10,)

No need to wrap again in array; it already is one:

In [405]: np.array(ls)
Out[405]: array([   1.,   12.,   23.,   34.,   45.,   56.,   67.,   78.,   89.,  100.])

resize operates in-place. It returns nothing (or None)

In [406]: ls.resize(ls.shape[0]//2,2)
In [407]: ls
Out[407]: 
array([[   1.,   12.],
       [  23.,   34.],
       [  45.,   56.],
       [  67.,   78.],
       [  89.,  100.]])
In [408]: ls.shape
Out[408]: (5, 2)

With this resize you aren't changing the number of elements, so reshape would work just as well.

In [409]: ls = np.linspace(1,100,10)
In [410]: ls.reshape(-1,2)
Out[410]: 
array([[   1.,   12.],
       [  23.,   34.],
       [  45.,   56.],
       [  67.,   78.],
       [  89.,  100.]])

reshape in either method or function form returns a value, leaving ls unchanged. The -1 is a handy short hand, avoiding the // division.

This is the inplace version of reshape:

In [415]: ls.shape=(-1,2)

reshape requires the same total number of elements. resize allows you to change the number of elements, truncating or repeating values if needed. We use reshape much more often then resize. repeat and tile are also more common than resize.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
2

The .resize method works in-place and returns None. It also refuses to work at all if there are other names referencing the same array. You can use the function form, which creates a new array and is not as capricious:

def shapeshift(mylist, num_col):
    num_col = int(num_col)
    return np.resize(mylist, (mylist.size//num_col,num_col))
Paul Panzer
  • 51,835
  • 3
  • 54
  • 99