Норма разреженных векторов питона
Можно ли эффективно получить норму разреженного вектора в питоне?
Я попробовал следующее:
from scipy import sparse
from numpy.linalg import norm
vector1 = sparse.csr_matrix([ 0 for i in xrange(4000000) ], dtype = float64)
#just to test I set a few points to a value higher than 0
vector1[ (0, 10) ] = 5
vector1[ (0, 1500) ] = 80
vector1[ (0, 2000000) ] = 6
n = norm(t1)
но тогда я получаю ошибку:
ValueError: dimension mismatch
Функция нормы работает только с массивами, поэтому, вероятно, именно поэтому csr_matrix не работает, но тогда я не нашел другого способа эффективного вычисления нормы. Одним из возможных решений будет вычисление:
norm(asarray(vector1.todense()))
но тогда это сначала убивает цель использования разреженных векторов. И в качестве последнего подхода я мог бы пройтись по каждому элементу вектора и вручную вычислить норму, но, поскольку эффективность действительно важна, я искал что-то более быстрое и простое в реализации.
Заранее благодарю за любую помощь!
РЕДАКТИРОВАТЬ: Я попробовал все, что было предложено, и лучшее решение:
(vector1.data ** 2).sum()
из Дугала. Но решение Cython также очень хорошо и работает лучше, так как вектор растет в количестве элементов, отличных от нуля. Спасибо всем за помощь!
3 ответа
- Я надеюсь, что вы на самом деле не инициализируете и не настраиваете подобные элементы, эти предупреждения появляются по определенной причине, а временный список 4M подтверждает, что у вас достаточно ресурсов;).
- Вычисление нормы вручную очень просто, просто используя базовые данные
vector1.data
непосредственно. Вы также можете использовать такие вещи, какvector1.multiply(vector1)
плюс.sum
или жеvector1.dot(vector1.T)
но, как указал Дугал, в этом простом случае это может быть намного медленнее. - Я предполагаю, что вы хотите сделать больше, но если вы хотите только векторные нормы, прохождение разреженных матриц кажется большой ненужной работой.
У меня просто была та же проблема, я реализовал функцию в Cython для увеличения скорости этой простой операции. Я проверил это с разреженным вектором 4M двойных чисел с ненулевыми элементами 100k. Метод с использованием sqrt(vector.multiply(vector).sum()) использовал 874us и мою функцию 205us.
# sparseLib.pyx
#cython: boundscheck=False
from cython.parallel cimport prange
from cython.view cimport array as cvarray
import numpy as np
from libc.math cimport sqrt
cpdef double sparseNorm2(double [:] data) nogil:
cdef long i
cdef double value = 0.0
for i in xrange(data.shape[0]):
value += data[i]*data[i]
return sqrt(value)
Я не думаю, что ваша инициализация делает то, что вы думаете.
Чтобы норма работала, вам нужно иметь квадратный массив. Если вы пытаетесь создать квадратный массив с 4 миллионами элементов, вы хотите сделать
csr_matrix( (2000,2000), dtype=float64)
полная документация для инициализации у scipy