У меня есть $I$-индексированный массив $V = (V_i)_{i \in I}$ из (столбцов) векторов $V_i$, который я хочу поточечно умножить (вдоль $i \in I$) на матрицу $М$. Итак, я ищу «векторизованную» операцию, в которой отдельная операция представляет собой умножение матрицы на вектор; то есть
$W = (M V_i)_{i \in I}$
Есть ли простой способ сделать это?
numpy.dot
, к сожалению, предполагает, что $V$ — это матрица, а не $I$-индексированное семейство векторов, что явно не работает.
Итак, в основном я хочу «векторизировать» операцию
W = [np.dot(M, V[i]) for i in range(N)]
Рассматривая двумерный массив V как список (первый индекс) векторов-столбцов (второй индекс).
Если
shape(M) == (2, 2)
shape(V) == (N, 2)
Затем
shape(W) == (N, 2)
также, не могли бы вы предоставить некоторые входные массивы numpy и ожидаемый результат
В numpy
*
— это точечное или поэлементное умножение. @
- это умножение матриц - с суммой произведений на размеры определенной пары. np.dot
и np.matmul
задокументируйте, как связаны размеры. np.einsum
— это более общий инструмент для указания осей умножения и суммирования. Для *
умножения применяются правила broadcasting
(broadcasting
также используется со сложением и другими операциями.
Ваше использование вектора и матрицы может быть расплывчатым. numpy
имеет массивы, которые могут быть 1d или 2d (или 0d или 3d и т. д.). vector/matrix
не являются «родными» терминами numpy. Двумерную матрицу можно считать «матрицей», но «вектор» может иметь форму (n), или (n, 1), или (1, n).
Для наглядности часто помогает пример с итеративным вычислением.
Я имею в виду их в правильном (математическом) смысле, игнорируя стандартную оскорбительную терминологию, которая может быть расплывчатой (поэтому «векторизация» взята в кавычки).
Какой раздел математики? Часто плакаты ожидают, что numpy
будет вести себя так же, как линейная алгебра или MATLAB, с различием между векторами-строками и векторами-столбцами.
"индексированное семейство векторов"? numpy
может иметь массив (n,) 1d, форму (n,1), которая отображается как «вектор-столбец», и (1,n), который может быть описан как «вектор-строка». «Матрица» может иметь форма (n,m). Фигуру (n,m) также можно рассматривать как вектора в форме m
(n,1). Или форму n
(1,m)? Может быть, ваша семья имеет форму (m,n,1) matmul
из (m,1,n) и (n,1) производит (m,1,1) с суммой продуктов на общем n
.
То, что вы ищете, это ([email protected]).T
. обновил мой ответ на тот же
Основываясь на вашем повторяющемся примере, кажется, что это можно сделать с помощью точечного продукта с некоторыми транспонированием, чтобы соответствовать формам. Это то же самое, что и ([email protected]).T
, который является транспонированием M @ V.T.
# Step by step
((2,2) @ (5,2).T).T
-> ((2,2) @ (2,5)).T
-> (2,5).T
-> (5,2)
Код, подтверждающий это, выглядит следующим образом. Ваш итеративный вывод приводит к матрице W
, которая точно равна матрице solutions
.
M = np.random.random((2,2))
V = np.random.random((5,2))
# YOUR ITERATIVE SOLUTION (STACKED AS MATRIX)
W = np.stack([np.dot(M, V[i]) for i in range(5)])
print(W)
#array([[0.71663319, 0.84053871],
# [0.28626354, 0.36282745],
# [0.26865497, 0.55552295],
# [0.40165606, 0.10177711],
# [0.33950909, 0.54215385]])
# PROPOSED DOT PRODUCt
solution = ([email protected]).T #<---------------
print(solution)
#array([[0.71663319, 0.84053871],
# [0.28626354, 0.36282745],
# [0.26865497, 0.55552295],
# [0.40165606, 0.10177711],
# [0.33950909, 0.54215385]])
np.allclose(W, solution) #compare the 2 matrices
True
IIUC, вы ищете поточечное умножение матрицы M
и вектора V
(с трансляцией).
Матрица здесь (3,3)
, а V
— это массив с 4 векторами-столбцами, каждый из которых вы хотите независимо умножить на матрицу, соблюдая правила трансляции.
# Broadcasting Rules
M -> 3, 3
V -> 4, 1, 3 #V.T[:,None,:]
----------------
R -> 4, 3, 3
----------------
Код для этого -
M = np.array([[1,1,1],
[0,0,0],
[1,1,1]]) #3,3 matrix M
V = np.array([[1,2,3,4],
[1,2,3,4], #4,3 indexed vector
[1,2,3,4]]) #store 4 column vectors
R = M * V.T[:,None,:] #<--------------
R
array([[[1, 1, 1],
[0, 0, 0],
[1, 1, 1]],
[[2, 2, 2],
[0, 0, 0],
[2, 2, 2]],
[[3, 3, 3],
[0, 0, 0],
[3, 3, 3]],
[[4, 4, 4],
[0, 0, 0],
[4, 4, 4]]])
Опубликуйте это, если у вас есть какая-либо агрегация, вы можете уменьшить матрицу с помощью необходимых операций.
Например, Matrix M
* вектор-столбец [1,1,1]
приводит к -
array([[[1, 1, 1],
[0, 0, 0],
[1, 1, 1]],
в то время как Matrix M
* вектор-столбец [4,4,4]
приводит к -
array([[[4, 4, 4],
[0, 0, 0],
[4, 4, 4]],
Я думаю, это на самом деле. Поиграюсь на всякий случай, спасибо
круто, если это так, то в основном numpy - это использование вещания в соответствии с вашими потребностями. проверьте обновленную таблицу broadcasting rules
(перед разделом кода), чтобы узнать, как это работает.
Извините, но выходной файл $W$ не должен быть семейством векторов с индексом $I$, как и $V$. Но я проверю ваши советы по вещанию, так как они, вероятно, очень помогут.
не могли бы вы привести пример с реальными формами? как форма M, количество векторов-столбцов и форма каждого вектора для V и ожидаемая форма вывода?
Хорошо, скоро добавлю информацию. Ваше здоровье
добавьте примечание здесь в комментариях, чтобы я мог получать уведомления и обновлять свой ответ. спасибо и ура!
W = [np.dot(M, V[i]) for i in range(N)]
— это просто точечный продукт. возможно с какой-то осью перетасовали. потому что скалярные произведения двух матриц можно рассматривать как скалярное произведение матрицы с ее векторами-столбцами. сложены. обновил мой ответ для деталей
С
shape(M) == (2, 2)
shape(V) == (N, 2)
и
W = [np.dot(M, V[i]) for i in range(N)]
V[i]
есть (2,), поэтому np.dot(M,V[i])
есть (2,2) с (2,) => (2,) с суммой произведений на последних 2 из M. np.array(W)
тогда (N,2) форма
Для 2d A,B
np.dot(A,B)
выполняет сумму произведений с последним измерением A
и от 2-го до последнего из B
. Вы хотите последний дим M
с последним из V
.
Один из способов:
np.dot(M,V.T).T # (2,2) with (2,N) => (2,N) => (N,2)
([email protected]).T # with the matmul operator
Иногда einsum
делает связь между осями более ясной:
np.einsum('ij,nj->ni',M,V)
np.einsum('ij,jn->in',M,V.T).T # with j in last/2nd last positions
Или поменять порядок V
и M
:
V @ M.T # 'nj,ji->ni'
Или, рассматривая размерность N
как партию, мы могли бы получить V[:,:,None]
(N,2,1). Это можно представить как N (2,1) «векторов-столбцов».
M @ V[:,:,None] # (N,2,1)
np.einsum('ij,njk->nik', M, V[:,:,None]) # again j is in the last/2nd last slots
Численно:
In [27]: M = np.array([[1,2],[3,4]]); V = np.array([[1,2],[2,3],[3,4]])
In [28]: [M@V[i] for i in range(3)]
Out[28]: [array([ 5, 11]), array([ 8, 18]), array([11, 25])]
In [30]: ([email protected]).T
Out[30]:
array([[ 5, 11],
[ 8, 18],
[11, 25]])
In [31]: [email protected]
Out[31]:
array([[ 5, 11],
[ 8, 18],
[11, 25]])
Или в пакетном режиме:
In [32]: M@V[:,:,None]
Out[32]:
array([[[ 5],
[11]],
[[ 8],
[18]],
[[11],
[25]]])
In [33]: np.squeeze(M@V[:,:,None])
Out[33]:
array([[ 5, 11],
[ 8, 18],
[11, 25]])
Спасибо за ответ. Итак, np.dot(M, V[i])
имеет форму (2,)
, и я действительно не хочу ничего суммировать.
Вы можете опубликовать свои уравнения в виде изображений? к сожалению, уравнения уценки/латекса не отображаются на SO.