Используйте формат scipy.sparse
, основанный на строках или столбцах: csc_matrix
и csr_matrix
.
В них используются эффективные реализации C под капотом (включая умножение), а транспонирование не используется (особенно если вы вызываете transpose(copy=False)
), как и в случае с массивными массивами.
РЕДАКТИРОВАТЬ: некоторые тайминги через ipython :
import numpy, scipy.sparse
n = 100000
x = (numpy.random.rand(n) * 2).astype(int).astype(float) # 50% sparse vector
x_csr = scipy.sparse.csr_matrix(x)
x_dok = scipy.sparse.dok_matrix(x.reshape(x_csr.shape))
Теперь x_csr
и x_dok
на 50% разрежены:
print repr(x_csr)
<1x100000 sparse matrix of type '<type 'numpy.float64'>'
with 49757 stored elements in Compressed Sparse Row format>
И время:
timeit numpy.dot(x, x)
10000 loops, best of 3: 123 us per loop
timeit x_dok * x_dok.T
1 loops, best of 3: 1.73 s per loop
timeit x_csr.multiply(x_csr).sum()
1000 loops, best of 3: 1.64 ms per loop
timeit x_csr * x_csr.T
100 loops, best of 3: 3.62 ms per loop
Похоже, я солгал. Транспозиция очень дешева , но эффективной реализации Csr * csc не существует (в последней версии scipy 0.9.0). Новый объект CSR создается в каждом вызове: - (
Как хак (хотя scipy в наши дни относительно стабилен), вы можете использовать скалярное произведение непосредственно на разреженных данных:
timeit numpy.dot(x_csr.data, x_csr.data)
10000 loops, best of 3: 62.9 us per loop
Обратите внимание, что этот последний подход снова делает умноженное плотное умножение. Разреженность составляет 50%, поэтому она на самом деле быстрее, чем dot(x, x)
в 2 раза.