In numpy
the dimensions of the resulting array vary at run time.
There is often confusion between a 1d array and a 2d array with 1 column.
In one case I can ite
I asked about dtype
because your example is puzzling.
I can make a structured array with 3 elements (1d) and 3 fields:
In [1]: A = np.ones((3,), dtype='i,i,i')
In [2]: A
Out[2]:
array([(1, 1, 1), (1, 1, 1), (1, 1, 1)],
dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])
I can access one field by name (adding brackets doesn't change things)
In [3]: A['f0'].shape
Out[3]: (3,)
but if I access 2 fields, I still get a 1d array
In [4]: A[['f0','f1']].shape
Out[4]: (3,)
In [5]: A[['f0','f1']]
Out[5]:
array([(1, 1), (1, 1), (1, 1)],
dtype=[('f0', '<i4'), ('f1', '<i4')])
Actually those extra brackets do matter, if I look at values
In [22]: A['f0']
Out[22]: array([1, 1, 1], dtype=int32)
In [23]: A[['f0']]
Out[23]:
array([(1,), (1,), (1,)],
dtype=[('f0', '<i4')])
If the array is a simple 2d one, I still don't get your shapes
In [24]: A=np.ones((3,3),int)
In [25]: A[0].shape
Out[25]: (3,)
In [26]: A[[0]].shape
Out[26]: (1, 3)
In [27]: A[[0,1]].shape
Out[27]: (2, 3)
But as to question of making sure an array is 2d, regardless of whether the indexing returns 1d or 2, your function is basically ok
def reshape_to_vect(ar):
if len(ar.shape) == 1:
return ar.reshape(ar.shape[0],1)
return ar
You could test ar.ndim
instead of len(ar.shape)
. But either way it is not costly - that is, the execution time is minimal - no big array operations. reshape
doesn't copy data (unless your strides are weird), so it is just the cost of creating a new array object with a shared data pointer.
Look at the code for np.atleast_2d
; it tests for 0d and 1d. In the 1d case it returns result = ary[newaxis,:]
. It adds the extra axis first, the more natural numpy
location for adding an axis. You add it at the end.
ar.reshape(ar.shape[0],-1)
is a clever way of bypassing the if
test. In small timing tests it faster, but we are talking about microseconds, the effect of a function call layer.
np.column_stack
is another function that creates column arrays if needed. It uses:
if arr.ndim < 2:
arr = array(arr, copy=False, subok=True, ndmin=2).T
There are mainly two ways to go from 1 dimensional array (N) to 2 dimensional
array with 1 column
(N x 1):
reshape()
method.x = np.array([1, 2, 3]) # shape: (3,) <- 1d
x[:, None] # shape: (3, 1) <- 2d (single column matrix)
x[:, np.newaxis] # shape: (3, 1) <- a meaningful alias to None
x.reshape(-1, 1) # shape: (3, 1)
The simplest way:
ar.reshape(-1, 1)
To avoid the need to reshape in the first place, if you slice a row / column with a list, or a "running" slice, you will get a 2D array with one row / column
import numpy as np
x = np.array(np.random.normal(size=(4,4)))
print x, '\n'
Result:
[[ 0.01360395 1.12130368 0.95429414 0.56827029]
[-0.66592215 1.04852182 0.20588886 0.37623406]
[ 0.9440652 0.69157556 0.8252977 -0.53993904]
[ 0.6437994 0.32704783 0.52523173 0.8320762 ]]
y = x[:,[0]]
print y, 'col vector \n'
Result:
[[ 0.01360395]
[-0.66592215]
[ 0.9440652 ]
[ 0.6437994 ]] col vector
y = x[[0],:]
print y, 'row vector \n'
Result:
[[ 0.01360395 1.12130368 0.95429414 0.56827029]] row vector
# Slice with "running" index on a column
y = x[:,0:1]
print y, '\n'
Result:
[[ 0.01360395]
[-0.66592215]
[ 0.9440652 ]
[ 0.6437994 ]]
Instead if you use a single number for choosing the row/column, it will result in a 1D array, which is the root cause of your issue:
y = x[:,0]
print y, '\n'
Result:
[ 0.01360395 -0.66592215 0.9440652 0.6437994 ]
You could do -
ar.reshape(ar.shape[0],-1)
That second input to reshape
: -1
takes care of the number of elements for the second axis. Thus, for a 2D
input case, it does no change. For a 1D
input case, it creates a 2D
array with all elements being "pushed" to the first axis because of ar.shape[0]
, which was the total number of elements.
Sample runs
1D Case :
In [87]: ar
Out[87]: array([ 0.80203158, 0.25762844, 0.67039516, 0.31021513, 0.80701097])
In [88]: ar.reshape(ar.shape[0],-1)
Out[88]:
array([[ 0.80203158],
[ 0.25762844],
[ 0.67039516],
[ 0.31021513],
[ 0.80701097]])
2D Case :
In [82]: ar
Out[82]:
array([[ 0.37684126, 0.16973899, 0.82157815, 0.38958523],
[ 0.39728524, 0.03952238, 0.04153052, 0.82009233],
[ 0.38748174, 0.51377738, 0.40365096, 0.74823535]])
In [83]: ar.reshape(ar.shape[0],-1)
Out[83]:
array([[ 0.37684126, 0.16973899, 0.82157815, 0.38958523],
[ 0.39728524, 0.03952238, 0.04153052, 0.82009233],
[ 0.38748174, 0.51377738, 0.40365096, 0.74823535]])
A variant of the answer by divakar is: x = np.reshape(x, (len(x),-1))
, which also deals with the case when the input is a 1d or 2d list.