Эффективно задан ряд в SciPy sparse.lil_matrix?

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

В настоящее время матрица и векторы имеют тип scipy.sparse.lil_matrix. Векторы устанавливаются в определенную строку матрицы, используя следующую функцию:

In [7]: us.get_utterance_representation('here is a sentence')
Out[7]:
<1x188796 sparse matrix of type '<type 'numpy.float64'="">'
 with 22489 stored elements in Compressed Sparse Row format>
def set_row_vector(self, row, rowvector):
 self.matrix[row] = rowvector[0]
for row, utterance in enumerate(utterances):
 uvector = self.get_utterance_representation(utterance)
 self.utterancematrix.add_row_vector(row, uvector)
</type>

Где uvector - это lil_matrix размерности 1x ~ 200.000.

Создание матрицы таким образом оказывается крайне неэффективным, когда одна текстовая строка (высказывание) занимает до 5 секунд. Глядя на профилирование, я пришел к выводу, что главной проблемой является установка вектора в виде строки в матрице.

55 def set_row_vector(self, row, rowvector):
 2564609 function calls (2564606 primitive calls) in 5.046 seconds
 Ordered by: internal time
 ncalls tottime percall cumtime percall filename:lineno(function)
 22489 1.397 0.000 1.397 0.000 {numpy.core.multiarray.where}
 22489 0.783 0.000 2.188 0.000 csr.py:281(_get_single_element)
 44978 0.365 0.000 0.916 0.000 stride_tricks.py:35(broadcast_arrays)
 44978 0.258 0.000 0.413 0.000 stride_tricks.py:22(as_strided)
 202490 0.244 0.000 0.244 0.000 {numpy.core.multiarray.array}
 22489 0.199 0.000 2.221 0.000 lil.py:280(__setitem__)
 44978 0.174 0.000 0.399 0.000 sputils.py:171(_unpack_index)
 584777 0.171 0.000 0.171 0.000 {isinstance}
 44988 0.170 0.000 0.230 0.000 sputils.py:115(isintlike)
 67467 0.166 0.000 0.278 0.000 sputils.py:196(_check_boolean)
 22489 0.154 0.000 0.647 0.000 sputils.py:215(_index_to_arrays)
 1 0.129 0.129 5.035 5.035 dsm_classes.py:55(set_row_vector)
 22489 0.120 0.000 0.171 0.000 lil.py:247(_insertat2)
 67467 0.102 0.000 0.102 0.000 {method 'ravel' of 'numpy.ndarray' objects}

Мой вопрос: есть ли лучший способ добиться создания матрицы из высказываний?

(Спасибо)

1 ответ

Во-первых, я думаю, что ваш uvector на самом деле находится в формате CSR, а не LIL. Это, вероятно, самое лучшее:

In [30]: import scipy.sparse as ss
In [31]: row = ss.rand(1,5000,0.1,'csr')
In [32]: matrix = ss.lil_matrix((30,5000))
In [33]: %timeit matrix[0] = row
10 loops, best of 3: 65.6 ms per loop
In [34]: row_lil = row.tolil()
In [35]: %timeit matrix[0] = row_lil
10 loops, best of 3: 93.4 ms per loop

Затем вы можете избежать некоторой стоимости, отбросив индекс [0] на rowvector:

In [38]: %timeit matrix[0] = row[0]
10 loops, best of 3: 104 ms per loop
In [39]: %timeit matrix[0] = row
10 loops, best of 3: 68.7 ms per loop

Наконец, реальное мясо решения заключается в том, чтобы по возможности избегать формата LIL. Хотя это самый гибкий формат, он также самый медленный (обычно). Например, если вы просто пытаетесь построить свою матрицу по одной строке за раз, вы можете использовать scipy.sparse.vstack:

In [40]: %%timeit
 ....: for i in xrange(matrix.shape[0]):
 ....: matrix[i] = row
 ....:
1 loops, best of 3: 3.14 s per loop
In [41]: %timeit ss.vstack([row for i in xrange(matrix.shape[0])])
1000 loops, best of 3: 1.46 ms per loop
In [44]: m2 = ss.vstack([row for i in xrange(matrix.shape[0])])
In [45]: numpy.allclose(matrix.todense(), m2.todense())
Out[45]: True

РЕДАКТИРОВАТЬ. Если память вызывает беспокойство, и вы все еще хотите максимальную скорость, вы можете сделать свой собственный vstack на основе быстрый vstack для CSR-матриц. Я бы начал с копирования функции _compressed_sparse_stack и вызова ее с вашим списком строк CSR и axis = 0. Затем вы сможете изменить его, чтобы вместо итератора вместо него использовать итератор, что позволило бы избежать чрезмерных издержек памяти. Или, вы можете встроить шаги в цикл for. В любом случае, вы потеряете небольшую скорость, но, возможно, сохраните много памяти.

licensed under cc by-sa 3.0 with attribution.