«Векторизованное» умножение матрицы на вектор в numpy

У меня есть $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)

Вы можете опубликовать свои уравнения в виде изображений? к сожалению, уравнения уценки/латекса не отображаются на SO.

Akshay Sehgal 11.01.2023 02:45

также, не могли бы вы предоставить некоторые входные массивы numpy и ожидаемый результат

Akshay Sehgal 11.01.2023 02:46

В numpy* — это точечное или поэлементное умножение. @ - это умножение матриц - с суммой произведений на размеры определенной пары. np.dot и np.matmul задокументируйте, как связаны размеры. np.einsum — это более общий инструмент для указания осей умножения и суммирования. Для * умножения применяются правила broadcasting (broadcasting также используется со сложением и другими операциями.

hpaulj 11.01.2023 02:57

Ваше использование вектора и матрицы может быть расплывчатым. numpy имеет массивы, которые могут быть 1d или 2d (или 0d или 3d и т. д.). vector/matrix не являются «родными» терминами numpy. Двумерную матрицу можно считать «матрицей», но «вектор» может иметь форму (n), или (n, 1), или (1, n).

hpaulj 11.01.2023 02:59

Для наглядности часто помогает пример с итеративным вычислением.

hpaulj 11.01.2023 03:04

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

Mark 11.01.2023 03:08

Какой раздел математики? Часто плакаты ожидают, что numpy будет вести себя так же, как линейная алгебра или MATLAB, с различием между векторами-строками и векторами-столбцами.

hpaulj 11.01.2023 03:17

"индексированное семейство векторов"? 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.

hpaulj 11.01.2023 03:23

То, что вы ищете, это ([email protected]).T. обновил мой ответ на тот же

Akshay Sehgal 11.01.2023 04:32
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
9
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Обновлено:

Основываясь на вашем повторяющемся примере, кажется, что это можно сделать с помощью точечного продукта с некоторыми транспонированием, чтобы соответствовать формам. Это то же самое, что и ([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]],

Я думаю, это на самом деле. Поиграюсь на всякий случай, спасибо

Mark 11.01.2023 03:11

круто, если это так, то в основном numpy - это использование вещания в соответствии с вашими потребностями. проверьте обновленную таблицу broadcasting rules (перед разделом кода), чтобы узнать, как это работает.

Akshay Sehgal 11.01.2023 03:13

Извините, но выходной файл $W$ не должен быть семейством векторов с индексом $I$, как и $V$. Но я проверю ваши советы по вещанию, так как они, вероятно, очень помогут.

Mark 11.01.2023 03:15

не могли бы вы привести пример с реальными формами? как форма M, количество векторов-столбцов и форма каждого вектора для V и ожидаемая форма вывода?

Akshay Sehgal 11.01.2023 03:16

Хорошо, скоро добавлю информацию. Ваше здоровье

Mark 11.01.2023 03:17

добавьте примечание здесь в комментариях, чтобы я мог получать уведомления и обновлять свой ответ. спасибо и ура!

Akshay Sehgal 11.01.2023 03:17
W = [np.dot(M, V[i]) for i in range(N)] — это просто точечный продукт. возможно с какой-то осью перетасовали. потому что скалярные произведения двух матриц можно рассматривать как скалярное произведение матрицы с ее векторами-столбцами. сложены. обновил мой ответ для деталей
Akshay Sehgal 11.01.2023 04:24

С

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,Bnp.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,), и я действительно не хочу ничего суммировать.

Mark 11.01.2023 06:52

Другие вопросы по теме