Суммирование по размеру широковещательного широковещания в numpy.einsum

В numpy у меня есть массив, который может быть либо 2-D, либо 3-D, и я хотел бы уменьшить его до 2-D, возведя квадрат каждого элемента. Поэтому я пробовал это, и он не работает:

A = np.random.rand(5, 3, 3) np.einsum('...ij,...ij->ij', A, A) 

Он возвращает эту ошибку:

 ValueError: output has more dimensions than subscripts given in einstein sum, but no '...' ellipsis provided to broadcast the extra dimensions. 

Я полагаю, что einsum не предполагает, что когда эллипсис уходит с правой стороны, я хочу суммировать размерность (ы) многоточия, если они существуют. Есть ли какой-то «изящный» способ (т. Е. Не проверяя количество измерений и используя оператор if), чтобы сказать ему, что я хочу сделать это для 3-D:

 A = np.random.rand(5, 3, 3) np.einsum('aij,aij->ij', A, A) 

и это для 2-D?

 A = np.random.rand(3, 3) np.einsum('ij,ij->ij', A, A) 

Иногда «элегантный» способ обработки переменных измерений состоит в использовании набора тестов if и скрыть их при вызове функции. Посмотрите пример на np.atleast_3d ; он имеет условие 4way if / else. Я бы рекомендовал его здесь, за исключением того, что добавляет дополнительное измерение в конце, а не начало. if предложения с использованием reshape не являются дорогостоящими (временными), поэтому не бойтесь их использовать. Даже если вы найдете магическую функцию, посмотрите на ее код; вы можете быть удивлены тем, что скрыто.


эллипсис используется для измерений, которые «идут вперед для езды», а не тех, где вам нужен определенный контроль. Здесь вы хотите суммировать исходный размер, поэтому вам нужно явно его индексировать:

 In [161]: np.einsum('i...,i...',A,A) Out[161]: array([[ 1.26942035, 1.32052776, 1.74118617], [ 1.59679765, 1.49331565, 2.04573002], [ 2.29027005, 1.48351522, 1.36679208]]) In [162]: np.einsum('aij,aij->ij',A,A) Out[162]: array([[ 1.26942035, 1.32052776, 1.74118617], [ 1.59679765, 1.49331565, 2.04573002], [ 2.29027005, 1.48351522, 1.36679208]]) 

Для массива 2d:

 In [165]: np.einsum('ij,ij->ij',A[0],A[0]) Out[165]: array([[ 0.20497776, 0.11632197, 0.65396968], [ 0.0529767 , 0.24723351, 0.27559647], [ 0.62806525, 0.33081124, 0.57070406]]) In [166]: A[0]*A[0] Out[166]: array([[ 0.20497776, 0.11632197, 0.65396968], [ 0.0529767 , 0.24723351, 0.27559647], [ 0.62806525, 0.33081124, 0.57070406]]) In [167]: In [167]: np.einsum('...,...',A[0],A[0]) Out[167]: array([[ 0.20497776, 0.11632197, 0.65396968], [ 0.0529767 , 0.24723351, 0.27559647], [ 0.62806525, 0.33081124, 0.57070406]]) 

Я не думаю, что вы можете обрабатывать оба случая одним выражением.

Другой способ получить первую сумму

 In [168]: (A*A).sum(axis=0) Out[168]: array([[ 1.26942035, 1.32052776, 1.74118617], [ 1.59679765, 1.49331565, 2.04573002], [ 2.29027005, 1.48351522, 1.36679208]]) 

Я внес исправление, исправляющее обработку многоточия, но это было пару лет назад. Так что детали не супер свежие в моем сознании. Как часть этого, я обратил конструкцию анализа синтаксического выражения (оригинал скомпилирован) и мог бы просмотреть этот код (или обратиться к нему), если нам нужен более окончательный ответ.


 In [172]: np.einsum('...ij,...ij->ij',A,A) --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-172-dfe39e268402> in <module>() ----> 1 np.einsum('...ij,...ij->ij',A,A) ValueError: output has more dimensions than subscripts given in einstein sum, but no '...' ellipsis provided to broadcast the extra dimensions. In [173]: np.einsum('...ij,...ij->...ij',A,A).shape Out[173]: (5, 3, 3) 

В сообщении об ошибке говорится, что он пытается передать ... размеры вывода, а не может – потому что на выходе отсутствуют размеры или ... Другими словами, он не выполняет суммирование по ... измерениям. Они передаются на выход без изменений (применяются правила вещания).