2016-05-15 21 views
0

我有一個稀疏矩陣像甲numpy的/ SciPy的廣播計算標量積爲一定的元件

和數據幀(DF)與應採取計算標量積的行。

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

我可以用循環播放的方式嗎?

在我的情況。類似的1M * 100K大小和數據框10M

+0

你有哪些稀疏矩陣類? –

+0

在我的情況並不重要,我可以很容易地將其轉換爲適當的類型。 – sh1ng

+0

用小'df'和矩陣(可能是密集的)展示。 – hpaulj

回答

0

開始用小 '疏' 矩陣(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=A.A # dense equivalent 

In [169]: idx=np.array([[1,1,0,3],[3,0,0,2]]).T # indexes 

我會與numpy的版本棒(熊貓是建立在numpy的頂部)

我們可以把所有的行點的產品,並選擇確定一個子組idx

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

稀疏矩陣產品(A.dot(A.T)也可以工作:

In [171]: (A*A.T)[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的這個版本的計算值:

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*A.T)[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格式的矩陣更快

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問題,我已經討論稀疏索引的行或列的更快的方法。但在那些最終目標是總結一組選定的行或列。爲此,使用矩陣產品實際上是最快的 - 具有1和0的矩陣。在這裏應用這個想法有點棘手。

看看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) 

如果這仍然產生存儲器錯誤,則迭代,可能在的0組數組(或數據幀)。

+0

你的例子中有一部分是無關緊要的,我不能計算點積(A.dot(AT)),因爲它會導致我的內存不足,最後我用A [df.Row1] .multiply(A [df .Row2])。sum(axis = 1)。也可以用愛因斯坦和來完成,但我沒有嘗試過。 – sh1ng

0

如果我正確理解你的問題,你可以使用dot功能大熊貓來計算兩個系列之間的點積:

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

文檔: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dot.html

+0

我不確定,矩陣A是一個包含向量座標的scipy稀疏矩陣。 dataframe(df)包含該矩陣中的位置。 – sh1ng

+0

這使事情變得更加混亂。我沒有看到稀疏矩陣如何包含「矢量座標」。稀疏矩陣是數字矩陣(2d)。 – hpaulj

0

我想.assign().apply()和(大熊貓> 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 
+0

是不是'df.apply'的一種迭代形式?用'df'的每一行緩慢的稀疏矩陣索引? – hpaulj

+0

我無法說出'df.apply'的確切工作方式,但它的確定速度比......快。 'df.iterrows':應用於具有10^4行df.apply的'df'(lambda行:...'給出'3個循環,最好是每個循環3:820 ms',而具有'df的相同輸出。 iterrows' - '3個循環,每個循環最好3:921 ms'。將'df'轉換爲'np.matrix'和'np.apply_along_axis'甚至更好:'3個循環,每個循環最好3:709 ms' 。我不知道如何避免緩慢的稀疏矩陣索引 –

+0

我熟悉'apply_along_axis'迭代的方式。看起來像熊貓有更多的開銷。 – hpaulj