Что такое интуитивное объяснение np.unravel_index?

Довольно многое, что говорится в названии. Я прочитал документацию, и я играл с этой функцией какое-то время, но я не могу различить, что такое физическое проявление этого преобразования.

Ответ 1

Начнем с примера в документации.

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

Если мы откроем эти индексы обратно в исходные позиции в массиве dim (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)] если массив не сплющен. Другими словами, функция переводит индексы в массиве flatten обратно в его невыпущенную версию.

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

Ответ 2

Компьютерная память адресуется линейно. Каждой ячейке памяти соответствует номер. Блок памяти может быть адресован в терминах базы, которая является адресом памяти ее первого элемента и индексом элемента. Например, если базовый адрес равен 10 000:

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

Чтобы хранить многомерные блоки, их геометрия должна каким-то образом быть встроена в линейную память. В C и NumPy это выполняется по очереди. 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. Поскольку это зависит от размеров блока, они также должны быть переданы. Итак, в нашем примере мы можем вернуть исходный 2D-индекс (1, 2) из линейного индекса 6:

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

Примечание. Вышеупомянутые лозунги над несколькими деталями. 1) При переводе индекса элемента на адрес памяти также необходимо учитывать размер элемента. Например, целое число обычно имеет 4 или 8 байтов. Итак, в последнем случае адрес памяти для элемента i будет base + 8 xi. 2). NumPy немного более гибкий, чем предлагается. При желании он может организовывать столбцы по столбцам ND. Он может даже обрабатывать данные, которые не смежны в памяти, но, например, оставляют пробелы и т.д.

Ответ 3

По содержанию это не отличается от двух других ответов, но может быть более интуитивным. Если у вас есть двумерная матрица или массив, вы можете ссылаться на нее по-разному. Вы можете набрать (row, col), чтобы получить значение в (row, col), или вы можете дать каждой ячейке индекс из одного числа. unravel_index просто переводит между этими двумя способами ссылки на значения в матрице.

enter image description here

Это может быть расширено до размеров больше 2. Вы также должны знать о np.ravel_multi_index(), который выполняет обратное преобразование. Обратите внимание, что для этого требуется индекс и форма массива.

Я также вижу, что у меня есть две десятки в матрице индекса - упс.

Ответ 4

Я могу объяснить это на очень простом примере. Это для 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 массив)
  • Работает только с индексами, т.е. и вход, и выход являются индексами