Умножение плотной матрицы с разреженными векторами скиппи с помощью @
невероятно неэффективно. Кажется, что он совсем не использует разреженность вектора.
Скажем, у нас есть
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)
Это намного быстрее! Несмотря на то, что эта реализация сначала создает плотный вектор, снова добавляя все нули, а затем снова удаляя все нули ... Поэтому мне интересно, если не @
, как я могу умножить плотную матрицу с кусочками на разреженный scipy? вектор эффективно? Конечно, такая основная операция является частью 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)
Редактировать 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)
Здесь вы можете видеть, что наш «взлом» занимает около 0,5% времени этой функции, в то время как использование dot
занимает 79,7% времени этой функции.