2017-02-05 7 views
4

У меня есть мешок из-слов представления корпуса, сохраненного в D по W разреженной матрицы word_freqs. Каждая строка является документом, и каждый столбец является словом. Данный элемент word_freqs[d,w] представляет число вхождений слова w в документ d.Logical не на SciPy разреженной матрицы

Я пытаюсь получить другую D по W матрица not_word_occs где для каждого элемента word_freqs:

  • Если word_freqs[d,w] равен нулю, not_word_occs[d,w] должен быть один.
  • В противном случае not_word_occs[d,w] должен быть равен нулю.

В конце концов, эту матрицу нужно будет умножить на другие матрицы, которые могут быть плотными или разреженными.


Я пробовал несколько методов, в том числе: (., Которая составляет около 18,000x16,000)

not_word_occs = (word_freqs == 0).astype(int) 

Эти слова для игрушечные примеры, но результаты в MemoryError для моих фактических данных ,

Я также попытался np.logical_not():

word_occs = sklearn.preprocessing.binarize(word_freqs) 
not_word_occs = np.logical_not(word_freqs).astype(int) 

Это казалось многообещающим, но np.logical_not() не работает на разреженных матриц, что дает следующую ошибку:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all(). 

Любые идеи или инструктивный будет оценена.

(.. Кстати, word_freqs порождается sklearn-х preprocessing.CountVectorizer() Если есть решение, которое включает в себя преобразование это другой вид матрицы, я, конечно, открыты для этого)

+0

Если 'word_freqs' является SciPy разреженной матрицы, она должна иметь представление печати, который показывает форму, число ненулевых значений, dtype и разреженного формата. – hpaulj

+0

'<18144x14511 разреженная матрица типа '' с 619900 хранимыми элементами в формате сжатого разреженного диапазона>' – err1100

+1

Так что это .002 разреженный. Тогда «нет» будет 99,8%. – hpaulj

ответ

1

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

>>> import numpy as np 
>>> a = [] 
>>> for j in range(100): 
...  print(j) 
...  a.append(np.ones((16000, 18000), dtype=int)) 

Мой ноутбук дросселей при у = 1. Поэтому, если у вас нет действительно хорошего компьютера, даже если вы можете получить дополнение (вы можете сделать

>>> compl = np.ones(S.shape,int) 
>>> compl[S.nonzero()] = 0 

) Память будет проблемой.

Одним из путей может быть не явное вычисление дополнения, назовем его C = B1 - A, где B1 является матрицей одинаковой формы, полностью заполненной единицами, а A - матрицей смежности вашей исходной разреженной матрицы. Например, матричный продукт XC можно записать в виде XB1-XA, поэтому у вас есть одно умножение с разреженным A и одно с B1, что на самом деле дешево, потому что оно сводится к вычислению сумм строк. Дело в том, что вы можете вычислить это, не вычисляя сначала C.

Особенно простым примером может быть умножение на один горячий вектор. Такое умножение просто выбирает столбец (если умножается справа) или строка (если умножить слева) другой матрицы. Это означает, что вам просто нужно найти этот столбец или строку разреженной матрицы и взять дополнение (для одного среза нет проблемы), и если вы сделаете это для одной горячей матрицы, как указано выше, вам не нужно явно вычислять дополнение.

+0

Я думаю, что следую за вами, но что такое «матрица смежности [моей] оригинальной разреженной матрицы»? – err1100

+0

@ err1100 О, жаргон, извините. Это одна и та же матрица со всеми ненулевыми элементами, установленными в одну. Btw. Я уверен, что схема, которую я описал в последнем абзаце, применима к однократным матрицам. Позвольте мне немного подумать, и я добавлю несколько строк. –

+0

Спасибо, Пол. Я смог заставить все работать благодаря вашему разложению.Вычисление фактических матриц по-прежнему использовало слишком много ОЗУ (в частности, составляя матрицу размером 16 КБ на 18 КБ), но ваш горячий пункт позволил мне понять, как это сделать, не делая матрицы. – err1100

0

Сделать небольшую разреженную матрицу:

