numpy中的坑点主要来自于shape、ndim、broadcast几方面,接下来将做详细分析
行向量 & 列向量 & 1-D数组
-
上述3个概念,主要区别于shape,这将引起很多差异
-
term shape example col-vector (m, 1) [[1], [2], [3]] row-vector (1, m) [[1, 2, 3]] 1-D array (m,) [1, 2, 3] -
通过观察上述表格,可以发现不论是哪种term,其本质都是array,其中col-vector 和 row-vector都是 2-D array
-
1-D array和 vector的相互转化主要借助于reshape函数,也可以采用其他**ndim改变手段****
# (m,) -> (m, 1) | (1, m) cv = a.reshape((-1, 1)) # rv = a.reshape((1, -1)) v = np.array([a]) # (m, 1) <-> (1, m) rv = cv.T # cv = rv.T # (m, 1) | (1, m) -> (m,) a = v.shape(-1)
矩阵乘法 & np.dot()
-
np.dot(a, b)并不是专门用来做矩阵乘法的,并且需要注意的是矩阵shape不合适时,会通过broadcast改造a、b,但这有时会带来很多麻烦
-
官网文档表明,对于不同类型的a、b,np.dot(a, b)会有不同的行为:
- If both a and b are 1-D arrays, it is inner product of vectors (without complex conjugation).
- If both a and b are 2-D arrays, it is matrix multiplication, but using
matmul
ora @ b
is preferred. - If either a or b is 0-D (scalar), it is equivalent to
multiply
and usingnumpy.multiply(a, b)
ora * b
is preferred. - If a is an N-D array and b is a 1-D array, it is a sum product over the last axis of a and b.
- If a is an N-D array and b is an M-D array (where
M>=2
), it is a sum product over the last axis of a and the second-to-last axis of b:
-
如果两个矩阵都是1-D的,则相当于**点积(内积)****
-
针对 1-D x 2-D 和 2-D x 1D 情形,说明如下:
X = np.arange(16).reshape((4, 4)) # 2-D x = np.ones(4) # 1-D # 1-D x 2-D a = np.dot(x, X) # reuslt: array([ 6., 22., 38., 54.]) # 2-D x 1-D b = np.dot(X, x) # reuslt: array([ 6., 22., 38., 54.])
计算过程如下图, 可以认为:
- 当左矩阵为1-D 时,可以把(m, )当做(1, m)来用,从而构成一个常规的矩阵乘法
- 当右矩阵为1-D时,相当于对左矩阵在axis-0上做加权和 😭真令人迷惑!
点积 & np.vdot()
- np.vdot(a, b)是专门用于向量点积的函数
- 对于任何数学实质是1-D向量的变量(包括 行向量、列向量、1-D 数组),作用都是点积,a、b的顺序无所谓
- 对于 n-D 向量 ,都将被flatten成一个长长的 1-D 向量, 然后执行点积操作
a = np.array([[1, 4], [5, 6]])
b = np.array([[4, 1], [2, 2]])
np.vdot(a, b) # 1*4 + 4*1 + 5*2 + 6*2
# result: 30
np.array 切片 & 索引
- 一般情况下,切片没什么好说的
- 当切片的结果为1行/1列时,结果总会作为1-D array
X = np.arange(16).reshape((4, 4))
X[:, 0]
# result: array([0, 4, 8, 12])
X[0, :]
# result: array[0, 1, 2, 3]
- 对于2-D的行向量或者列向量,可以仅有时直接用**x[0]**来得到 x 0 x_0 x0的引用(值),这与x[0, 0]效果相同
x = np.ones((4, 1))
y = np.ones((1, 4))
z = np.ones(4)
x[0]
# result: array([1])
y[0]
# result: array([1, 1, 1, 1])
z[0]
# result: 1
x[0] = 9
# result: x -> array([[9], [1], [1], [1]])
y[0] = 9
# result: y -> array([[9, 9, 9, 9]])
z[0] =9
# result: y -> array([9, 1, 1, 1])
总结
- 综上所述,我们需要特别关注 array 的 shape、ndim
- 1-D array 在 np.dot() 中可当做行向量, 列向量在索引时可当做 1-D array