2015-04-14 3 views
2

У меня есть большая csr_matrix, и я хочу добавить строки и получить новую csr_matrix с таким же количеством столбцов, но с уменьшенным числом строк. (Контекст: Матрица представляет собой документ, срок матрица, полученная из sklearn CountVectorizer, и я хочу, чтобы иметь возможность быстро объединять документы в соответствии с кодами, связанными с этими документами)Сумма строк в scipy.sparse.csr_matrix

Для минимального примера, это моя матрица:

import numpy as np 
from scipy.sparse import csr_matrix 
from scipy.sparse import vstack 

row = np.array([0, 4, 1, 3, 2]) 
col = np.array([0, 2, 2, 0, 1]) 
dat = np.array([1, 2, 3, 4, 5]) 
A = csr_matrix((dat, (row, col)), shape=(5, 5)) 
print A.toarray() 

[[1 0 0 0 0] 
[0 0 3 0 0] 
[0 5 0 0 0] 
[4 0 0 0 0] 
[0 0 2 0 0]] 

Нет, скажем, я хочу новую матрицу B, в которой строки (1, 4) и (2, 3, 5) комбинируются путем суммирования их, что будет выглядеть примерно так:

[[5 0 0 0 0] 
[0 5 5 0 0]] 

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

idx1 = [1, 4] 
idx2 = [2, 3, 5] 
A_sub1 = A[idx1, :].sum(axis=1) 
A_sub2 = A[idx2, :].sum(axis=1) 
B = vstack((A_sub1, A_sub2)) 

Но это дает мне суммированные до значения только для ненулевых столбцов в срезе, так что я не могу объединить его с другими поскольку количество столбцов в суммированных срезах различно.

Я чувствую, что должен быть простой способ сделать это. Но я не мог найти никакого обсуждения этого онлайн или в документации. Что мне не хватает?

Спасибо за вашу помощь

ответ

4

Обратите внимание, что вы можете сделать это путем тщательного построения другой матрицы. Вот как это будет работать для плотной матрицы:

>>> S = np.array([[1, 0, 0, 1, 0,], [0, 1, 1, 0, 1]]) 
>>> np.dot(S, A.toarray()) 
array([[5, 0, 0, 0, 0], 
     [0, 5, 5, 0, 0]]) 
>>> 

Редкая версия немного сложнее. Информация о какие строки должны быть просуммированы кодируется в row:

col = range(5) 
row = [0, 1, 1, 0, 1] 
dat = [1, 1, 1, 1, 1] 
S = csr_matrix((dat, (row, col)), shape=(2, 5)) 
result = S * A 
# check that the result is another sparse matrix 
print type(result) 
# check that the values are the ones we want 
print result.toarray() 

Выход:

<class 'scipy.sparse.csr.csr_matrix'> 
[[5 0 0 0 0] 
[0 5 5 0 0]] 

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

+0

Привет, спасибо за ваш ответ. Я не могу преобразовать матрицу А в массив, потому что она большая. Но я думаю, что я могу сделать матрицу размножаться непосредственно на разреженной матрице? –

+0

А вот последний «toarray» - это просто показать, что мы получаем правильный ответ, когда мы умножаем 'S * A' для этого небольшого примера - я не имел в виду, что вы конвертируете в плотный массив в свой код. Я добавлю комментарий. – YXD

+0

Отлично, спасибо. Это действительно элегантное решение –

1

Индексация должна быть:

idx1 = [0, 3]  # rows 1 and 4 
idx2 = [1, 2, 4] # rows 2,3 and 5 

Тогда вам нужно держать A_sub1 и A_sub2 в разреженном формате и использовать axis=0:

A_sub1 = csr_matrix(A[idx1, :].sum(axis=0)) 
A_sub2 = csr_matrix(A[idx2, :].sum(axis=0)) 
B = vstack((A_sub1, A_sub2)) 
B.toarray() 
array([[5, 0, 0, 0, 0], 
     [0, 5, 5, 0, 0]]) 

Заметь, я думаю, что операции A[idx, :].sum(axis=0) связаны с преобразованием из разреженных матриц - так что ответ @ Mr_E, вероятно, э.

Кроме того, она работает, когда вы используете axis=0 и np.vstack (в отличие от scipy.sparse.vstack):

A_sub1 = A[idx1, :].sum(axis=0) 
A_sub2 = A[idx2, :].sum(axis=0) 
np.vstack((A_sub1, A_sub2)) 

Отдает:

matrix([[5, 0, 0, 0, 0], 
     [0, 5, 5, 0, 0]]) 
+1

'A.sum (0)' использует 'np.matrix (np.((1,5), int)) * A', который возвращает плотную матрицу. 'sparse.csr_matrix (np.ones ((1,5), int)) * A' возвращает разреженный. – hpaulj

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