簡體   English   中英

如何在密集的numpy矩陣和稀疏的scipy向量之間進行有效的矩陣乘法?

[英]How to do efficient matrix multiplication between a dense numpy matrix and a sparse scipy vector?

使用@將稀疏的矢量向量與稀疏的numpy矩陣相乘效率極低。 似乎它根本沒有利用向量的稀疏性。

說我們有

A = np.eye(5000)
x = np.eye(5000)[333]
x = scipy.sparse.coo_matrix(x).T # make it a sparse vector

然后使用@產生乘法:

%timeit A @ x
8 ms ± 78.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

讓我們自己編寫一個非常糟糕的稀疏乘法:

def mult_dense_with_sparse(A, x):
  return (A[:,x.nonzero()[0]] @ x.toarray()[x.nonzero()[0]]).T[0]

瞧瞧:

%timeit mult_dense_with_sparse(A, x)
50.3 µs ± 45.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

很多 即使此實現首先通過再次添加所有零來創建密集向量,然后再次刪除所有零...所以我想知道,如果不是@ ,我如何才能將密集的numpy矩陣與稀疏的scipy向量有效相乘? 這樣的基本操作當然是科學的一部分嗎?

編輯:在其他問題中提供的解決方案沒有幫助,因為它與@一樣低效:

%timeit scipy.sparse.csr_matrix.dot(A, x)
7.97 ms ± 113 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

在響應程序Hameer Abbasi中編輯2:

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   101                                                       @profile
   102                                                       def ratio(self, n):
   103        80         51.0      0.6      0.0                  s = n + 1
   104        80   11401854.0 142523.2     16.1                  self.sfpc = self.scolPCA(s) # sparse first principal component
   106        80     351898.0   4398.7      0.5                  wSums = (self.signals[:,self.sfpc.nonzero()[0]] @ self.sfpc.toarray()[self.sfpc.nonzero()[0]]).T[0]
   108        80   56487433.0 706092.9     79.7                  wSums = self.sfpc.T.dot(self.signals.T)[0]
   110        80    2521189.0  31514.9      3.6                  self.Flag, self.threshold, self.incline, self.deltaVar = self.actFunctOpt(list(wSums))
   111        80        160.0      2.0      0.0                  return  self.deltaVar / (2 + s)

在這里,您可以看到我們的“ hack”花費了此功能約0.5%的時間,而使用dot花費了此功能約79.7%的時間。

在您的示例中, A的類型為np.ndarrayx的類型為scipy.sparse.coo_matrix

如果您正在尋找最簡單的答案來加快速度,請按以下步驟進行:

import numpy as np
import scipy.sparse as sps
A = np.random.rand(5000, 5000)
v = np.zeros((5000, 1))
v[333] = 1
v_s = sps.csc_matrix(v)
%timeit v_s.T.dot(A).T # 46.6 µs ± 1.11 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit A @ v # 6.75 ms ± 29.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

但是,如果您想讓這個問題的答案更復雜:當前,由於有bug ,運算符@不支持NumPy數組的重載。 此外, scipy.sparse.coo_matrix甚至都不會嘗試覆蓋@ ,並且scipy.sparse.csr_matrix矩陣乘法更快( coo_matrix都將首先轉換為csr_matrix進行乘法)。

因此,發生的事情是NumPy將您的稀疏矢量轉換為NumPy數組,然后執行密集乘法。

但是, csr_matrix.dot存在並且支持與密集的NumPy數組相乘。 因此,我們使用屬性A @ B = (BT @ AT).T以及csc_matrix.T生成csr_matrix來生成上述優化代碼的事實。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM