Почему результат scipy.sparse.csc_matrix.sum () меняет свой тип на пустую матрицу? - PullRequest
0 голосов
/ 06 июня 2018

Я хочу сгенерировать большую разреженную матрицу и суммировать ее, но я сталкиваюсь с MemoryError.Поэтому я попытался выполнить операцию с помощью scipy.sparse.csc_matrix.sum , но обнаружил, что тип данных изменился на ноль matrix после получения суммы.

window = 10    
np.random.seed = 0
mat = sparse.csc_matrix(np.random.rand(100, 120)>0.5, dtype='d')
print type(mat)
>>> <class 'scipy.sparse.csc.csc_matrix'>

mat_head = mat[:,0:window].sum(axis=1)
print type(mat_head)
>>> <class 'numpy.matrixlib.defmatrix.matrix'>

Я сгенерировал mat как матрицу нулей, чтобы проверить результат, когда mat_head - все нули.

mat = sparse.csc_matrix((100,120))
print type(mat)
>>> <class 'scipy.sparse.csc.csc_matrix'>
mat_head = mat.sum(axis=1)
print type(mat_head)
>>> <class 'numpy.matrixlib.defmatrix.matrix'>
print np.count_nonzero(mat_head)
>>> 0

Почему это происходит?Таким образом, сумма через scipy.sparse не выгодна для сохранения памяти, чем numpy, так как они все равно изменяют тип данных?

Ответы [ 3 ]

0 голосов
/ 06 июня 2018

Форматы csr и csc были разработаны для линейных алгебр, особенно для решения больших, но разреженных линейных уравнений

A*x = b
x = b/A

A должны быть обратимыми и не могут иметьвсе строки 0 или столбцы.

A.sum(1) выполняется с помощью умножения матриц, с (n, 1) массивом 1 с.

С вашим mat:

In [203]: np.allclose(mat*np.mat(np.ones((120,1))), mat.sum(1))
Out[203]: True

Делая это самостоятельнона самом деле немного быстрее (где-то накладные расходы?)

In [204]: timeit mat.sum(1)
92.7 µs ± 111 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [205]: timeit mat*np.mat(np.ones((120,1)))
59.2 µs ± 53.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Я мог бы также сделать это с разреженной матрицей:

In [209]: mat*sparse.csc_matrix(np.ones((120,1)))
Out[209]: 
<100x1 sparse matrix of type '<class 'numpy.float64'>'
    with 100 stored elements in Compressed Sparse Column format>
In [211]: np.allclose(mat.sum(1),_.todense())
Out[211]: True

Но время медленнее, даже если я перемещаю разреженныесоздание вне цикла:

In [213]: %%timeit I=sparse.csc_matrix(np.ones((120,1)))
     ...: mat*I
     ...: 
215 µs ± 401 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Если mat было (115100,10) с множеством всех 0 строк, то такой редкий подход мог бы дать экономию времени и пространства.


mat[:,:10] также выполняется с умножением матрицы, с разреженной матрицей извлечения.

Это на самом деле медленнее, чем сумма строки:

In [247]: timeit mat[:,:10]
305 µs ± 10.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [248]: timeit mat[:,:10].sum(1)
384 µs ± 9.05 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Я могу объединить выбор столбца с суммой, используя:

In [252]: I = sparse.lil_matrix((120,1),dtype=int); I[:10,:]=1; I=I.tocsc()
In [253]: I
Out[253]: 
<120x1 sparse matrix of type '<class 'numpy.int64'>'
    with 10 stored elements in Compressed Sparse Column format>
In [254]: np.allclose((mat*I).todense(),mat[:,:10].sum(1))
Out[254]: True

Время на этом mat*I медленнее, хотя я мог бы улучшить шаг строительства I.

I = sparse.csc_matrix((np.ones(10,int), np.arange(10), np.array([0,10])), shape=(120,1))
0 голосов
/ 08 июня 2018

Мне известно, что ваш вопрос "почему" в основном нацелен на мотивацию, лежащую в основе решения о дизайне, но в любом случае я разыскал, как результат csc_matrix.sum(axis=1) на самом деле становится пустышкой matrix.

csc_matrix класс наследуется от _cs_matrix класса , который наследуется от _data_matrix класса , который наследуется от spmatrix базового класса .Этот последний реализует .sum(ax) как

if axis == 0:
    # sum over columns
    ret = np.asmatrix(np.ones(
        (1, m), dtype=res_dtype)) * self
else:
    # sum over rows
    ret = self * np.asmatrix(np.ones((n, 1), dtype=res_dtype))

Другими словами, , как также отмечено в комментарии , суммы столбцов / строк вычисляются умножением наплотная матрица строк или столбцов единиц соответственно.Результатом этой операции будет плотная матрица, которую вы видите на выходе.

Хотя некоторые из подклассов переопределяют свой метод .sum(), насколько я могу судить, это происходит только для случая axis=None,поэтому результат, который вы видите, можно отнести к приведенному выше блоку кода.

0 голосов
/ 06 июня 2018

Насколько возможно дать вескую причину того, что по сути является выбором дизайна, я бы привел следующий аргумент:

Форматы csr и csc предназначены для разреженных, но не очень разреженных матриц.В частности, для матрицы nxn, в которой значительно меньше, чем n ненулевых, эти форматы довольно расточительны, поскольку поверх данных и индексов они содержат поле indptr (обозначающее строки или столбцы) размером n + 1.

Поэтому при условии правильного использования матрицы csc или csr разумно ожидать, что суммы строк или столбцов не будут редкими, и соответствующий метод должен возвращать плотный вектор.

...