解释numpy中dim、shape、rank、dimension和axis的区别

2024-09-19 21:36:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我对python和numpy基本上还不熟悉。我读了几本教程,仍然对dim、rands、shape、aix和dimensions之间的差异感到困惑。我的思想似乎被矩阵表示法所束缚。所以如果你说A是一个矩阵,它看起来是这样的:

A = 

1 2 3
4 5 6

我能想到的就是一个2x3矩阵(两行三列)。我知道这里的形状是2x3。但我真的不能不去想二维矩阵。我不明白例如dot() documentation当它说“对于N维,它是a的最后一个轴和b的第二个轴的和积”。我很困惑,无法理解。我不明白V是N:1向量,M是N:N矩阵,点(V,M)或点(M,V)是如何工作的,以及它们之间的区别。

那么有谁能给我解释一下什么是N维数组,什么是形状,什么是轴,它和dot()函数的文档有什么关系?如果解释能使这些想法形象化,那就太好了。


Tags: numpydocumentation教程矩阵差异向量dot思想
6条回答

NumPy数组的维数必须用data structures sense来理解,而不是数学意义上的维数,也就是说,它是获取标量值所需的标量索引的数量。(*)

例如,这是一个三维数组:

>>> X = np.arange(24).reshape(2, 3, 4)
>>> X
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])

索引一次可生成二维数组(矩阵):

>>> X[0]
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

索引两次给出一维数组(矢量),索引三次给出标量。

X的秩是它的维数:

>>> X.ndim
3
>>> np.rank(X)
3

Axis大致等同于dimension;它用于广播操作:

>>> X.sum(axis=0)
array([[12, 14, 16, 18],
       [20, 22, 24, 26],
       [28, 30, 32, 34]])
>>> X.sum(axis=1)
array([[12, 15, 18, 21],
       [48, 51, 54, 57]])
>>> X.sum(axis=2)
array([[ 6, 22, 38],
       [54, 70, 86]])

老实说,我觉得这个“rank”的定义很混乱,因为它既不匹配属性名ndim,也不匹配属性名linear algebra definition of rank

现在关于np.dot,您需要了解的是,有三种方法可以表示NumPy中的向量:一维数组、形状为(n, 1)的列向量或形状为(1, n)的行向量。(实际上,有更多的方法,例如作为一个(1, n, 1)形状的数组,但这些方法非常少见。)np.dot当两个参数都是1-d时执行向量乘法,当一个参数是1-d而另一个参数是2-d时执行矩阵向量乘法,否则执行(广义)矩阵乘法:

>>> A = np.random.randn(2, 3)
>>> v1d = np.random.randn(2)
>>> np.dot(v1d, A)
array([-0.29269547, -0.52215117,  0.478753  ])
>>> vrow = np.atleast_2d(v1d)
>>> np.dot(vrow, A)
array([[-0.29269547, -0.52215117,  0.478753  ]])
>>> vcol = vrow.T
>>> np.dot(vcol, A)
Traceback (most recent call last):
  File "<ipython-input-36-98949c6de990>", line 1, in <module>
    np.dot(vcol, A)
ValueError: matrices are not aligned

规则“在a的最后一个轴上和b的第二个轴上的和积”匹配并推广了矩阵乘法的一般定义。

(*)数组dtype=object有点异常,因为它们将任何Python对象视为标量。

NumPy数组的维数必须在data structures sense中理解,而不是数学意义上的维数,也就是说,它是获得标量值所需的标量索引的数量。(*)

例如,这是一个三维数组:

>>> X = np.arange(24).reshape(2, 3, 4)
>>> X
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])

索引一次可生成二维数组(矩阵):

>>> X[0]
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

索引两次给出一维数组(矢量),索引三次给出标量。

X的秩是它的维数:

>>> X.ndim
3
>>> np.rank(X)
3

Axis大致等同于dimension;它用于广播操作:

>>> X.sum(axis=0)
array([[12, 14, 16, 18],
       [20, 22, 24, 26],
       [28, 30, 32, 34]])
>>> X.sum(axis=1)
array([[12, 15, 18, 21],
       [48, 51, 54, 57]])
>>> X.sum(axis=2)
array([[ 6, 22, 38],
       [54, 70, 86]])

老实说,我觉得这个“rank”的定义很混乱,因为它既不匹配属性名ndim,也不匹配属性名linear algebra definition of rank

