расширение (добавление строки или столбца) матрицы scipy.sparse - PullRequest
30 голосов
/ 14 января 2011

Предположим, у меня есть NxN матрица M (lil_matrix или csr_matrix) из scipy.sparse, и я хочу сделать это (N + 1) xN, где M_modified [i, j] = M [i, j] для 0 <= i <N (и все j) и M [N, j] = 0 для всех j. По сути, я хочу добавить строку нулей в нижней части M и сохранить оставшуюся часть матрицы. Есть ли способ сделать это без копирования данных? </p>

Ответы [ 3 ]

26 голосов
/ 04 июля 2013

У Сципи нет способа сделать это без копирования данных, но вы можете сделать это самостоятельно, изменив атрибуты, определяющие разреженную матрицу.

Существует 4 атрибута, из которых состоит csr_matrix:

данные: массив, содержащий фактические значения в матрице

индексы: массив, содержащий индекс столбца, соответствующий каждому значению в данных

indptr: Массив, который указывает индекс перед первым значением в данных для каждой строки. Если строка пуста, индекс совпадает с предыдущим столбцом.

shape: кортеж, содержащий форму матрицы

Если вы просто добавляете строку нулей к основанию, все, что вам нужно сделать, это изменить форму и indptr для вашей матрицы.

x = np.ones((3,5))
x = csr_matrix(x)
x.toarray()
>> array([[ 1.,  1.,  1.,  1.,  1.],
          [ 1.,  1.,  1.,  1.,  1.],
          [ 1.,  1.,  1.,  1.,  1.]])
# reshape is not implemented for csr_matrix but you can cheat and do it  yourself.
x._shape = (4,5)
# Update indptr to let it know we added a row with nothing in it. So just append the last
# value in indptr to the end.
# note that you are still copying the indptr array
x.indptr = np.hstack((x.indptr,x.indptr[-1]))
x.toarray()
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.]])

Вот функция для обработки более общего случая vstacking любых 2 csr_matrices. Вы по-прежнему копируете базовые массивы numpy, но это все же значительно быстрее, чем метод scipy vstack.

def csr_vappend(a,b):
    """ Takes in 2 csr_matrices and appends the second one to the bottom of the first one. 
    Much faster than scipy.sparse.vstack but assumes the type to be csr and overwrites
    the first matrix instead of copying it. The data, indices, and indptr still get copied."""

    a.data = np.hstack((a.data,b.data))
    a.indices = np.hstack((a.indices,b.indices))
    a.indptr = np.hstack((a.indptr,(b.indptr + a.nnz)[1:]))
    a._shape = (a.shape[0]+b.shape[0],b.shape[1])
    return a
8 голосов
/ 07 сентября 2012

Не уверен, что вы все еще ищете решение, но, возможно, другие могут посмотреть на hstack и vstack - http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.hstack.html. Я думаю, что мы можем определить csr_matrix для одной дополнительной строки и затем1005 * это с предыдущей матрицей.

6 голосов
/ 14 января 2011

Я не думаю, что есть какой-то способ действительно избежать копирования.Оба этих типа разреженных матриц хранят свои данные как массивы Numpy (в атрибутах data и indexs для csr, а также в атрибутах data и rowings для lil), и массивы Numpy не могут быть расширены.

Обновление с дополнительной информацией:

LIL означает LInked List, но текущая реализация не совсем соответствует названию.Массивы Numpy, используемые для data и rows, относятся к типу object.Каждый из объектов в этих массивах на самом деле является списками Python (пустой список, когда все значения равны нулю подряд).Списки Python - это не совсем связанные списки, но они довольно близки и, честно говоря, являются лучшим выбором из-за поиска O (1).Лично я не вижу смысла использовать здесь массив объектов Numpy, а не просто список Python.Вы могли бы довольно легко изменить текущую реализацию lil для использования списков Python вместо этого, что позволило бы вам добавить строку без копирования всей матрицы.

...