什么是np.unravel_index的直观解释?

时间:2018-01-07 09:00:20

标签: python numpy indexing

相当于标题所说的内容。我已经阅读了文档,并且我已经使用了该函数一段时间了,但我无法分辨出这种转换的物理表现形式。

5 个答案:

答案 0 :(得分:22)

计算机内存线性处理。每个存储器单元对应于一个数字。可以根据base(其第一个元素的内存地址)和项索引来寻址内存块。例如,假设基址是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的块中,2D索引(1, 2)将对应于6的线性索引1 x 4 + 2

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

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

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

答案 1 :(得分:20)

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

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

首先,(7,6)指定我们想要将索引转换回的目标数组的维度。其次,如果数组被展平,[22, 41, 37]是此数组上的一些索引。如果一个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, 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

答案 2 :(得分:11)

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

enter image description here

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

我也看到我在索引矩阵中有两个10 - 哎呀。

答案 3 :(得分:-1)

我可以用一个非常简单的例子来解释它。这适用于 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)

Output: idx = (array([1, 3, 3], dtype=int64), array([1, 0, 1], dtype=int64))
i.e,  x = [1, 3, 3]
      y = [1, 0, 1]

它返回索引的x,y [因为X是二维的]


如果您将 ravel_multi_index 应用于获得的IDx

idx_flat = np.ravel_multi_index(idx, X.shape)

Output: idx_flat = array([3, 6, 7], dtype=int64)
idx_flat is a linear index of X where value 3 presents

从上面的示例中,我们可以了解

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

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

x_linear = X.ravel()
Output: 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)
Output: (array([1, 3, 3], dtype=int64), array([1, 0, 1], dtype=int64))

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

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

答案 4 :(得分:-1)

这仅适用于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)没有任何意义,只是将未定义的线性索引可以通过该函数传递的大小设置上限。