Как по-разному умножить матрицу scipy.sparse на широковещательный плотный массив 1d?
Предположим, что у меня есть 2d разреженный массив. В моем реальном использовании количество строк и столбцов намного больше (скажем, 20000 и 50000), поэтому оно не может вместиться в память при использовании плотного представления:
>>> import numpy as np
>>> import scipy.sparse as ssp
>>> a = ssp.lil_matrix((5, 3))
>>> a[1, 2] = -1
>>> a[4, 1] = 2
>>> a.todense()
matrix([[ 0., 0., 0.],
[ 0., 0., -1.],
[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 2., 0.]])
Теперь предположим, что у меня есть плотный 1d-массив со всеми компонентами non-zeros размером 3 (или 50000 в моем реальном случае жизни):
>>> d = np.ones(3) * 3
>>> d
array([ 3., 3., 3.])
Я хотел бы вычислить элементарное умножение a и d, используя обычную семантику трансляции numpy. Однако разреженные матрицы в scipy имеют np.matrix: оператор '*' перегружен, чтобы он вел себя как матричное умножение вместо элементарного умножения:
>>> a * d
array([ 0., -3., 0., 0., 6.])
Одним из решений было бы сделать "a" переключением на семантику массива для оператора "*", что даст ожидаемый результат:
>>> a.toarray() * d
array([[ 0., 0., 0.],
[ 0., 0., -3.],
[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 6., 0.]])
Но я не могу этого сделать, поскольку вызов toarray() будет реализовывать плотную версию "a", которая не вписывается в память (и результат тоже будет плотным):
>>> ssp.issparse(a.toarray())
False
Любая идея, как построить это, сохраняя только разреженные структуры данных и не выполняя неэффективный цикл питона на столбцах 'a'?
Ответы
Ответ 1
Я тоже ответил на scipy.org, но я подумал, что должен добавить здесь ответ, если другие найдут эту страницу при поиске.
Вы можете превратить вектор в разреженную диагональную матрицу, а затем использовать матричное умножение (с *), чтобы сделать то же самое, что и трансляция, но эффективно.
>>> d = ssp.lil_matrix((3,3))
>>> d.setdiag(np.ones(3)*3)
>>> a*d
<5x3 sparse matrix of type '<type 'numpy.float64'>'
with 2 stored elements in Compressed Sparse Row format>
>>> (a*d).todense()
matrix([[ 0., 0., 0.],
[ 0., 0., -3.],
[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 6., 0.]])
Надеюсь, что это поможет!
Ответ 2
Я думаю, что A.multiply(B) должен работать в скудном разрезе. Метод умножает умножение "по точкам", а не на матричное умножение.
НТН
Ответ 3
Ну, вот простой код, который будет делать то, что вы хотите. Я не знаю, насколько это так эффективно, как вы хотели бы, поэтому возьмите его или оставьте его:
import scipy.sparse as ssp
def pointmult(a,b):
x = a.copy()
for i in xrange(a.shape[0]):
if x.data[i]:
for j in xrange(len(x.data[i])):
x.data[i] *= b[x.rows[i]]
return x
Он работает только с матрицами lil, поэтому вам нужно будет внести некоторые изменения, если вы хотите, чтобы он работал с другими форматами.