Эффективный способ нормализовать скудную разреженную матрицу

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

from pylab import *
import scipy.sparse as sp

def normalize(W):
    z = W.sum(0)
    z[z < 1e-6] = 1e-6
    return W / z[None,:]

w = (rand(10,10)<0.1)*rand(10,10)
w = sp.csr_matrix(w)
w = normalize(w)

Однако это дает следующее исключение:

File "/usr/lib/python2.6/dist-packages/scipy/sparse/base.py", line 325, in __div__
     return self.__truediv__(other)
File "/usr/lib/python2.6/dist-packages/scipy/sparse/compressed.py", line 230, in  __truediv__
   raise NotImplementedError

Есть ли достаточно простые решения? Я смотрел наэтот, но до сих пор неясно, как на самом деле сделать разделение.

 conradlee13 сент. 2012 г., 00:28
Я не согласен, это другая проблема. Дубликат, на который вы указали, выполняет поэлементное умножение, в то время как этот вопрос, кажется, хочет разделить каждую строку на другое значение (а не на все ненулевые элементы на одно и то же значение). Решение Aaron McDaid, представленное ниже, должно работать эффективно (и не требует никакого копирования данных).
 sterne07 сент. 2012 г., 14:14
Большое спасибо!
 seberg06 сент. 2012 г., 22:39
Это в основном дубликат:stackoverflow.com/questions/12237954/… поскольку не имеет значения, является ли построчное поэлементное умножение или деление. Конечно, если у кого-то есть лучший ответ, отлично :)
 Emmet21 авг. 2013 г., 03:39
AFAICT это дубликатstackoverflow.com/questions/8358962/…

Ответы на вопрос(3)

я реализовал решение, когда хотел нормализоваться относительно максимумаabsolute ценности, которые склеарн не предлагает. Мой метод использует ненулевые записи и находит их в массиве csr_matrix.data для быстрой замены значений там.

def normalize_sparse(csr_matrix):
    nonzero_rows = csr_matrix.nonzero()[0]
    for idx in np.unique(nonzero_rows):
        data_idx = np.where(nonzero_rows==idx)[0]
        abs_max = np.max(np.abs(csr_matrix.data[data_idx]))
        if abs_max != 0:
            csr_matrix.data[data_idx] = 1./abs_max * csr_matrix.data[data_idx]

В отличие от сунейского решения, этот способ не требует какого-либо преобразования матрицы в плотный формат (что может вызвать проблемы с памятью) и умножения матрицы. Я проверил способ на разреженной матрице формы (35 ', 486' 000), и это заняло ~ 18 секунд.

Решение Вопроса

scikit-learn sklearn.preprocessing.normalize.

from sklearn.preprocessing import normalize
w_normalized = normalize(w, norm='l1', axis=1)

axis=1 следует нормализовать по строкам,axis=0 нормализовать по столбцу. Используйте необязательный аргументcopy=False изменить матрицу на месте.

 10 июл. 2015 г., 14:56
Обратите внимание, что если вы нормализуете по признакам (ось = 0), то возвращаемая матрица будет иметь тип «csc». даже если w был "csr". Это может быть неприятно, если вы рассчитываете на то, что это «csr»;

transpose A calculate sum of each col format diagonal matrix B with reciprocal of sum A*B equals normalization

transpose C

import scipy.sparse as sp
import numpy as np
import math

minf = 0.0001

A = sp.lil_matrix((5,5))
b = np.arange(0,5)
A.setdiag(b[:-1], k=1)
A.setdiag(b)
print A.todense()
A = A.T
print A.todense()

sum_of_col = A.sum(0).tolist()
print sum_of_col
c = []
for i in sum_of_col:
    for j in i:
        if math.fabs(j)<minf:
            c.append(0)
        else:
            c.append(1/j)

print c

B = sp.lil_matrix((5,5))
B.setdiag(c)
print B.todense()

C = A*B
print C.todense()
C = C.T
print C.todense()

Ваш ответ на вопрос