Main Question: Is it bad (perhaps in terms of computation time or memory) to using np.array([[1, 2, 3]])
everywhere instead of np.array([1, 2, 3])
?
Motivation:
I come form a math background, so I like to think of things in terms of vectors and matrices. For example, I think of y = np.array([1, 2, 3])
as a row vector, or as a 1 X 3 matrix. However, numpy doesn't treat y quite like a 1 X 3 matrix. For instance, if we take a 2 X 3 matrix A = np.array([[1, 2, 3], [4, 5, 6]])
numpy will allow us to do the matrix multiplication A @ y
even though the dimensions are (2 X 3) times (1 X 3) don't make sense mathematically.
On the other hand, y @ AT
gives an error even though the dimensions (1 X 3) times (3 X 2) make sense.
So in conclusion np.array([1, 2, 3])
does not behave exactly as a matrix. However, from my experiments it seems that numpy does treat np.array([[1, 2, 3]])
as a bona fide 1 X 3 matrix. So if there are no downsides, I would prefer to use this version.
numpy
has an old subclass np.matrix
that makes sure everything has exactly 2 dimensions. But it is no longer recommended.
numpy
tries to work equally well with 0,1,2, and more dimensions.
In [69]: A = np.array([[1,2,3],[4,5,6]])
In [70]: x = np.array([1,2,3])
In [71]: y = np.array([[1,2,3]])
In [72]: A.shape
Out[72]: (2, 3)
Matrix product of a (2,3) with (3,) resulting a (2,). It's docs say it expands the (3,) to (3,1), getting a (2,1) result, and then squeezing out that 1:
In [73]: A@x
Out[73]: array([14, 32])
The (2,3) with (1,3) transposed produces (2,1):
In [74]: A@y.T
Out[74]:
array([[14],
[32]])
(3,) with (3,2) => (2,):
In [78]: x@A.T
Out[78]: array([14, 32])
(1,3) with (3,2) => (1,3):
In [79]: y@A.T
Out[79]: array([[14, 32]])
How does your math intuition handle 3d or higher arrays? matmul/@
handles them nicely. np.einsum
does even better.
While you can create a (1,n) arrays, if it makes you more comfortable. But beware that you'll still end up with 1 or even 0d results.
For example with indexing:
In [80]: A
Out[80]:
array([[1, 2, 3],
[4, 5, 6]])
In [81]: A[1,:]
Out[81]: array([4, 5, 6])
In [82]: A[:,1]
Out[82]: array([2, 5])
In [83]: A[1,1]
Out[83]: 5
In [84]: A[1,1].shape
Out[84]: ()
In [85]: A[1,1].ndim
Out[85]: 0
or reduction along an axis:
In [86]: A.sum(axis=1)
Out[86]: array([ 6, 15])
though it's possible to retain dimensions:
In [87]: A.sum(axis=1, keepdims=True)
Out[87]:
array([[ 6],
[15]])
In [88]: A[[1],:]
Out[88]: array([[4, 5, 6]])
In [89]: A[:,[1]]
Out[89]:
array([[2],
[5]])
Another to keep in mind is that numpy operators most operation element-wise. The main exception being @
. Where as in MATLAB A*B
is matrix multiplication, and A.*B
is element-wise. Add to that broadcasting
, which allows us to add a (2,3) and (3,) array:
In [90]: A+x
Out[90]:
array([[2, 4, 6],
[5, 7, 9]])
Here (2,3) + (3,) => (2,3) + (1,3) => (2,3). The (3,) 1d array often behaves as a (1,3) or even (1,1,3) if needed. But expansion in the other direction has to be explicit.
In [92]: A / A.sum(axis=1) # (2,3) with (2,) error
Traceback (most recent call last):
File "<ipython-input-92-fec3395556f9>", line 1, in <module>
A / A.sum(axis=1)
ValueError: operands could not be broadcast together with shapes (2,3) (2,)
In [93]: A / A.sum(axis=1, keepdims=True) # (2,3) with (2,1) ok
Out[93]:
array([[0.16666667, 0.33333333, 0.5 ],
[0.26666667, 0.33333333, 0.4 ]])
In [94]: A / A.sum(axis=1)[:,None]
Out[94]:
array([[0.16666667, 0.33333333, 0.5 ],
[0.26666667, 0.33333333, 0.4 ]])
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.