Как поэлементно умножить матрицу scipy.sparse на транслируемый плотный 1d массив? - PullRequest
41 голосов
/ 14 июля 2010

Предположим, у меня есть 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со всеми ненулевыми компонентами с размером 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

Любая идея, как построить это, сохраняя только разреженные структуры данных и не делая неэффективный цикл Python настолбцы «а»?

Ответы [ 3 ]

45 голосов
/ 29 июля 2010

Я также ответил на 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.]])

Надеюсь, это поможет!

24 голосов
/ 21 декабря 2010

Я думаю, что A.multiply (B) должен работать в скудном разреженном виде.Метод умножения выполняет «точечное» умножение, а не умножение матриц.

HTH

1 голос
/ 19 июля 2010

Хорошо, вот простой код, который будет делать то, что вы хотите.Я не знаю, насколько это эффективно, как вы хотели бы, поэтому возьмите его или оставьте:

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, поэтому вам придется внести некоторые изменения, если вы хотитеработать с другими форматами.

...