【问题标题】:numpy - column-wise and row-wise sums of a given 2d matrixnumpy - 给定二维矩阵的按列和按行求和
【发布时间】:2021-04-04 12:24:45
【问题描述】:

我有这个 numpy 矩阵(ndarray)。

    array([[ 1,  2,  3,  4,  5],
           [ 6,  7,  8,  9, 10],
           [11, 12, 13, 14, 15],
           [16, 17, 18, 19, 20],
           [21, 22, 23, 24, 25]])

我想计算列和行的总和。

我知道这是通过分别调用来完成的

np.sum(mat, axis=0)   ### column-wise sums

np.sum(mat, axis=1)   ### row-wise sums   

但我无法理解这两个调用。

为什么轴 0 会逐列给我总和?!
不应该反过来吗?

我认为行是轴 0,列是轴 1。

我在这里看到的行为看起来违反直觉
(但我确定没关系,我想我只是错过了一些重要的东西)。

我只是在这里寻找一些直观的解释。

提前致谢。

【问题讨论】:

  • This 可能会有所帮助。它也适用于负列 -1 和 -2
  • 我尝试在 3 个角度上添加直觉 - graphicalphysicallogical 解释 numpy 数组、轴和轴上的缩减。希望这些可以帮助各种 SO 用户建立直觉,包括 OP。
  • 对于 1d 或 3d,歧义更少。很容易看出 axis 是被淘汰的那个,而不是剩下的那个。

标签: python numpy


【解决方案1】:

直观地说,“轴 0”从上到下,“轴 1”从左到右。因此,当您沿“轴 0”求和时,得到列总和,沿“轴 1”求和时,得到行总和。

当您沿着“0 轴”前进时,行数会增加。当您沿着“轴 1”前进时,列数会增加。

【讨论】:

  • 有趣...好吧,让我再想一想。顺便说一句,我想如果我再多一个轴,我会完全迷路。
【解决方案2】:

让我们从一个一维的例子开始:

a, b, c, d, e = 0, 1, 2, 3, 4
arr = np.array([a, b, c, d, e])

如果你这样做,

arr.sum(0) 

输出

10

也就是数组元素的总和

a + b + c + d + e

现在在进行二维示例之前。让我们澄清一下,在 numpy 中,两个一维数组的总和是按元素完成的,例如:

a = np.array([1, 2, 3, 4, 5])
b = np.array([6, 7, 8, 9, 10])
print(a + b)

输出

[ 7  9 11 13 15]

现在,如果我们将初始变量更改为数组,而不是标量,以创建一个二维数组并求和

a = np.array([1, 2, 3, 4, 5])
b = np.array([6, 7, 8, 9, 10])
c = np.array([11, 12, 13, 14, 15])
d = np.array([16, 17, 18, 19, 20])
e = np.array([21, 22, 23, 24, 25])

arr = np.array([a, b, c, d, e])
print(arr.sum(0))

输出

[55 60 65 70 75]

输出与一维示例的相同,即数组元素的总和:

a + b + c + d + e

现在数组的元素是一维数组,并且应用了这些元素的总和。现在在解释结果之前,对于轴 = 1,让我们考虑一个替代轴 = 0 的表示法,基本上:

np.array([arr[0, :], arr[1, :], arr[2, :], arr[3, :], arr[4, :]]).sum(0) # [55 60 65 70 75]

也就是说,我们在所有其他不是第一个维度的索引中进行了完整切片。如果我们换成:

res = np.array([arr[:, 0], arr[:, 1], arr[:, 2], arr[:, 3], arr[:, 4]]).sum(0)
print(res)

输出

[ 15  40  65  90 115]

我们得到沿轴=1 求和的结果。所以总结起来,你总是对数组的元素求和。轴将指示这些元素是如何构造的

