2016-04-03 7 views
0

です。これは古典的な質問ですが、私はまだ多くの人が答えを探していると信じています。 この質問はthis oneとは異なります。なぜなら私の質問は、2つの疎なベクトル(行列ではない)の間の操作だからです。高速Python Cosineの相違点はScipy CSR "vectors"

データの次元が高くなると(高密度ベクトルで動作するため)、Cosine Scipy Spatial Distance(SSD)がどのように遅くなっているかについて、blog postと書きました。ポストはインドネシア語ですが、コード、私の実験設定&の結果は言語にかかわらず(ポストの下に)簡単に理解できるはずです。

現在、このソリューションは&より多くのメモリ効率的な(SSDに比べて)高次元データのために70回以上高速である:

import numpy as np 

    def fCosine(u,v): # u,v CSR vectors, Cosine Dissimilarity 
     uData = u.data; vData = v.data 
     denominator = np.sqrt(np.sum(uData**2)) * np.sqrt(np.sum(vData**2)) 
     if denominator>0: 
      uCol = u.indices; vCol = v.indices # np array 
      intersection = set(np.intersect1d(uCol,vCol)) 
      uI = np.array([u1 for i,u1 in enumerate(uData) if uCol[i] in intersection]) 
      vI = np.array([v2 for j,v2 in enumerate(vData) if vCol[j] in intersection])    
      return 1-np.dot(uI,vI)/denominator 
     else: 
      return float("inf") 

は、それはさらに(Python的にその機能を改善したり、JIT/Cythonを経由することは可能です???)。ここで

答えて

1

およそ3倍速くサイズ10**510**4非ゼロ要素のCSRベクトルのためである(私のマシン上で)、代替、alt_fCosineです:

import scipy.sparse as sparse 
import numpy as np 
import math 

def fCosine(u,v): # u,v CSR vectors, Cosine Dissimilarity 
    uData = u.data; vData = v.data 
    denominator = np.sqrt(np.sum(uData**2)) * np.sqrt(np.sum(vData**2)) 
    if denominator>0: 
     uCol = u.indices; vCol = v.indices # np array 
     intersection = set(np.intersect1d(uCol,vCol)) 
     uI = np.array([u1 for i,u1 in enumerate(uData) if uCol[i] in intersection]) 
     vI = np.array([v2 for j,v2 in enumerate(vData) if vCol[j] in intersection])    
     return 1-np.dot(uI,vI)/denominator 
    else: 
     return float("inf") 

def alt_fCosine(u,v): 
    uData, vData = u.data, v.data 
    denominator = math.sqrt(np.sum(uData**2) * np.sum(vData**2)) 
    if denominator>0: 
     uCol, vCol = u.indices, v.indices 
     uI = uData[np.in1d(uCol, vCol)] 
     vI = vData[np.in1d(vCol, uCol)] 
     return 1-np.dot(uI,vI)/denominator 
    else: 
     return float("inf") 

# Check that they return the same result 
N = 10**5 
u = np.round(10*sparse.random(1, N, density=0.1, format='csr')) 
v = np.round(10*sparse.random(1, N, density=0.1, format='csr')) 
assert np.allclose(fCosine(u, v), alt_fCosine(u, v)) 

alt_fCosineは、2つのリストの内包表記の呼び出しを置き換えますnp.intersection1d と、np.in1dへの2つの呼び出しと高度な の呼び出しを含むPythonセットの形成。 N = 10**5については


In [322]: %timeit fCosine(u, v) 
100 loops, best of 3: 5.73 ms per loop 

In [323]: %timeit alt_fCosine(u, v) 
1000 loops, best of 3: 1.62 ms per loop 

In [324]: 5.73/1.62 
Out[324]: 3.537037037037037 
+0

恐ろしいmath.sqrtがnumpy.sqrtよりも高速である理由、本当にありがとうございました... は、私が疑問に思いますか? 一般的に単純なドメイン(スカラー/リスト)の方が数学は高速ですか? – taufikedys

+0

はい、 'math.sqrt'はスカラーにとって高速です。対応するNumPy関数とは異なり、代替コードパスをテストする必要はありません(配列の場合、繰り返し可能な場合など)ので、これは 'math'モジュールのすべての関数にも当てはまります。 – unutbu