Вычисление скалярного произведения Numpy / Scipy для определенных элементов

У меня есть разреженная матрица вроде A

и dataframe (df) со строками, которые следует брать для вычисления скалярного произведения.

Row1 Row2 Value 2 147 scalar product of vectors at Row1 and Raw2 in matrix A 

Могу ли я сделать это в режиме вещания без циклов и т. Д.?

В моем случае A, как размер 1m * 100k, и dataframe 10M

3 Solutions collect form web for “Вычисление скалярного произведения Numpy / Scipy для определенных элементов”

Начните с небольшой «разреженной» матрицы (csr является лучшим для математики):

 In [167]: A=sparse.csr_matrix([[1, 2, 3], # Vadim's example [2, 1, 4], [0, 2, 2], [3, 0, 3]]) In [168]: AA=AA # dense equivalent In [169]: idx=np.array([[1,1,0,3],[3,0,0,2]]).T # indexes 

Я буду придерживаться версии numpy (Pandas построен поверх numpy)

Мы могли бы взять все продукты строки и выбрать подмножество, определенное idx :

 In [170]: (AA.dot(AA.T))[idx[:,0], idx[:,1]] Out[170]: array([18, 16, 14, 6], dtype=int32) 

Разреженный матричный продукт ( A.dot(AT) также работает:

 In [171]: (A*AT)[idx[:,0], idx[:,1]] Out[171]: matrix([[18, 16, 14, 6]], dtype=int32) 

Или мы можем сначала выбрать строки, а затем взять сумму продуктов. Мы не хотим использовать dot здесь, поскольку мы не принимаем все комбинации.

 In [172]: (AA[idx[:,0]]*AA[idx[:,1]]).sum(axis=1) Out[172]: array([18, 16, 14, 6], dtype=int32) 

Версия einsum этого calc:

 In [180]: np.einsum('ij,ij->i',AA[idx[:,0]],AA[idx[:,1]]) Out[180]: array([18, 16, 14, 6], dtype=int32) 

sparse может сделать то же самое ( * – матричный продукт, .multiply – элемент за элементом).

 In [173]: (A[idx[:,0]].multiply(A[idx[:,1]])).sum(axis=1) Out[173]: matrix([[18], [16], [14], [ 6]], dtype=int32) 

В этом маленьком корпусе плотные версии работают быстрее. Интенсивность разреженных строк медленная.

 In [181]: timeit np.einsum('ij,ij->i', AA[idx[:,0]], AA[idx[:,1]]) 100000 loops, best of 3: 18.1 µs per loop In [182]: timeit (A[idx[:,0]].multiply(A[idx[:,1]])).sum(axis=1) 1000 loops, best of 3: 1.32 ms per loop In [184]: timeit (AA.dot(AA.T))[idx[:,0], idx[:,1]] 100000 loops, best of 3: 9.62 µs per loop In [185]: timeit (A*AT)[idx[:,0], idx[:,1]] 1000 loops, best of 3: 689 µs per loop 

Я почти забыл – итеративные версии:

 In [191]: timeit [AA[i].dot(AA[j]) for i,j in idx] 10000 loops, best of 3: 38.4 µs per loop In [192]: timeit [A[i].multiply(A[j]).sum() for i,j in idx] 100 loops, best of 3: 2.58 ms per loop 

Индексация lil матрицы формата lil выполняется быстрее

 In [207]: Al=A.tolil() In [208]: timeit A[idx[:,0]] 1000 loops, best of 3: 476 µs per loop In [209]: timeit Al[idx[:,0]] 1000 loops, best of 3: 234 µs per loop 

Но к тому времени, когда он будет преобразован обратно в csr для умножения, это может не сэкономить время.

===============

В других недавних вопросах SO я обсуждал более быстрые способы индексирования разреженных строк или столбцов. Но в них конечной целью было суммирование по выбранному набору строк или столбцов. Для этого было бы самым быстрым использовать матричный продукт – с матрицей из 1s и 0s. Применение этой идеи здесь немного сложнее.

Глядя на csr.__getitem__ индексирования csr.__getitem__ , я обнаружил, что она фактически индексирует A[idx,:] с матричным продуктом. Он создает матрицу extractor с функцией, подобной:

 def extractor(indices,N): """Return a sparse matrix P so that P*self implements slicing of the form self[[1,2,3],:] """ indptr = np.arange(len(indices)+1, dtype=int) data = np.ones(len(indices), dtype=int) shape = (len(indices),N) return sparse.csr_matrix((data,indices,indptr), shape=shape) In [328]: %%timeit .....: A1=extractor(idx[:,0],4)*A .....: A2=extractor(idx[:,1],4)*A .....: (A1.multiply(A2)).sum(axis=1) .....: 1000 loops, best of 3: 1.14 ms per loop 

Это время немного лучше, чем у A[idx[:,0],:] ( In[182] ) – предположительно потому, что оно немного упрощает действие. Он должен масштабироваться одинаково.

Это работает, потому что idx0 является булевой матрицей, полученной из [1,1,0,3]

 In [330]: extractor(idx[:,0],4).A Out[330]: array([[0, 1, 0, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]]) In [296]: A[idx[:,0],:].A Out[296]: array([[2, 1, 4], [2, 1, 4], [1, 2, 3], [3, 0, 3]], dtype=int32) In [331]: (extractor(idx[:,0],4)*A).A Out[331]: array([[2, 1, 4], [2, 1, 4], [1, 2, 3], [3, 0, 3]], dtype=int32) 

================

В общем случае, если проблема слишком велика для непосредственного использования плотного массива, то лучше всего использовать масштабирование для большого разреженного случая

 (A[idx[:,0]].multiply(A[idx[:,1]])).sum(axis=1) 

Если это все еще вызывает ошибки памяти, то итерация, возможно, над группами массива idx (или dataframe).

Если я правильно понимаю ваш вопрос, вы можете использовать функцию dot в Pandas для вычисления точечного продукта между двумя рядами:

 A['Row1'].dot(A['Row2']) 

Документация: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dot.html

Я думаю, .assign() подходящим является: .assign() и .apply() (для pandas> 0.16.0):

 import numpy as np from pandas import DataFrame from scipy.sparse import bsr_matrix df = DataFrame(np.random.randint(4, size=(4, 2)), columns=['Row1', 'Row2']) A = bsr_matrix([[1, 2, 3], [2, 1, 4], [0, 2, 2], [3, 0, 3]]) A = A.tocsr() # Skip this if your matrix is csc_, csr_, dok_ or lil_matrix df.assign(Value=df.apply(lambda row: A[row[0]].dot(A[row[1]].transpose())[0, 0], axis=1)) Out[15]: Row1 Row2 Value 0 1 3 18 1 1 0 16 2 0 0 14 3 3 2 6 
  • Проблемы с 2D-интерполяцией в Scipy
  • Вычисление локальных средств в массиве 1D numpy
  • Добавление очень повторяющейся матрицы к разреженной в numpy / scipy?
  • Выбор элементов словаря с помощью ключа эффективно в Python
  • 2d интерполяция в python со случайным пятном
  • Фиксирование (гауссово) со Scipy против ROOT и др.
  • Внедрение Scipy в C
  • Как применить фильтр к сигналу в python
  • Python - лучший язык программирования в мире.