【讨论】:

    【解决方案3】:

    想想一维数组:

    mat=array([ 1,  2,  3,  4,  5])
    

    它的项目被mat[0], mat[1],等调用

    如果你这样做:

    np.sum(mat, axis=0) 
    

    它将返回 15

    在后台,它将所有项目与mat[0], mat[1], mat[2], mat[3], mat[4]相加

    表示第一个索引(axis=0)

    现在考虑一个二维数组:

    mat=array([[ 1,  2,  3,  4,  5],
               [ 6,  7,  8,  9, 10],
               [11, 12, 13, 14, 15],
               [16, 17, 18, 19, 20],
               [21, 22, 23, 24, 25]])
    

    当你要求时

    np.sum(mat, axis=0)
    

    它将再次根据第一个索引 (axis=0) 对所有项目求和,保持所有其余部分相同。这意味着

    mat[0][1], mat[1][1], mat[2][1], mat[3][1], mat[4][1]
    

    会给一笔钱

    mat[0][2], mat[1][2], mat[2][2], mat[3][2], mat[4][2]
    

    会给另一个,等等

    如果您考虑 3-D 数组,逻辑将是相同的。每个总和都将在同一轴(索引)上计算,保持所有其余部分相同。 axis=0 上的总和将由以下方式产生:

    mat[0][1][1],mat[1][1][1],mat[2][1][1],mat[3][1][1],mat[4][1][1]
    

    axis=2 上的总和将由:

    mat[2][3][0], mat[2][3][1], mat[2][3][2], mat[2][3][3], mat[2][3][4]
    

    我希望你明白其中的逻辑。为了让事情保持简单,请考虑轴 = 链索引中索引的位置,例如 7 维数组上的轴 = 3 将是:

    mat[0][0][0][this is our axis][0][0][0]
    

    【讨论】:

      【解决方案4】:

      对数组和轴的直觉

      我想在这里提供 3 种直觉。

      1. 图形(如何在视觉上想象它们)
      2. 物理(物理存储方式)
      3. 逻辑(如何在逻辑上使用它们)

      图形直觉

      将 numpy 数组视为 n 维对象。这个 n 维对象包含以下每个方向的元素。

      此表示中的

      是张量的方向。因此,2D 矩阵只有 2 个轴,而 4D 张量有 4 个轴。

      给定轴上的

      Sum 基本上可以认为是在该方向上的减少。想象一个 3D 张量被挤压成扁平的方式(一个 2D 张量)。轴告诉我们squashreduce 它在哪个方向。


      物理直觉

      Numpy 将其 ndarray 存储为连续的内存块。每个元素在前一个元素之后每隔 n 个字节按顺序存储。

      (图片引用自excellent SO post

      所以如果你的 3D 数组看起来像这样 -

      然后在内存中存储为 -

      当检索一个元素(或一个元素块)时,NumPy 计算它需要遍历多少个strides(字节)才能获取下一个元素in that direction/axis。因此,对于上面的示例,对于axis=2,它必须遍历 8 个字节(取决于datatype),但对于axis=1,它必须遍历8*4 字节,而axis=0 它需要8*8 字节。

      此表示中的

      基本上是给定stride 之后的next elements 系列。考虑以下数组 -

      print(X)
      print(X.strides)
      
      [[0 2 1 4 0 0 0]
       [5 0 0 0 0 0 0]
       [8 0 0 0 0 0 0]
       [0 0 0 0 0 0 0]
       [0 0 1 0 0 0 0]
       [0 0 0 1 0 0 0]]
      
      #Strides (bytes) required to traverse in each axis.
      (56, 8)
      

      在上面的数组中,任何元素 56 字节后的每个元素都是 axis=0 中的next element,任何元素 8 字节后的每个元素都在 axis=1 中。 (最后一个元素除外)

      Sum 或减少在这方面意味着取该跨步系列中的每个元素的总和。所以, sum over axis=0 意味着我需要求和 [0,5,8,0,0,0], [2,0,0,0,0,0], ... 而 sum over axis=1 意味着只求和 [0 2 1 4 0 0 0] , [5 0 0 0 0 0 0], ...


      逻辑直觉

      这种解释与element groupings 有关。 numpy 将其 ndarray 存储为 groups of groups of groups ... of elements。元素组合在一起并包含最后一个轴 (axis=-1)。然后在它们之上的另一个分组在它之前创建另一个轴(轴=-2)。最后一个最外面的组是axis=0。

      这些是 3 组,每组 2 组,每组 5 个元素。

      同样,NumPy 数组的形状也是由相同的决定的。

      1D_array = [1,2,3]
      2D_array = [[1,2,3]]
      3D_array = [[[1,2,3]]]
      ...
      
      此表示中的

      是存储元素的组。最外层为axis=0,最内层为axis=-1。

      Sum 或减少在这方面意味着我减少了该特定组或轴上的元素。因此,轴上的总和=-1 意味着我对最里面的组求和。考虑一个(6, 5, 8) 维张量。当我说我想要某个轴上的总和时,我想将位于 grouping / direction 中的元素减少为等于它们总和的单个值。

      所以,

      • np.sum(arr, axis=-1) 会将最里面的组(长度为 8)减少为单个值并返回 (6,5,1)(6,5)
      • np.sum(arr, axis=-2) 将减少位于第 1 轴(或第 -2 轴)方向的元素并将其减少为单个值,返回 (6,1,8)(6,8)
      • np.sum(arr, axis=0) 同样会将张量减少到 (1,5,8)(5,8)

      希望这 3 种直觉对任何试图了解轴和 NumPy 张量的一般工作原理以及如何建立直观理解以更好地使用它们的人有所帮助。

      【讨论】:

        猜你喜欢
        • 2018-10-13
        • 2020-06-20
        • 1970-01-01
        • 1970-01-01
        • 2017-09-30
        • 1970-01-01
        • 2018-04-24
        • 1970-01-01
        • 2015-06-10
        相关资源
        最近更新 更多