Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between numpy.array shape (R, 1) and (R,)

In numpy, some of the operations return in shape (R, 1) but some return (R,). This will make matrix multiplication more tedious since explicit reshape is required. For example, given a matrix M, if we want to do numpy.dot(M[:,0], numpy.ones((1, R))) where R is the number of rows (of course, the same issue also occurs column-wise). We will get matrices are not aligned error since M[:,0] is in shape (R,) but numpy.ones((1, R)) is in shape (1, R).

So my questions are:

  1. What's the difference between shape (R, 1) and (R,). I know literally it's list of numbers and list of lists where all list contains only a number. Just wondering why not design numpy so that it favors shape (R, 1) instead of (R,) for easier matrix multiplication.

  2. Are there better ways for the above example? Without explicitly reshape like this: numpy.dot(M[:,0].reshape(R, 1), numpy.ones((1, R)))

like image 744
clwen Avatar asked Feb 26 '14 20:02

clwen


People also ask

What does the shape of a NumPy array mean?

The shape of an array is the number of elements in each dimension.

What is the difference between shape and reshape in NumPy?

The shape tool gives a tuple of array dimensions and can be used to change the dimensions of an array. The reshape tool gives a new shape to an array without changing its data. It creates a new array and does not modify the original array itself.

What does .shape 1 mean in Python?

Python numpy shape 1 Shape[1] is n. shape is a tuple that always gives dimensions of the array. The shape function is a tuple that gives you an arrangement of the number of dimensions in the array.

What's the difference between array shape and array size?

So, when you call shape , you get the N dimension shape of the array, so you can see exactly how your array looks like. In essence, size is equal to the product of the elements of shape . EDIT: The difference in name can be attributed to 2 parts: firstly, you can initialise your array with a size.


2 Answers

1. The meaning of shapes in NumPy

You write, "I know literally it's list of numbers and list of lists where all list contains only a number" but that's a bit of an unhelpful way to think about it.

The best way to think about NumPy arrays is that they consist of two parts, a data buffer which is just a block of raw elements, and a view which describes how to interpret the data buffer.

For example, if we create an array of 12 integers:

>>> a = numpy.arange(12) >>> a array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11]) 

Then a consists of a data buffer, arranged something like this:

┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ 

and a view which describes how to interpret the data:

>>> a.flags   C_CONTIGUOUS : True   F_CONTIGUOUS : True   OWNDATA : True   WRITEABLE : True   ALIGNED : True   UPDATEIFCOPY : False >>> a.dtype dtype('int64') >>> a.itemsize 8 >>> a.strides (8,) >>> a.shape (12,) 

Here the shape (12,) means the array is indexed by a single index which runs from 0 to 11. Conceptually, if we label this single index i, the array a looks like this:

i= 0    1    2    3    4    5    6    7    8    9   10   11 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ 

If we reshape an array, this doesn't change the data buffer. Instead, it creates a new view that describes a different way to interpret the data. So after:

>>> b = a.reshape((3, 4)) 

the array b has the same data buffer as a, but now it is indexed by two indices which run from 0 to 2 and 0 to 3 respectively. If we label the two indices i and j, the array b looks like this:

i= 0    0    0    0    1    1    1    1    2    2    2    2 j= 0    1    2    3    0    1    2    3    0    1    2    3 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ 

which means that:

>>> b[2,1] 9 

You can see that the second index changes quickly and the first index changes slowly. If you prefer this to be the other way round, you can specify the order parameter:

>>> c = a.reshape((3, 4), order='F') 

which results in an array indexed like this:

i= 0    1    2    0    1    2    0    1    2    0    1    2 j= 0    0    0    1    1    1    2    2    2    3    3    3 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ 

which means that:

>>> c[2,1] 5 

It should now be clear what it means for an array to have a shape with one or more dimensions of size 1. After:

>>> d = a.reshape((12, 1)) 

the array d is indexed by two indices, the first of which runs from 0 to 11, and the second index is always 0:

i= 0    1    2    3    4    5    6    7    8    9   10   11 j= 0    0    0    0    0    0    0    0    0    0    0    0 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ 

and so:

>>> d[10,0] 10 

A dimension of length 1 is "free" (in some sense), so there's nothing stopping you from going to town:

>>> e = a.reshape((1, 2, 1, 6, 1)) 

giving an array indexed like this:

i= 0    0    0    0    0    0    0    0    0    0    0    0 j= 0    0    0    0    0    0    1    1    1    1    1    1 k= 0    0    0    0    0    0    0    0    0    0    0    0 l= 0    1    2    3    4    5    0    1    2    3    4    5 m= 0    0    0    0    0    0    0    0    0    0    0    0 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ 

and so:

>>> e[0,1,0,0,0] 6 

See the NumPy internals documentation for more details about how arrays are implemented.

2. What to do?

Since numpy.reshape just creates a new view, you shouldn't be scared about using it whenever necessary. It's the right tool to use when you want to index an array in a different way.

However, in a long computation it's usually possible to arrange to construct arrays with the "right" shape in the first place, and so minimize the number of reshapes and transposes. But without seeing the actual context that led to the need for a reshape, it's hard to say what should be changed.

The example in your question is:

numpy.dot(M[:,0], numpy.ones((1, R))) 

but this is not realistic. First, this expression:

M[:,0].sum() 

computes the result more simply. Second, is there really something special about column 0? Perhaps what you actually need is:

M.sum(axis=0) 
like image 182
Gareth Rees Avatar answered Oct 05 '22 01:10

Gareth Rees


The difference between (R,) and (1,R) is literally the number of indices that you need to use. ones((1,R)) is a 2-D array that happens to have only one row. ones(R) is a vector. Generally if it doesn't make sense for the variable to have more than one row/column, you should be using a vector, not a matrix with a singleton dimension.

For your specific case, there are a couple of options:

1) Just make the second argument a vector. The following works fine:

    np.dot(M[:,0], np.ones(R)) 

2) If you want matlab like matrix operations, use the class matrix instead of ndarray. All matricies are forced into being 2-D arrays, and operator * does matrix multiplication instead of element-wise (so you don't need dot). In my experience, this is more trouble that it is worth, but it may be nice if you are used to matlab.

like image 39
Evan Avatar answered Oct 05 '22 01:10

Evan