Получить норму пустых разреженных строк матрицы
У меня есть разреженная матрица, которую я получил с помощью объекта Sklearn's TfidfVectorizer:
vect = TfidfVectorizer(sublinear_tf=True, max_df=0.5, analyzer='word', vocabulary=my_vocab, stop_words='english')
tfidf = vect.fit_transform([my_docs])
Разреженная матрица (вычтя числа для общности):
<sparse matrix of type '<type 'numpy.float64'>'
with stored elements in Compressed Sparse Row format>]
Я пытаюсь получить числовое значение для каждой строки, чтобы сказать мне, насколько высоко в документе были условия, которые я ищу. Меня не волнует, в каких словах оно содержится, я просто хочу знать, сколько в нем слов. Поэтому я хочу получить норму для каждой строки или строки. Тем не менее, мне очень трудно работать с NumPy, чтобы получить это.
Мой первый подход был просто сделать:
tfidf[i] * numpy.transpose(tfidf[i])
Тем не менее, NumPy, по-видимому, не будет транспонировать массив с менее чем одним измерением, так что он будет просто квадрат вектора Итак, я попытался сделать:
tfidf[i] * numpy.transpose(numpy.atleast_2d(tfidf[0]))
Но numpy.transpose(numpy.atleast_2d(tfidf[0])) по-прежнему не будет транспонировать строку.
Я перешел к попытке получить норму ряда (этот подход, вероятно, лучше в любом случае). Мой первоначальный подход был с использованием numpy.linalg.
numpy.linalg.norm(tfidf[0])
Но это дало мне ошибку "несоответствие размеров". Поэтому я попытался вычислить норму вручную. Я начал с того, что просто установил переменную, равную версии массива с разреженной матрицей, и распечатал len первой строки:
my_array = numpy.array(tfidf)
print my_array
print len(my_array[0])
Он правильно печатает my_array, но когда я пытаюсь получить доступ к len, он говорит мне:
IndexError: 0-d arrays can't be indexed
Я просто хочу получить числовое значение каждой строки в разреженной матрице, возвращаемой fit_transform. Получение нормы было бы лучше всего. Любая помощь здесь очень ценится.
2 ответа
Некоторые простые фальшивые данные:
a = np.arange(9.).reshape(3,3)
s = sparse.csr_matrix(a)
Чтобы получить норму каждого ряда из разреженных, вы можете использовать:
np.sqrt(s.multiply(s).sum(1))
И перенормированный s
было бы
s.multiply(1/np.sqrt(s.multiply(s).sum(1)))
или сохранить его редким перед перенормировкой:
s.multiply(sparse.csr_matrix(1/np.sqrt(s.multiply(s).sum(1))))
Чтобы получить из нее обычную матрицу или массив, используйте:
m = s.todense()
a = s.toarray()
Если у вас достаточно памяти для плотной версии, вы можете получить норму каждой строки с помощью:
n = np.sqrt(np.einsum('ij,ij->i',a,a))
или же
n = np.apply_along_axis(np.linalg.norm, 1, a)
Для нормализации можно сделать
an = a / n[:, None]
или, чтобы нормализовать исходный массив на месте:
a /= n[:, None]
[:, None]
вещь в основном переносит n
быть вертикальным массивом.
scipy.sparse
Это отличный пакет, и он продолжает улучшаться с каждым выпуском, но многие вещи еще только наполовину приготовлены, и вы можете добиться значительных улучшений производительности, если сами реализуете некоторые алгоритмы. Например, 7-кратное улучшение по сравнению с реализацией @askewchan с использованием функций scipy:
In [18]: a = sps.rand(1000, 1000, format='csr')
In [19]: a
Out[19]:
<1000x1000 sparse matrix of type '<type 'numpy.float64'>'
with 10000 stored elements in Compressed Sparse Row format>
In [20]: %timeit a.multiply(a).sum(1)
1000 loops, best of 3: 288 us per loop
In [21]: %timeit np.add.reduceat(a.data * a.data, a.indptr[:-1])
10000 loops, best of 3: 36.8 us per loop
In [24]: np.allclose(a.multiply(a).sum(1).ravel(),
...: np.add.reduceat(a.data * a.data, a.indptr[:-1]))
Out[24]: True
Вы можете аналогичным образом нормализовать массив, выполнив следующие действия:
norm_rows = np.sqrt(np.add.reduceat(a.data * a.data, a.indptr[:-1]))
nnz_per_row = np.diff(a.indptr)
a.data /= np.repeat(norm_rows, nnz_per_row)
Если вы собираетесь часто использовать разреженные матрицы, прочитайте страницу википедии о сжатых разреженных форматах, и вы часто найдете более эффективные способы, чем по умолчанию.
Как насчет использования собственного scipy API scipy.sparse.linalg.norm
?
Подробнее читайте на https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.norm.html.