现在关于np.dot,您需要了解的是,有三种方法可以表示NumPy中的向量:一维数组、形状为(n, 1)的列向量或形状为(1, n)的行向量。(实际上,有更多的方法,例如作为(1, n, 1)形状的数组,但这些方法非常少见。)np.dot当两个参数都是1-d时执行向量乘法,当一个参数是1-d而另一个参数是2-d时执行矩阵向量乘法,否则执行(广义)矩阵乘法:

>>> A = np.random.randn(2, 3)
>>> v1d = np.random.randn(2)
>>> np.dot(v1d, A)
array([-0.29269547, -0.52215117,  0.478753  ])
>>> vrow = np.atleast_2d(v1d)
>>> np.dot(vrow, A)
array([[-0.29269547, -0.52215117,  0.478753  ]])
>>> vcol = vrow.T
>>> np.dot(vcol, A)
Traceback (most recent call last):
  File "<ipython-input-36-98949c6de990>", line 1, in <module>
    np.dot(vcol, A)
ValueError: matrices are not aligned

规则“在a的最后一个轴上和b的第二个轴上的和积”匹配并推广了矩阵乘法的一般定义。

(*)数组dtype=object有点异常,因为它们将任何Python对象视为标量。

对你来说

  1. A是二维数组,即矩阵,其形状为(2,3)。来自numpy.matrix的docstring:

    A matrix is a specialized 2-D array that retains its 2-D nature through operations.

  2. numpy.rank返回数组的维数的数目,这与rank in linear algebra的概念有很大不同,例如A是维数/秩2的数组。

  3. np.dot(V, M),或V.dot(M)将矩阵VM相乘。注意numpy.dot尽可能地进行乘法运算。如果V为N:1,M为N:N,则V.dot(M)将引发ValueError

例如:

In [125]: a
Out[125]: 
array([[1],
       [2]])

In [126]: b
Out[126]: 
array([[2, 3],
       [1, 2]])

In [127]: a.dot(b)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-127-9a1f5761fa9d> in <module>()
----> 1 a.dot(b)

ValueError: objects are not aligned

编辑:

我不明白(N,)和(N,1)的形状之间的区别,它与dot()文档有关。

形状(N,)的V表示长度为N的1D数组,而形状(N,1)表示具有N行1列的2D数组:

In [2]: V = np.arange(2)

In [3]: V.shape
Out[3]: (2,)

In [4]: Q = V[:, np.newaxis]

In [5]: Q.shape
Out[5]: (2, 1)

In [6]: Q
Out[6]: 
array([[0],
       [1]])

正如np.dot的docstring所说:

For 2-D arrays it is equivalent to matrix multiplication, and for 1-D arrays to inner product of vectors (without complex conjugation).

如果其中一个参数是向量,它还执行向量矩阵乘法。说V.shape==(2,); M.shape==(2,2)

In [17]: V
Out[17]: array([0, 1])

In [18]: M
Out[18]: 
array([[2, 3],
       [4, 5]])

In [19]: np.dot(V, M)  #treats V as a 1*N 2D array
Out[19]: array([4, 5]) #note the result is a 1D array of shape (2,), not (1, 2)

In [20]: np.dot(M, V)  #treats V as a N*1 2D array
Out[20]: array([3, 5]) #result is still a 1D array of shape (2,), not (2, 1)

In [21]: Q             #a 2D array of shape (2, 1)
Out[21]: 
array([[0],
       [1]])

In [22]: np.dot(M, Q)  #matrix multiplication
Out[22]: 
array([[3],            #gets a result of shape (2, 1)
       [5]])

对你来说

  1. A是二维数组,即矩阵,其形状为(2,3)。来自numpy.matrix的docstring:

    A matrix is a specialized 2-D array that retains its 2-D nature through operations.

  2. numpy.rank返回数组的维数的数目,这与rank in linear algebra的概念有很大不同,例如A是维数/秩2的数组。

  3. np.dot(V, M),或V.dot(M)将矩阵VM相乘。注意numpy.dot尽可能地进行乘法运算。如果V为N:1,M为N:N,则V.dot(M)将引发ValueError

例如:

In [125]: a
Out[125]: 
array([[1],
       [2]])

In [126]: b
Out[126]: 
array([[2, 3],
       [1, 2]])

In [127]: a.dot(b)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-127-9a1f5761fa9d> in <module>()
----> 1 a.dot(b)

