2016-09-25 7 views
2

У меня есть разреженная матрица в формате csr_matrix. Для каждой строки мне нужно вычесть среднее значение строки из ненулевых элементов. Средство должно вычисляться по числу ненулевых элементов строки (вместо длины строки). я нашел быстрый способ вычисления строки означает, что с помощью следующего кода:scipy.sparse matrix: вычитание строки означает ненулевые элементы

# M is a csr_matrix 
sums = np.squeeze(np.asarray(M.sum(1))) # sum of the nonzero elements, for each row 
counts = np.diff(M.tocsr().indptr)   # count of the nonzero elements, for each row 


# for the i-th row the mean is just sums[i]/float(counts[i]) 

Проблемы является частью обновления. Мне нужен быстрый способ сделать это. На самом деле то, что я делаю, чтобы превратить М в lil_matrix и выполнять обновления таким образом:

M = M.tolil() 

for i in xrange(len(sums)): 
    for j in M.getrow(i).nonzero()[1]: 
     M[i, j] -= sums[i]/float(counts[i]) 

, который медленно. Любое предложение для более быстрого решения?

+0

Я попытался бы повторить разграничение строк с помощью 'np.repeat' и' counts' и sub, которые непосредственно из массива 'M.data'. – hpaulj

ответ

2

Этот сложный вопрос. Кажется, у меня это есть. Основная идея состоит в том, что мы пытаемся получить диагональную матрицу со средствами на диагонали и матрицей, подобной М, но имеющей единицы в ненулевых местоположениях данных в М. Затем мы умножаем их и вычитаем произведение из М. Здесь идет ...

>>> import numpy as np 
>>> import scipy.sparse as sp 
>>> a = sp.csr_matrix([[1., 0., 2.], [1.,2.,3.]]) 
>>> a.todense() 
matrix([[ 1., 0., 2.], 
     [ 1., 2., 3.]]) 
>>> tot = np.array(a.sum(axis=1).squeeze())[0] 
>>> tot 
array([ 3., 6.]) 
>>> cts = np.diff(a.indptr) 
>>> cts 
array([2, 3], dtype=int32) 
>>> mu = tot/cts 
>>> mu 
array([ 1.5, 2. ]) 
>>> d = sp.diags(mu, 0) 
>>> d.todense() 
matrix([[ 1.5, 0. ], 
     [ 0. , 2. ]]) 
>>> b = a.copy() 
>>> b.data = np.ones_like(b.data) 
>>> b.todense() 
matrix([[ 1., 0., 1.], 
     [ 1., 1., 1.]]) 
>>> (d * b).todense() 
matrix([[ 1.5, 0. , 1.5], 
     [ 2. , 2. , 2. ]]) 
>>> (a - d*b).todense() 
matrix([[-0.5, 0. , 0.5], 
     [-1. , 0. , 1. ]]) 

Удачи! Надеюсь, это поможет.

+0

Да, я думал об одном и том же. Спасибо! – revy

2

Начиная с @Dthal's образца:

In [92]: a = sparse.csr_matrix([[1.,0,2],[1,2,3]]) 
In [93]: a.A 
Out[93]: 
array([[ 1., 0., 2.], 
     [ 1., 2., 3.]]) 

In [94]: sums=np.squeeze(a.sum(1).A) 
# sums=a.sum(1).A1 # shortcut 
In [95]: counts=np.diff(a.tocsr().indptr) 
In [96]: means=sums/counts 
In [97]: sums 
Out[97]: array([ 3., 6.]) 
In [98]: counts 
Out[98]: array([2, 3], dtype=int32) 
In [99]: means 
Out[99]: array([ 1.5, 2. ]) 

repeat позволяет нам повторить means, создавая массив, который соответствует матрице data размера.

In [100]: mc = np.repeat(means, counts) 
In [101]: mc 
Out[101]: array([ 1.5, 1.5, 2. , 2. , 2. ]) 

Это mc такая же, как @Dthal's(b*d).data.

Теперь просто вычтите его из data.

In [102]: a.data -= mc 
In [103]: a.A 
Out[103]: 
array([[-0.5, 0. , 0.5], 
     [-1. , 0. , 1. ]]) 

 Смежные вопросы

  • Нет связанных вопросов^_^