Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: How can I force 1-element NumPy arrays to be two-dimensional?

I have piece of code that slices a 2D NumPy array and returns the resulting (sub-)array. In some cases, the slicing only indexes one element, in which case the result is a one-element array:

>>> sub_array = orig_array[indices_h, indices_w]
>>> sub_array.shape
(1,)

How can I force this array to be two-dimensional in a general way? I.e.:

>>> sub_array.shape
(1,1)

I know that sub_array.reshape(1,1) works, but I would like to be able to apply it to sub_array generally without worrying about the number of elements in it. To put it in another way, I would like to compose a (light-weight) operation that converts a shape-(1,) array to a shape-(1,1) array, a shape-(2,2) array to a shape-(2,2) array etc. I can make a function:

def twodimensionalise(input_array):
     if input_array.shape == (1,):
         return input_array.reshape(1,1)
     else:
         return input_array

Is this the best I am going to get or does NumPy have something more 'native'?

Addition:

As pointed out in https://stackoverflow.com/a/31698471/865169, I was doing the indexing wrong. I really wanted to do:

sub_array = orig_array[indices_h][:, indices_w]

This does not work when there is only one entry in indices_h, but combining it with np.atleast_2d suggested in another answer, I arrive at:

sub_array = np.atleast_2d(orig_array[indices_h])[:, indices_w]
like image 900
Thomas Arildsen Avatar asked Jul 29 '15 10:07

Thomas Arildsen


3 Answers

It sounds like you might be looking for atleast_2d. This function returns a view of a 1D array as a 2D array:

>>> arr1 = np.array([1.7]) # shape (1,)
>>> np.atleast_2d(arr1)
array([[ 1.7]])
>>> _.shape
(1, 1)

Arrays that are already 2D (or have more dimensions) are unchanged:

>>> arr2 = np.arange(4).reshape(2,2) # shape (2, 2)
>>> np.atleast_2d(arr2)
array([[0, 1],
       [2, 3]])
>>> _.shape
(2, 2)
like image 56
Alex Riley Avatar answered Oct 06 '22 00:10

Alex Riley


When defining a numpy array you can use the keyword argument ndmin to specify that you want at least two dimensions. e.g.

arr = np.array(item_list, ndmin=2)
arr.shape
>>> (100, 1) # if item_list is 100 elements long etc

In the example in the question, just do

sub_array = np.array(orig_array[indices_h, indices_w], ndmin=2)
sub_array.shape
>>> (1,1)

This can be extended to higher dimensions too, unlike np.atleast_2d().

like image 22
berkelem Avatar answered Oct 06 '22 01:10

berkelem


Are you sure you are indexing in the way you want to? In the case where indices_h and indices_w are broadcastable integer indexing arrays, the result will have the broadcasted shape of indices_h and indices_w. So if you want to make sure that the result is 2D, make the indices arrays 2D.

Otherwise, if you want all combinations of indices_h[i] and indices_w[j] (for all i, j), do e.g. a sequential indexing:

sub_array = orig_array[indices_h][:, indices_w]

Have a look at the documentation for details about advanced indexing.

like image 41
Rob Avatar answered Oct 05 '22 23:10

Rob