【问题标题】:What is an intuitive explanation of np.unravel_index?np.unravel_index 的直观解释是什么?
【发布时间】:2018-06-16 13:44:21
【问题描述】:

和标题说的差不多。我已经阅读了文档并且我已经使用了一段时间的功能,但我无法辨别这种转换的物理表现是什么。

【问题讨论】:

  • 根据形成这些轴的 nd 网格的形状,将线性索引转换为沿每个轴的索引。 Here's some explanation 换了np.ravel_multi_index

标签: python numpy indexing numpy-ndarray tensor


【解决方案1】:

计算机内存是线性寻址的。每个存储单元对应一个数字。可以根据基址(即其第一个元素的内存地址)和项目索引来寻址内存块。例如,假设基地址为 10,000:

item index      0       1       2       3
memory address  10,000  10,001  10,002  10,003

要存储多维块,它们的几何形状必须以某种方式适应线性内存。在CNumPy 中,这是逐行完成的。一个 2D 示例是:

  | 0      1      2      3
--+------------------------
0 | 0      1      2      3
1 | 4      5      6      7
2 | 8      9     10     11

因此,例如,在这个 3×4 块中,二维索引 (1, 2) 将对应于线性索引 6,即 1 x 4 + 2

unravel_index 则相反。给定一个线性索引,它计算相应的ND 索引。由于这取决于块尺寸,因此也必须通过这些尺寸。因此,在我们的示例中,我们可以从线性索引 6 中获取原始二维索引 (1, 2)

>>> np.unravel_index(6, (3, 4))
(1, 2)

注意:以上内容掩盖了一些细节。 1)将项目索引转换为内存地址还必须考虑项目大小。例如,一个整数通常有 4 或 8 个字节。因此,在后一种情况下,项目i 的内存地址将是base + 8 x i。 2)。 NumPy 比建议的要灵活一些。如果需要,它可以逐列组织ND 数据。它甚至可以处理内存中不连续但例如留下间隙等的数据。


额外阅读:internal memory layout of an ndarray

【讨论】:

【解决方案2】:

我可以用非常简单的例子来解释它。这适用于 np.ravel_multi_index 以及 np.unravel_index

>>> X = np.array([[4,  2],
                  [9,  3],
                  [8,  5],
                  [3,  3],
                  [5,  6]])
>>> X.shape
(5, 2)

找出所有值 3 在 X 中的位置:

>>> idx = np.where(X==3)
>>> idx
(array([1, 3, 3], dtype=int64), array([1, 0, 1], dtype=int64))

x = [1,3,3] , y = [1,0,1] 它返回索引的 x、y(因为 X 是二维的)。


如果你申请ravel_multi_indexidx获得:

>>> idx_flat = np.ravel_multi_index(idx, X.shape)
>>> idx_flat
array([3, 6, 7], dtype=int64)

idx_flat 是 X 的线性索引,其中值 3。

从上面的例子我们可以理解:

  • ravel_multi_index 将多维索引(nd 数组)转换为单维索引(线性数组)
  • 它仅适用于索引,即输入和输出都是索引

结果索引将是X.ravel() 的直接索引。您可以在下面x_linear进行验证:

>>> x_linear = X.ravel()
>>> x_linear
array([4, 2, 9, 3, 8, 5, 3, 3, 5, 6])

unravel_index 非常简单,只是上面的相反 (np.ravel_multi_index)

>>> idx = np.unravel_index(idx_flat , X.shape)
>>> idx
(array([1, 3, 3], dtype=int64), array([1, 0, 1], dtype=int64))

idx = np.where(X==3)相同

  • unravel_index 将单维索引(线性数组)转换为多维索引(nd 数组)
  • 它仅适用于索引,即输入和输出都是索引

【讨论】:

  • 我喜欢 ravel 和 unravel_index 的具体示例。谢谢!
【解决方案3】:

这仅适用于2D情况,但是这种情况下np.unravel_index函数返回的两个坐标相当于分别做地板除法和取模函数。

for j in range(1,1000):
    for i in range(j):
        assert(np.unravel_index(i,(987654321,j))==(i//j,i%j))

形状数组的第一个元素(即 987654321)是没有意义的,除了设置一个未散列线性索引可以通过函数的大小的上限。

【讨论】:

    【解决方案4】:

    这在内容上与其他两个答案没有什么不同,但可能更直观。如果你有一个二维矩阵或数组,你可以用不同的方式引用它。您可以键入 (row, col) 以获取 (row, col) 处的值,或者您可以为每个单元格指定一个数字索引。 unravel_index 只是在这两种引用矩阵值的方式之间进行转换。

    这可以扩展到大于 2 的维度。您还应该知道 np.ravel_multi_index(),它执行反向转换。请注意,它需要 (row, col) 和数组的形状。

    我还看到索引矩阵中有两个 10 ——哎呀。

    【讨论】:

    • 就直觉而言,这实际上正是我所寻找的,谢谢。请问,这样做的动机仅仅是因为它使计算的计算复杂性降低/更容易存储在内存中吗?
    • 我想有很多原因/应用。我使用它的一种方法是:我有一个单宽度像素的骨架,我需要沿着它走并返回我走过的地方的坐标。对我来说,在“索引”空间而不是“行,列”空间工作要简单得多,因为它将操作数量减少了一半。例如,如果您想查看是否已经走到 (2,1),则必须先检查 2,然后再检查 1。使用索引时,我只检查“7”。基本示例,但它确实简化了事情。重申一下,还有许多其他应用程序:)
    【解决方案5】:

    我们将从文档中的示例开始。

    >>> np.unravel_index([22, 41, 37], (7,6))
    (array([3, 6, 6]), array([4, 5, 1]))
    

    首先,(7,6) 指定我们要将索引转换回的目标数组的维度。其次,[22, 41, 37] 是这个数组上的一些索引如果数组被展平。如果 7 x 6 数组被展平,它的索引看起来像

    [ 0,  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, 26, 27, 28, 29, 30, 31, 32, 33,
       34, 35, 36, *37*, 38, 39, 40, *41*]
    

    如果我们将这些索引展开回它们在昏暗(7, 6) 数组中的原始位置,它将是

          [[ 0,   1,   2,   3,   4,   5],
           [ 6,   7,   8,   9,  10,  11],
           [12,  13,  14,  15,  16,  17],
           [18,  19,  20,  21, *22*, 23],  <- (3, 4)
           [24,  25,  26,  27,  28,  29],
           [30,  31,  32,  33,  34,  35],
           [36, *37*, 38,  39,  40, *41*]]
               (6, 1)               (6,5)
    

    unravel_index 函数的返回值告诉您如果数组未展平,[22,41,37] 的索引应该是什么。如果数组没有展平,这些索引应该是[(3, 4), (6, 5), (6,1)]。换句话说,该函数将展平数组中的索引转换回其未展平的版本。

    https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.unravel_index.html

    【讨论】:

    • 坦率地说,我认为您的示例中的输出应该是 [(3, 4), (6, 5), (6,1)] 而不是文档中的转置,以便保持一致np.unravel_index(1621, (6,7,8,9)) 的输出为 (3, 1, 4, 1)
    猜你喜欢
    • 2012-05-12
    • 2015-04-20
    • 1970-01-01
    • 2012-08-02
    • 2021-03-18
    • 2013-07-04
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    相关资源
    最近更新 更多