Я пытаюсь вычислить среднее значение ненулевых значений в каждой строке матрицы разреженных строк. Использование среднего метода матрицы не делает этого:

>>> from scipy.sparse import csr_matrix
>>> a = csr_matrix([[0, 0, 2], [1, 3, 8]])
>>> a.mean(axis=1)
matrix([[ 0.66666667],
        [ 4.        ]])

Следующее работает, но медленно для больших матриц:

>>> import numpy as np
>>> b = np.zeros(a.shape[0])
>>> for i in range(a.shape[0]):
...    b[i] = a.getrow(i).data.mean()
... 
>>> b
array([ 2.,  4.])

Может ли кто-нибудь сказать мне, если есть более быстрый метод?

5
batsc 14 Дек 2015 в 14:21

3 ответа

Лучший ответ

Это типичная проблема, когда вы можете использовать numpy.bincount.. Для этого я использовал три функции:

(x,y,z)=scipy.sparse.find(a)

Возвращает строки (x), столбцы (y) и значения (z) разреженной матрицы. Например, x это array([0, 1, 1, 1].

numpy.bincount(x) возвращает для каждого номера строки, сколько ненулевых элементов у вас есть.

numpy.bincount(x,wights=z) возвращает для каждой строки суммы ненулевых элементов.

Окончательный рабочий код:

from scipy.sparse import csr_matrix
a = csr_matrix([[0, 0, 2], [1, 3, 8]])

import numpy
import scipy.sparse
(x,y,z)=scipy.sparse.find(a)
countings=numpy.bincount(x)
sums=numpy.bincount(x,weights=z)
averages=sums/countings

print(averages)

Возвращает :

[ 2.  4.]
6
Antonio Ragagnin 14 Дек 2015 в 15:21

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

Вот так:

sp_arr = csr_matrix([[0, 0, 2], [1, 3, 8]])
col_avg = sp_arr.sum(0) / (sp_arr != 0).sum(0)
row_avg = sp_arr.sum(1) / (sp_arr != 0).sum(1)
print(col_avg)
matrix([[ 1.,  3.,  5.]])
print(row_avg)
matrix([[ 2.],
        [ 4.]])

По сути, вы суммируете общее значение всех записей вдоль заданной оси и делите на сумму True записей, где матрица! = 0 (это число реальных записей).

Я считаю этот подход менее сложным и простым, чем другие варианты.

2
Grr 25 Сен 2017 в 21:43

С матрицей формата CSR вы можете сделать это еще проще:

sums = a.sum(axis=1).A1
counts = np.diff(a.indptr)
averages = sums / counts

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

7
perimosocordiae 15 Дек 2015 в 17:16