Под numpy я хочу выполнить «обычное» умножение матриц следующим образом:
С=А*Б
где
A — матрица «2D-типа», но каждый элемент матрицы имеет форму (1,5).
и
B — вектор «1D-типа», но каждый элемент векторного элемента имеет форму (20,5).
Результат
C должен быть вектором «1D-типа», но каждый элемент векторного элемента снова имеет форму (20,5).
Я попытался создать элементы C1 и C2 из C вручную:
>>> A.shape
(2, 2, 1, 5)
>>> B.shape
(2, 20, 5)
>>> C0 = A[0,0]*B[0]+A[0,1]*B[1]
>>> C0.shape
(20, 5)
>>> C1 = A[1,0]*B[0]+A[1,1]*B[1]
>>> C1.shape
(20, 5)
>>>
Трансляция (1,5) из A с (20,5) из B работает как положено.
Однако мне не удалось выяснить, как это можно записать как умножение матриц:
C = np.matmul(A, B)
Конечно, это не работает, потому что numpy не может знать, какие индексы я хочу суммировать. Но я предполагаю, что должно существовать какое-то простое «нумерпитоническое» решение...
Также создайте минимальный воспроизводимый пример с фактическими ожидаемыми значениями.
В любом случае решение, скорее всего, будет включать np.einsum






Вы можете использовать einsum:
C = np.einsum('ij...,j...->i...', A, B)
Это сжатие второго измерения А с первым измерением Б. Остальные измерения переносятся вместе с нами.
Пример в сеансе ipython:
In [114]: rng = np.random.default_rng(8779780912870439733)
In [115]: A = rng.integers(0, 5, size=(2, 2, 1, 5))
In [116]: B = rng.integers(0, 5, size=(2, 20, 5))
In [117]: C = np.einsum('ij...,j...->i...', A, B)
In [118]: C.shape
Out[118]: (2, 20, 5)
In [119]: C0 = A[0,0]*B[0]+A[0,1]*B[1]
In [120]: C1 = A[1,0]*B[0]+A[1,1]*B[1]
In [121]: np.all(C[0] == C0)
Out[121]: True
In [122]: np.all(C[1] == C1)
Out[122]: True
Это сработало немедленно. Спасибо.
Вы можете напрямую умножить A и B и суммировать второе измерение:
C = (A*B).sum(1)
# or
C = np.multiply(A, B).sum(1)
C.shape
# (2, 20, 5)
Это дает тот же результат, что и ваши ручные вычисления:
np.allclose(C[0], C0)
# True
np.allclose(C[1], C1)
# True
Это работает, поскольку numpy выравнивает массивы справа:
A (2, 2, 1, 5)
| | | | # multiplication
B (2, 20, 5)
B (1, 2, 20, 5) # broadcasting
| | | # sum(1)
C (2, 20, 5)
Обратите внимание, что это эквивалентно скалярному произведению, используя:
C = np.matmul(B[:, None].T, A.T).T[:, 0]
# or
C = (B[:, None][email protected]).T[:, 0]
Ваш matmul можно объяснить так: B меняется с (2,20,5) на (2,1,20,5) на (5,20,1,2). A.T это (5,1,2,2). Затем dot на последних 2 измерениях сделать (1,2), и транслировать на ведущие 2, чтобы сделать (5,20,1,2). Транспонируйте и уберите 1, чтобы получить (2,20,5).
Точно, спасибо за подробное описание @hpaulj, я показал эту альтернативу, чтобы продемонстрировать, что matmul можно использовать, хотя здесь это не совсем практично.
A*BНЕ является «обычным» матричным умножением (которое будетA @ BилиA.dot(B)), это поэлементное умножение. Чего вы на самом деле хотите?