ValueError: objects are not aligned

编辑:

我不理解(N,)和(N,1)的形状之间的区别,它与dot()文档有关。

形状(N,)的V表示长度为N的1D数组,而形状(N,1)表示具有N行1列的2D数组:

In [2]: V = np.arange(2)

In [3]: V.shape
Out[3]: (2,)

In [4]: Q = V[:, np.newaxis]

In [5]: Q.shape
Out[5]: (2, 1)

In [6]: Q
Out[6]: 
array([[0],
       [1]])

正如np.dot的docstring所说:

For 2-D arrays it is equivalent to matrix multiplication, and for 1-D arrays to inner product of vectors (without complex conjugation).

如果其中一个参数是向量,它还执行向量矩阵乘法。说V.shape==(2,); M.shape==(2,2)

In [17]: V
Out[17]: array([0, 1])

In [18]: M
Out[18]: 
array([[2, 3],
       [4, 5]])

In [19]: np.dot(V, M)  #treats V as a 1*N 2D array
Out[19]: array([4, 5]) #note the result is a 1D array of shape (2,), not (1, 2)

In [20]: np.dot(M, V)  #treats V as a N*1 2D array
Out[20]: array([3, 5]) #result is still a 1D array of shape (2,), not (2, 1)

In [21]: Q             #a 2D array of shape (2, 1)
Out[21]: 
array([[0],
       [1]])

In [22]: np.dot(M, Q)  #matrix multiplication
Out[22]: 
array([[3],            #gets a result of shape (2, 1)
       [5]])

np.dot是矩阵乘法的推广。 在正则矩阵乘法中,(N,M)形矩阵与(M,P)形矩阵相乘得到(N,P)形矩阵。合成的形状可以认为是通过将两个形状挤压在一起((N,M,M,P)),然后去掉中间的数字M(产生(N,P))而形成的。这是np.dot在泛化到高维数组时保留的属性。

当医生说

"For N dimensions it is a sum product over the last axis of a and the second-to-last of b".

这正说明了这一点。一个以形状数组(u,v,M)点缀的形状数组(w,x,y,M,z)将产生一个形状数组(u,v,w,x,y,z)


让我们看看这个规则应用于

In [25]: V = np.arange(2); V
Out[25]: array([0, 1])

In [26]: M = np.arange(4).reshape(2,2); M
Out[26]: 
array([[0, 1],
       [2, 3]])

首先,简单的部分:

In [27]: np.dot(M, V)
Out[27]: array([1, 3])

这并不奇怪,这只是矩阵向量乘法。

现在考虑一下

In [28]: np.dot(V, M)
Out[28]: array([2, 3])

看V和M的形状:

In [29]: V.shape
Out[29]: (2,)

In [30]: M.shape
Out[30]: (2, 2)

所以np.dot(V,M)就像是(2,)-形矩阵与(2,2)形矩阵的矩阵乘法,应该得到(2,)-形矩阵。

V的最后一个轴(也是唯一的)和M的第二个到最后一个轴(也称为M的第一个轴)相乘和相加,只留下M的最后一个轴。

如果您想可视化这个:np.dot(V, M)看起来V有1行2列:

[[0, 1]] * [[0, 1],
            [2, 3]] 

所以,当V乘以M时,np.dot(V, M)等于

[[0*0 + 1*2],     [2, 
 [0*1 + 1*3]]   =  3] 

然而,我并不建议尝试以这种方式可视化NumPy数组——至少我从来没有这样做过。我几乎只关注形状。

(2,) * (2,2)
   \   /
    \ /
    (2,)

你只需想想“中间”轴被点着,然后从结果形状中消失。


np.sum(arr, axis=0)告诉NumPy对第0轴中的元素进行求和。如果arr是二维的,则第0个轴是行。例如,如果arr看起来像这样:

In [1]: arr = np.arange(6).reshape(2,3); arr
Out[1]: 
array([[0, 1, 2],
       [3, 4, 5]])

然后np.sum(arr, axis=0)将沿着列求和,从而消除第0个轴(即行)。

In [2]: np.sum(arr, axis=0)
Out[2]: array([3, 5, 7])

3是0+3的结果,5等于1+4,7等于2+5。

注意arr有形状(2,3),求和后,第0轴被移除,因此结果是形状(3,)。第0轴的长度为2,每个和由添加这2个元素组成。形状(2,3)“变成”(3,)。你可以提前知道结果形状!这有助于引导你的思维。