In [743]: freq = sparse.random(10,10,.1) 
In [744]: freq 
Out[744]: 
<10x10 sparse matrix of type '<class 'numpy.float64'>' 
    with 10 stored elements in COOrdinate format> 

repr(freq) показывает форму, элементы и формат.

In [745]: freq==0 
/usr/local/lib/python3.5/dist-packages/scipy/sparse/compressed.py:213: SparseEfficiencyWarning: Comparing a sparse matrix with 0 using == is inefficient, try using != instead. 
    ", try using != instead.", SparseEfficiencyWarning) 
Out[745]: 
<10x10 sparse matrix of type '<class 'numpy.bool_'>' 
    with 90 stored elements in Compressed Sparse Row format> 

Если вы делаете свое первое действие, я получаю предупреждение и новый массив с 90 (из 100) ненулевыми терминами. То, что not больше не разрежено.

В целом функции numpy не работают при применении к разреженным матрицам. Чтобы работать, они должны делегировать задачу редким методам. Но даже если бы logical_not работал, это не решило бы проблему с памятью.

+0

В этом случае у вас есть предложения? Для контекста у меня есть горячая _D_ по _K_ матрице 'doc_topics', представляющая тему каждого документа. Позже мне нужно найти матрицу _W_ by_K_, которая сообщает мне, сколько документов темы _k_ do _not_ содержит слово _w_. С моими игрушечными примерами я выполнял это с помощью 'not_word_occs.T @ doc_topics', но теперь мне нужен другой способ сделать это. – err1100

0

Ниже приведен пример использования Pandas.SparseDataFrame:

In [42]: X = (sparse.rand(10, 10, .1) != 0).astype(np.int64) 

In [43]: X = (sparse.rand(10, 10, .1) != 0).astype(np.int64) 

In [44]: d1 = pd.SparseDataFrame(X.toarray(), default_fill_value=0, dtype=np.int64) 

In [45]: d2 = pd.SparseDataFrame(np.ones((10,10)), default_fill_value=1, dtype=np.int64) 

In [46]: d1.memory_usage() 
Out[46]: 
Index 80 
0  16 
1   0 
2   8 
3  16 
4   0 
5   0 
6  16 
7  16 
8   8 
9   0 
dtype: int64 

In [47]: d2.memory_usage() 
Out[47]: 
Index 80 
0   0 
1   0 
2   0 
3   0 
4   0 
5   0 
6   0 
7   0 
8   0 
9   0 
dtype: int64 

математика:

In [48]: d2 - d1 
Out[48]: 
    0 1 2 3 4 5 6 7 8 9 
0 1 1 0 0 1 1 0 1 1 1 
1 1 1 1 1 1 1 1 1 0 1 
2 1 1 1 1 1 1 1 1 1 1 
3 1 1 1 1 1 1 1 0 1 1 
4 1 1 1 1 1 1 1 1 1 1 
5 0 1 1 1 1 1 1 1 1 1 
6 1 1 1 1 1 1 1 1 1 1 
7 0 1 1 0 1 1 1 0 1 1 
8 1 1 1 1 1 1 0 1 1 1 
9 1 1 1 1 1 1 1 1 1 1 

источника разреженная матрица: использование

In [49]: d1 
Out[49]: 
    0 1 2 3 4 5 6 7 8 9 
0 0 0 1 1 0 0 1 0 0 0 
1 0 0 0 0 0 0 0 0 1 0 
2 0 0 0 0 0 0 0 0 0 0 
3 0 0 0 0 0 0 0 1 0 0 
4 0 0 0 0 0 0 0 0 0 0 
5 1 0 0 0 0 0 0 0 0 0 
6 0 0 0 0 0 0 0 0 0 0 
7 1 0 0 1 0 0 0 1 0 0 
8 0 0 0 0 0 0 1 0 0 0 
9 0 0 0 0 0 0 0 0 0 0 

памяти:

In [50]: (d2 - d1).memory_usage() 
Out[50]: 
Index 80 
0  16 
1   0 
2   8 
3  16 
4   0 
5   0 
6  16 
7  16 
8   8 
9   0 
dtype: int64 

PS если вы не можете построить весь SparseDataFrame сразу (из-за ограничения памяти), вы можете использовать approach similar to one used in this answer