Умножение массива и матрицы - PullRequest
0 голосов
/ 16 октября 2018

Я пытаюсь избавиться от цикла for и вместо этого выполнить умножение матрицы на матрицу, чтобы уменьшить время обработки, когда массив weights очень большой:

import numpy as np
sequence = [np.random.random(10), np.random.random(10), np.random.random(10)]

weights = np.array([[0.1,0.3,0.6],[0.5,0.2,0.3],[0.1,0.8,0.1]])
Cov_matrix = np.matrix(np.cov(sequence))
results = []
for w in weights:
    result = np.matrix(w)*Cov_matrix*np.matrix(w).T
    results.append(result.A)

Где:

Cov_matrix - матрица 3x3weights это массив n длины с n 1x3 матрицами в нем.

Есть ли способ умножить / отобразить weights на Cov_matrix и обойти цикл for?Я не очень знаком со всеми функциями numpy.

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Я хотел бы повторить то, что уже было сказано в другом ответе: класс np.matrix имеет гораздо больше недостатков, чем преимуществ в наши дни, и я предлагаю перейти к использованию только класса np.array.Матричное умножение массивов может быть легко записано с использованием оператора @, поэтому запись в большинстве случаев такая же элегантная, как и для класса matrix (и у массивов нет нескольких ограничений, которые есть у матриц).

При этом все, что вам нужно, можно сделать с помощью звонка на номер np.einsum.Нам нужно сжать определенные индексы трех матриц, оставив один индекс в двух матрицах.То есть мы хотим выполнить w_{ij} * Cov_{jk} * w.T_{ki} с суммированием по j, k, что даст нам массив с индексами i.Будет выполнен следующий вызов einsum:

res = np.einsum('ij,jk,ik->i', weights, Cov_matrix, weights)

Обратите внимание, что приведенное выше даст вам один 1d массив, тогда как у вас изначально был список массивов с формой (1,1).Я подозреваю, что приведенный выше результат будет иметь больше смысла.Также обратите внимание, что я пропустил транспонирование во втором аргументе weights, и именно поэтому соответствующие индексы суммирования отображаются как ik, а не ki.Это должно быть немного быстрее.

Чтобы доказать, что приведенное выше дает тот же результат:

In [8]: results # original
Out[8]: [array([[0.02803215]]), array([[0.02280609]]), array([[0.0318784]])]

In [9]: res # einsum
Out[9]: array([0.02803215, 0.02280609, 0.0318784 ])
0 голосов
/ 16 октября 2018

То же самое можно достичь, работая с весами в качестве матрицы, а затем просматривая диагональные элементы результата.А именно:

np.diag(weights.dot(Cov_matrix).dot(weights.transpose()))

, что дает:

array([0.03553664, 0.02394509, 0.03765553])

Это делает больше вычислений, чем необходимо (вычисляет вне диагоналей), поэтому, возможно, кто-то предложит более эффективный метод.

Примечание: я бы посоветовал медленно отойти от np.matrix и вместо этого работать с np.array.Требуется некоторое время, чтобы привыкнуть к неспособности сделать A*b, но в долгосрочной перспективе это принесет дивиденды. Здесь является связанным обсуждением.

...