Python: 区分行向量和列向量

在 python 中有区分行向量和列向量的好方法吗?到目前为止,我使用了 numpy 和 scipy 我所看到的是,如果我给一个向量,比如

from numpy import *
Vector = array([1,2,3])

他们不能说“天气”我指的是一行或一列的向量,而且:

array([1,2,3]) == array([1,2,3]).transpose()
True

这在“现实世界”中是完全不真实的。 我认识到大多数的向量函数从提到的模块不需要区分。例如 outer(a,b)或者 a.dot(b),但是为了我自己的方便,我想区分一下。

184994 次浏览

It looks like Python's Numpy doesn't distinguish it unless you use it in context:

"You can have standard vectors or row/column vectors if you like. "

" :) You can treat rank-1 arrays as either row or column vectors. dot(A,v) treats v as a column vector, while dot(v,A) treats v as a row vector. This can save you having to type a lot of transposes. "

Also, specific to your code: "Transpose on a rank-1 array does nothing. " Source: http://wiki.scipy.org/NumPy_for_Matlab_Users

You can make the distinction explicit by adding another dimension to the array.

>>> a = np.array([1, 2, 3])
>>> a
array([1, 2, 3])
>>> a.transpose()
array([1, 2, 3])
>>> a.dot(a.transpose())
14

Now force it to be a column vector:

>>> a.shape = (3,1)
>>> a
array([[1],
[2],
[3]])
>>> a.transpose()
array([[1, 2, 3]])
>>> a.dot(a.transpose())
array([[1, 2, 3],
[2, 4, 6],
[3, 6, 9]])

Another option is to use np.newaxis when you want to make the distinction:

>>> a = np.array([1, 2, 3])
>>> a
array([1, 2, 3])
>>> a[:, np.newaxis]
array([[1],
[2],
[3]])
>>> a[np.newaxis, :]
array([[1, 2, 3]])

If you want a distiction for this case I would recommend to use a matrix instead, where:

matrix([1,2,3]) == matrix([1,2,3]).transpose()

gives:

matrix([[ True, False, False],
[False,  True, False],
[False, False,  True]], dtype=bool)

You can also use a ndarray explicitly adding a second dimension:

array([1,2,3])[None,:]
#array([[1, 2, 3]])

and:

array([1,2,3])[:,None]
#array([[1],
#       [2],
#       [3]])

The excellent Pandas library adds features to numpy that make these kinds of operations more intuitive IMO. For example:

import numpy as np
import pandas as pd


# column
df = pd.DataFrame([1,2,3])


# row
df2 = pd.DataFrame([[1,2,3]])

You can even define a DataFrame and make a spreadsheet-like pivot table.

I think you can use ndmin option of numpy.array. Keeping it to 2 says that it will be a (4,1) and transpose will be (1,4).

>>> a = np.array([12, 3, 4, 5], ndmin=2)
>>> print a.shape
>>> (1,4)
>>> print a.T.shape
>>> (4,1)

When I tried to compute w^T * x using numpy, it was super confusing for me as well. In fact, I couldn't implement it myself. So, this is one of the few gotchas in NumPy that we need to acquaint ourselves with.

As far as 1D array is concerned, there is no distinction between a row vector and column vector. They are exactly the same.

Look at the following examples, where we get the same result in all cases, which is not true in (the theoretical sense of) linear algebra:

In [37]: w
Out[37]: array([0, 1, 2, 3, 4])


In [38]: x
Out[38]: array([1, 2, 3, 4, 5])


In [39]: np.dot(w, x)
Out[39]: 40


In [40]: np.dot(w.transpose(), x)
Out[40]: 40


In [41]: np.dot(w.transpose(), x.transpose())
Out[41]: 40


In [42]: np.dot(w, x.transpose())
Out[42]: 40

With that information, now let's try to compute the squared length of the vector |w|^2.

For this, we need to transform w to 2D array.

In [51]: wt = w[:, np.newaxis]


In [52]: wt
Out[52]:
array([[0],
[1],
[2],
[3],
[4]])

Now, let's compute the squared length (or squared magnitude) of the vector w :

In [53]: np.dot(w, wt)
Out[53]: array([30])

Note that we used w, wt instead of wt, w (like in theoretical linear algebra) because of shape mismatch with the use of np.dot(wt, w). So, we have the squared length of the vector as [30]. Maybe this is one of the ways to distinguish (numpy's interpretation of) row and column vector?

And finally, did I mention that I figured out the way to implement w^T * x ? Yes, I did :

In [58]: wt
Out[58]:
array([[0],
[1],
[2],
[3],
[4]])


In [59]: x
Out[59]: array([1, 2, 3, 4, 5])


In [60]: np.dot(x, wt)
Out[60]: array([40])

So, in NumPy, the order of the operands is reversed, as evidenced above, contrary to what we studied in theoretical linear algebra.


P.S. : potential gotchas in numpy

Here's another intuitive way. Suppose we have:

>>> a = np.array([1, 3, 4])
>>> a
array([1, 3, 4])

First we make a 2D array with that as the only row:

>>> a = np.array([a])
>>> a
array([[1, 3, 4]])

Then we can transpose it:

>>> a.T
array([[1],
[3],
[4]])

Use double [] when writing your vectors.

Then, if you want a row vector:

row_vector = array([[1, 2, 3]])    # shape (1, 3)

Or if you want a column vector:

col_vector = array([[1, 2, 3]]).T  # shape (3, 1)

The vector you are creating is neither row nor column. It actually has 1 dimension only. You can verify that by

  • checking the number of dimensions myvector.ndim which is 1
  • checking the myvector.shape, which is (3,) (a tuple with one element only). For a row vector is should be (1, 3), and for a column (3, 1)

Two ways to handle this

  • create an actual row or column vector
  • reshape your current one

You can explicitly create a row or column

row = np.array([    # one row with 3 elements
[1, 2, 3]
]
column = np.array([  # 3 rows, with 1 element each
[1],
[2],
[3]
])

or, with a shortcut

row = np.r_['r', [1,2,3]]     # shape: (1, 3)
column = np.r_['c', [1,2,3]]  # shape: (3,1)

Alternatively, you can reshape it to (1, n) for row, or (n, 1) for column

row = my_vector.reshape(1, -1)
column = my_vector.reshape(-1, 1)

where the -1 automatically finds the value of n.

You can store the array's elements in a row or column as follows:

>>> a = np.array([1, 2, 3])[:, None] # stores in rows
>>> a
array([[1],
[2],
[3]])


>>> b = np.array([1, 2, 3])[None, :] # stores in columns
>>> b
array([[1, 2, 3]])

If I want a 1x3 array, or 3x1 array:

import numpy as np
row_arr = np.array([1,2,3]).reshape((1,3))
col_arr = np.array([1,2,3]).reshape((3,1)))

Check your work:

row_arr.shape  #returns (1,3)
col_arr.shape  #returns (3,1)

I found a lot of answers here are helpful, but much too complicated for me. In practice I come back to shape and reshape and the code is readable: very simple and explicit.

row vectors are (1,0) tensor, vectors are (0, 1) tensor. if using v = np.array([[1,2,3]]), v become (0,2) tensor. Sorry, i am confused.