要测试您的理解,请考虑np.sum(arr, axis=1)。现在1轴被移除。因此结果形状将是(2,),结果中的元素将是3个值的和。

In [3]: np.sum(arr, axis=1)
Out[3]: array([ 3, 12])

3等于0+1+2,12等于3+4+5。


所以我们看到对一个轴进行求和可以从结果中消除这个轴。这与np.dot有关,因为np.dot执行的计算是产品的之和。由于np.dot沿某些轴执行求和操作,因此将从结果中删除该轴。这就是为什么将np.dot应用于形状(2,)和(2,2)的数组会产生形状(2,)的数组的原因。两个数组中的前2个相加,消除了这两个数组,只剩下第二个数组中的第二个2。

np.dot是矩阵乘法的推广。 在正则矩阵乘法中,(N,M)形矩阵与(M,P)形矩阵相乘得到(N,P)形矩阵。合成的形状可以认为是通过将两个形状挤压在一起((N,M,M,P)),然后去掉中间的数字M(产生(N,P))而形成的。这是np.dot在泛化到高维数组时保留的属性。

当医生说

"For N dimensions it is a sum product over the last axis of a and the second-to-last of b".

这正说明了这一点。一个以形状数组(u,v,M)点缀的形状数组(w,x,y,M,z)将产生一个形状数组(u,v,w,x,y,z)


让我们看看这个规则应用于

In [25]: V = np.arange(2); V
Out[25]: array([0, 1])

In [26]: M = np.arange(4).reshape(2,2); M
Out[26]: 
array([[0, 1],
       [2, 3]])

首先,简单的部分:

In [27]: np.dot(M, V)
Out[27]: array([1, 3])

这并不奇怪,这只是矩阵向量乘法。

现在考虑一下

In [28]: np.dot(V, M)
Out[28]: array([2, 3])

看V和M的形状:

In [29]: V.shape
Out[29]: (2,)

In [30]: M.shape
Out[30]: (2, 2)

所以np.dot(V,M)就像是(2,)-形矩阵与(2,2)形矩阵的矩阵乘法,结果应该是(2,)-形矩阵。

V的最后(也是唯一)轴和M的第二个到最后一个轴(也称为M的第一个轴)相乘和相加,只留下M的最后一个轴。

如果您想可视化这个:np.dot(V, M)看起来V有1行2列:

[[0, 1]] * [[0, 1],
            [2, 3]] 

所以,当V乘以M时,np.dot(V, M)等于

[[0*0 + 1*2],     [2, 
 [0*1 + 1*3]]   =  3] 

然而,我并不建议尝试以这种方式可视化NumPy数组——至少我从来没有这样做过。我几乎只关注形状。

(2,) * (2,2)
   \   /
    \ /
    (2,)

你只需想想“中间”轴被点着,然后从结果形状中消失。


np.sum(arr, axis=0)告诉NumPy对第0轴中的元素进行求和。如果arr是二维的,则第0个轴是行。例如,如果arr看起来像这样:

In [1]: arr = np.arange(6).reshape(2,3); arr
Out[1]: 
array([[0, 1, 2],
       [3, 4, 5]])

然后np.sum(arr, axis=0)将沿着列求和,从而消除第0个轴(即行)。

In [2]: np.sum(arr, axis=0)
Out[2]: array([3, 5, 7])

3是0+3的结果,5等于1+4,7等于2+5。

注意arr有形状(2,3),求和后,第0轴被移除,因此结果是形状(3,)。第0轴的长度为2,每个和由添加这2个元素组成。形状(2,3)“变成”(3,)。你可以提前知道结果形状!这有助于引导你的思维。

要测试您的理解,请考虑np.sum(arr, axis=1)。现在1轴被移除。结果的形状是(2,),结果中的元素是3个值的和。

In [3]: np.sum(arr, axis=1)
Out[3]: array([ 3, 12])

3等于0+1+2,12等于3+4+5。


所以我们看到对一个轴进行求和可以从结果中消除这个轴。这与np.dot有关,因为np.dot执行的计算是产品的之和。由于np.dot沿某些轴执行求和操作,因此将从结果中删除该轴。这就是为什么对形状(2,)和(2,2)的数组应用np.dot会得到形状(2,)的数组。两个数组中的前2个相加,消除了这两个数组,只剩下第二个数组中的第二个2。

相关问题 更多 >