Изменение ранга> 2 numpy массивов в Python - PullRequest
0 голосов
/ 06 августа 2020

Я работаю с массивами numpy как тензоры ранга> 2 в Python и пытаюсь преобразовать такой тензор в матрицу, то есть массив ранга 2. Стандартная функция ndarray.reshape() для этого не работает, потому что мне нужно сгруппировать индексы моего тензора определенным образом. Я имею в виду следующее: скажем, я начинаю с тензора ранга 3, T_ijk. Я пытаюсь найти функцию, которая будет выводить, например, тензор 2-го ранга T_ (j) (ik), т.е. для этого примера желаемый ввод / вывод будет

[Input:]      T=np.array([[[1 2]
                           [3 4]]
                          [[5 6]
                           [7 8]]])

[Output:]     array([[1, 2, 5, 6],
                     [3, 4, 7, 8]])

Кроме того, друг предложил для меня этот тензорный поток может иметь подобные функции, но я никогда не использовал его. Есть ли у кого-нибудь здесь понимание?

Ответы [ 2 ]

0 голосов
/ 06 августа 2020
In [216]: arr = np.arange(1,9).reshape(2,2,2)                                                        
In [217]: arr                                                                                        
Out[217]: 
array([[[1, 2],
        [3, 4]],

       [[5, 6],
        [7, 8]]])

reshape сохраняет элементы в исходном [1,2,3,4,5 ...] порядке

In [218]: arr.reshape(2,4)                                                                           
Out[218]: 
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])

Определить правильный порядок транспонирования может быть непросто. Иногда я просто пробую несколько вещей. Здесь я отмечаю, что вы хотите сохранить порядок в последнем измерении, поэтому все, что нам нужно сделать, это поменять местами первые 2 оси:

In [219]: arr.transpose(1,0,2)                                                                       
Out[219]: 
array([[[1, 2],
        [5, 6]],

       [[3, 4],
        [7, 8]]])

теперь изменение формы делает то, что мы хотим:

In [220]: arr.transpose(1,0,2).reshape(2,4)                                                          
Out[220]: 
array([[1, 2, 5, 6],
       [3, 4, 7, 8]])

Эта последовательность, насколько мне известно, лучший "встроенный" подход.

Вы прокомментируете:

если бы я хотел преобразовать T_ijklmno в T_ (ilo) (jmnk) необходимость выяснить, какие оси переключить и как изменить форму, вероятно, выйдет из-под контроля ... поэтому я ищу встроенное решение

Обозначение T_.... напоминает мне, что мы могли бы использовать einsum для транспонирования:

In [221]: np.einsum('ijk->jik',arr)                                                                  
Out[221]: 
array([[[1, 2],
        [5, 6]],

       [[3, 4],
        [7, 8]]])

Итак, T_ijklmno to T_(ilo)(jmnk) может стать

np.einsum('ijklmno->ilojmnk',T).reshape(I*L*O, J*M*N*K)
T.transpose(0,3,6,1,4,5,2).reshape(...)

(я написал это, просто взглянув на ваше T выражение )

Существует так много способов транспонирования и изменения формы массива с семью измерениями, что нет смысла придумывать что-либо более общее, чем существующие методы - транспонирование, свопакси, einsum. Простое определение размеров, как при использовании «ijk ...», является самой сложной частью проблемы.

0 голосов
/ 06 августа 2020

Попробуйте это -

k = 1
m = 2
i = 5
j = 5
l = 2

#dummy T_ijklm
T = np.array(range(100)).reshape(k,m,i,j,l)
T_new = T.reshape(k*m,i*j*l)

print('Original T:',T.shape)
print('New T:',T_new.shape)

#(km)(ijl) = 2*50

Original T: (1, 2, 5, 5, 2)
New T: (2, 50)

Новый тензор теперь имеет ранг 2

array([[ 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, 42, 43, 44, 45, 46, 47,
        48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
        66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
        82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
        98, 99]])
...