Создание нетривиального представления массива numpy - PullRequest
0 голосов
/ 24 мая 2018

TL; DR:

Я ищу способ получить нетривиальный и, в частности, неконкурентный вид на numpy ndarray.

Например, дано 1Dndarray, x = np.array([1, 2, 3, 4]), есть ли способ получить нетривиальный просмотр его, например, np.array([2, 4, 3, 1])?

Более длинная версия

Контекст вопросаследующее: у меня есть 4D ndarray формы (U, V, S, T), который я хотел бы изменить в 2D ndarray формы (U*S, V*T) нетривиальным способом, то есть простой np.reshape() не справляется с задачей, так как у меня естьИмеется в виду более сложная схема индексации, при которой измененный массив не будет скачком в памяти.Массивы в моем случае довольно большие, и я хотел бы получить представление, а не копию массива.

Пример

Учитывая массив x(u, v, s, t) формы (2, 2, 2, 2):

x = np.array([[[[1, 1], [1, 1]],[[2, 2], [2, 2]]],
              [[[3, 3], [3, 3]], [[4, 4], [4, 4]]]])

Я хотел бы получить представление z(a, b) массива:

np.array([[1, 1, 2, 2],
          [1, 1, 2, 2],
          [3, 3, 4, 4],
          [3, 3, 4, 4]])

Это соответствует схеме индексации a = u * S + s и b = v * T + t, где в данном случае S = 2 = T.

То, что я пробовал

  1. Различные подходы с использованием np.reshape или даже as_strided.Выполнение стандартного изменения формы не изменит порядок элементов, как они появляются в памяти.Я попытался поиграть с order='F' и немного транспонировать, но понятия не имел, что дало мне правильный результат.

  2. Так как я знаю схему индексации, я попытался оперировать на плоском видемассива, используя np.ravel().Моя идея состояла в том, чтобы создать массив индексов, следуя желаемой схеме индексации, и применить его к представлению плоского массива, но, к сожалению, причудливое / расширенное индексирование дает копию массива, а не представление.

Вопрос

Можно ли как-нибудь получить представление индексации, которое я ищу?

В принципе, я думаю, что это должно быть возможно, так как, например, ndarray.sort() выполняет нетривиальную индексацию массива на месте.С другой стороны, это, вероятно, реализовано в C / C ++, так что это может быть даже невозможно в чистом Python?

1 Ответ

0 голосов
/ 24 мая 2018

Давайте рассмотрим основы массива - он имеет плоский буфер данных, shape, strides и dtype.Эти три атрибута используются для view элементов буфера данных особым образом, будь то простая 1d последовательность, 2d или более высокие измерения.

Истина view, чем использование того же буфера данных, но применяет к нему другую форму, шаг или dtype.

Чтобы получить [2, 4, 3, 1] из [1,2,3,4], необходимо начать с 2, прыгнуть вперед 2, затем перейти назад к 1 и вперед 2. Это нерегулярный шаблон, который может быть представлен как strides.

arr[1::2] дает [2,4], а arr[0::2] дает [1,3].

(U, V, S, T) до (U*S, V*T) требуется транспонирование в (U, S, V, T) с последующим изменением формы

arr.transpose(0,2,1,3).reshape(U*S, V*T)

Для этого потребуется копия, никак не обойтись.

In [227]: arr = np.arange(2*3*4*5).reshape(2,3,4,5)
In [230]: arr1 = arr.transpose(0,2,1,3).reshape(2*4, 3*5)
In [231]: arr1.shape
Out[231]: (8, 15)
In [232]: arr1
Out[232]: 
array([[  0,   1,   2,   3,   4,  20,  21,  22,  23,  24,  40,  41,  42,
         43,  44],
       [  5,   6,   7,   8,   9,  25,  26,  27,  28,  29,  45,  46,  47,
         48,  49],
       ....)

Или с вашим x

In [234]: x1 = x.transpose(0,2,1,3).reshape(4,4)
In [235]: x1
Out[235]: 
array([[1, 1, 2, 2],
       [1, 1, 2, 2],
       [3, 3, 4, 4],
       [3, 3, 4, 4]])

Обратите внимание, что элементы расположены в другом порядке:

In [254]: x.ravel()
Out[254]: array([1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4])
In [255]: x1.ravel()
Out[255]: array([1, 1, 2, 2, 1, 1, 2, 2, 3, 3, 4, 4, 3, 3, 4, 4])

ndarray.sort на месте и меняет порядок байтов в буфере данных.Он работает на низком уровне, к которому у нас нет доступа.Это не view исходного массива.

...