2016-09-26 1 views
1

Давайте упрощенный пример, где у меня есть массив данныхинтуитивный способ использовать 3D Numpy массивы

A = np.asarray([[1,3], [2,4]]) 

И эти данные должны быть преобразованы в другую форму после простого преобразования:

Q = np.asarray([[-0.5,1], [1,0.5]]) 
B = np.dot(Q,np.dot(A,Q.T)) 
print B 

Теперь предположим, что у меня есть набор данных, который принимает форму массива 2d для нескольких временных шагов. Для простоты снова предположим, что эти данные всего A скопированы на 3 временных шага. Мы можем представить эти данные как 3d-массив с размерами (2,2,N), где N =3 в этом случае. Третье измерение представляет собой временной индекс данных. Теперь было бы естественным требовать простой способ преобразования данных, как указано выше, но для каждого временного шага, путем интуитивного умножения трехмерных массивов, однако я только смог сделать следующую работу, которая не интуитивно понятна:

# Create the 3d data array 
AA = np.tile(A,(3,1,1)) # shape (3,2,2) 
BB = np.dot(Q,np.dot(AA,Q.T)) 

print np.all(BB[:,0,:] == B) # Returns true 

так с помощью этого метода я не переделать Q массив, чтобы сделать его работу, но теперь второе измерение действует как показатель «времени», который немного счетчик интуитивно, так как в AA это был первый размер, который обозначал время ... В идеале я хотел бы получить решение, в котором оба AA и BB имеют индекс времени в третьем измерении!

Edit:

С dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m]) от Docs Я интересно, если я пытаюсь достичь не возможно? Кажется странным, поскольку это должно быть относительно распространенным явлением, которое может быть желательным ...

+1

С '' numpy' 1-я ось - самая внешняя, поэтому форма '(N, 2,2)' может быть более естественной, например, с помощью команды np.array ([A1, A2, A3]) ', объединение трех массивов 2x2. Но такой поворот 'dot' может быть выполнен для работы с (2, N, 2) или (2,2, N). 'dot' обычно работает с последним тусклым и вторым до последнего тусклого. 'np.matmul' и' np.einsum' являются альтернативами. – hpaulj

+0

@hpaulj Итак, как бы я мог выполнить умножение массива в этом случае? – Jack

ответ

1
In [91]: A=np.array([[1,3],[2,4]]) 
In [92]: Q=np.array([[-.5,1],[1,.5]]) 
In [93]: B=np.dot(Q,np.dot(A,Q.T)) 
In [94]: B 
Out[94]: 
array([[ 1.75, 2.75], 
     [ 4. , 4.5 ]]) 

Такой же расчет с einsum:

In [95]: np.einsum('ij,jk,kl',Q,A,Q) 
Out[95]: 
array([[ 1.75, 2.75], 
     [ 4. , 4.5 ]]) 

Если я сделать несколько копий A - на новом 1-й размерности:

In [96]: AA = np.array([A,A,A]) 
In [97]: AA.shape 
Out[97]: (3, 2, 2) 
... 
In [99]: BB=np.einsum('ij,pjk,kl->pil',Q,AA,Q) 
In [100]: BB 
Out[100]: 
array([[[ 1.75, 2.75], 
     [ 4. , 4.5 ]], 

     [[ 1.75, 2.75], 
     [ 4. , 4.5 ]], 

     [[ 1.75, 2.75], 
     [ 4. , 4.5 ]]]) 

BB имеет (3,2,2) форму.

matmul довольно новый (оператор @) позволяет мне делать то же самое

In [102]: [email protected]@Q.T 
Out[102]: 
array([[ 1.75, 2.75], 
     [ 4. , 4.5 ]]) 
In [103]: [email protected]@Q.T 
Out[103]: 
array([[[ 1.75, 2.75], 
     [ 4. , 4.5 ]], 

     [[ 1.75, 2.75], 
     [ 4. , 4.5 ]], 

     [[ 1.75, 2.75], 
     [ 4. , 4.5 ]]]) 

С einsum это так же легко работать с последним измерением:

In [104]: AA3=np.stack([A,A,A],-1) # newish np.stack 
In [105]: AA3.shape 
Out[105]: (2, 2, 3) 
In [106]: np.einsum('ij,jkp,kl->ilp',Q,AA3,Q) 
Out[106]: 
array([[[ 1.75, 1.75, 1.75], 
     [ 2.75, 2.75, 2.75]], 

     [[ 4. , 4. , 4. ], 
     [ 4.5 , 4.5 , 4.5 ]]]) 
In [107]: _.shape 
Out[107]: (2, 2, 3) 
+0

Очень приятно - я просто экспериментировал с 'einsum'! Похоже, что это очень общий гибкий способ выполнения суммирования. У вас есть какие-либо знания с головы, как он сравнивает производительность с точкой? – Jack

+0

Также еще одно: ваше первое решение слегка неверно, оно должно быть «BB = np.einsum (« ij, pjk, lk-> pil », Q, AA, Q)», хотя в этом случае он не обозначает потому что 'Q' является симметричным! – Jack

+0

Правда; Я мысленно заметил, что 'Q.T' требовал переключения индекса, но не проверял его. – hpaulj

0

Я не уверен, что согласен с вашим определением «интуитивный» - мне представляется более естественным представлять индекс времени первым размерность массива. Поскольку массивы numpy row-major по умолчанию, это упорядочение размеров даст вам locality of reference для каждой подматрицы 2x2, поскольку все элементы будут находиться в соседних адресах памяти.

Тем не менее, можно адаптировать пример работы для (2, 2, N) массива с помощью np.matmul и транспонирования каждой из промежуточных массивов:

CC = np.repeat(A[..., None], 3, -1) # shape (2, 2, 3) 
DD = np.matmul(Q.T, np.matmul(CC.T, Q)).T 

print(DD.shape) 
# (2, 2, 3) 

print(repr(DD)) 
# array([[[ 1.75, 1.75, 1.75], 
#   [ 2.75, 2.75, 2.75]], 

#  [[ 4. , 4. , 4. ], 
#   [ 4.5 , 4.5 , 4.5 ]]]) 

В Python 3.5+ вы можете сделать это еще более компактный, используя @ operator как сокращение для np.matmul:

DD = (Q.T @ (CC.T @ Q)).T 
Смежные вопросы