【问题标题】:Explaining the differences between dim, shape, rank, dimension and axis in numpy解释numpy中dim、shape、rank、dimension和axis之间的区别
【发布时间】:2014-04-02 14:55:05
【问题描述】:

总的来说,我是 python 和 numpy 的新手。我阅读了几个教程,但仍然对昏暗、等级、形状、轴和尺寸的差异感到困惑。我的思绪似乎停留在矩阵表示上。所以如果你说 A 是一个看起来像这样的矩阵:

A = 

1 2 3
4 5 6

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

谁能向我解释一下什么是 N 维数组、什么是形状、什么是轴以及它与 dot() 函数的文档有何关系?如果解释可视化这些想法,那就太好了。

【问题讨论】:

  • 你熟悉矩阵乘法吗?
  • @unutbu 当然!但是如果你做 dot(V,M) 并将其视为矩阵乘法,那么这是错误的,因为 V 是 N:1 而 M 是 N:N。但是 dot(M,V) 是正确的。但是做 dot(V,M) 仍然会产生结果!!!
  • @AlexTwain 那是不可能的。查看我的答案,或显示您的代码。
  • This answer 介绍了形状。

标签: python arrays numpy matrix


【解决方案1】:

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

例如,这是一个 3-d 数组:

>>> 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

轴大致是维度的同义词;它用于广播操作:

>>> 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]])

老实说,我发现“等级”的这个定义令人困惑,因为它既不匹配属性名称 ndim 也不匹配 linear algebra definition of rank

现在关于np.dot,你要明白的是,在 NumPy 中表示向量有三种方式:一维数组、形状为(n, 1) 的列向量或形状为(1, n) 的行向量。 (实际上,还有更多方法,例如(1, n, 1) 形数组,但这些非常少见。)np.dot 当两个参数都是一维时执行向量乘法,当一个参数是一维时执行矩阵向量乘法另一个是二维的,否则它执行(广义)矩阵乘法:

>>> 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 对象视为标量。

【讨论】:

  • 我不明白轴上求和的概念。它是如何完成的?你能详细说明一下吗?
  • @AlexTwain:用矩阵来解释更容易。让A = array([[1, 2, 3], [4, 5, 6]])。然后A.sum(axis=0) == array([5, 7, 9]),即每一列的总和,而A.sum(axis=1) == array([ 6, 15]),每一行的总和。
  • To be honest, I find this definition of "rank" confusing 这就是为什么 rank 被弃用并被 ndim 取代的原因。 docs.scipy.org/doc/numpy/release.html#rank-function
【解决方案2】:

np.dot 是矩阵乘法的推广。 在常规矩阵乘法中,一个 (N,M) 形矩阵与一个 (M,P) 形矩阵相乘得到一个 (N,P) 形矩阵。最终的形状可以被认为是通过将两个形状挤压在一起((N,M,M,P))然后删除中间数字M(以产生(N,P))来形成的。这是np.dot 在推广到更高维数组时保留的属性。

当文档说,

"对于 N 维,它是 a 的最后一个轴上的和积和 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 的第一个轴)相乘和相加,只剩下@987654337 的最后一个轴@。

如果你想可视化这个: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 对 arr 中的元素求和 消除 第 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 执行的计算是产品的sum。由于np.dot 沿某些轴执行求和运算,因此从结果中删除了该轴。这就是为什么将np.dot 应用于形状为 (2,) 和 (2,2) 的数组会产生一个形状为 (2,) 的数组。将两个数组中的第一个 2 相加,消除两者,只留下第二个数组中的第二个 2。

【讨论】:

  • 我的问题正是轴的想法。我不明白像 sum(m, axes=0) 或 axes=1 这样的轴是什么意思。同样在您的示例中,我认为乘以 (2,) * (2,2) 应该导致 (2,2) 因为您从最右边和最左边获取维度。如 ((N,M,M,P)) --- 变成 (N,P)
  • 非常感谢,但我仍然缺少的是在消除轴时可视化 arr 会发生什么。假设您消除了 axis=0 那么 arr 的外观如何。与轴 = 1 相同。我无法在脑海中想象。
  • 我不确定我是否理解这个问题。 np.sum(arr, axis=0) 不影响 arr。它返回一个新数组,保持arr 不变。就可视化而言,请注意上面我描述“5 等于 1+4”之类的部分。在结果中查找 5,在 arr 中查找 1 和 4。你看到这是如何将同一列中的数字相加的吗?
  • 这正是我问的原因。我的想法将其可视化为在行而不是列上完成,因为它选择一列并且总和正在下降,即沿着行。我看不出这是如何消除第 0 维的。我不明白它是如何被淘汰的,也不明白它的意义。
  • 当你看到axis=0时,想想axis 0 correspond to "rows" in 2D。 (我们可以稍后考虑更高的维度)。这指定了总和的“运动方向”。迭代在行中向下移动。由于同一列中的所有数字都被聚合为一个数字,因此行轴消失(被消除),剩下的就是每一列的一个数字。所以结果少了一个轴。被淘汰的轴是代表行的轴,即0轴。因此,当您看到 axis=0 时,对形状的最终影响是 0-axis 被消除了。
【解决方案3】:

在你的情况下,

  1. A是一个二维数组,即矩阵,其shape为(2, 3)。来自numpy.matrix的文档字符串:

    矩阵是一种特殊的二维数组,通过运算保持其二维性质。

  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:NV.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 的一维数组,而形状 (N, 1) 表示具有 N 行 1 列的二维数组:

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 的文档字符串所说:

对于二维数组,它等价于矩阵乘法,对于一维数组 数组到向量的内积(没有复共轭)。

如果参数之一是向量,它也会执行向量矩阵乘法。说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]])

【讨论】:

  • 但是如果 V 是一维向量,那么 dot(V, M) 仍然有效!我认为我的困惑更多是关于 V 的形状(N,)。我不明白 (N,) 和 (N,1) 形状之间的区别,它与 dot() 文档有关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-01
  • 2017-07-23
  • 2023-01-02
  • 1970-01-01
  • 2013-07-04
  • 2011-10-02
  • 1970-01-01
相关资源
最近更新 更多