建議

2010-11-21 50 views
5

考慮下面的類:建議

class SquareErrorDistance(object): 
    def __init__(self, dataSample): 
     variance = var(list(dataSample)) 
     if variance == 0: 
      self._norm = 1.0 
     else: 
      self._norm = 1.0/(2 * variance) 

    def __call__(self, u, v): # u and v are floats 
     return (u - v) ** 2 * self._norm 

我用它來計算一個矢量的兩個元素之間的距離。我基本上爲使用此距離度量的向量的每個維度創建該類的一個實例(有使用其他距離度量的維度)。分析表明,這個類的功能佔我knn實現的運行時間的90%(誰會想到)。我不認爲有任何純Python的方式來加速,但也許如果我在C中實現它?

如果我運行一個簡單的C程序,它使用上面的公式計算隨機值的距離,它比Python快幾個數量級。所以我嘗試使用ctypes並調用一個執行計算的C函數,但顯然參數和返回值的轉換遠遠要昂貴,因爲結果代碼要慢得多。

我當然可以在C中實現整個kn並且只是調用它,但問題是,就像我所描述的,我使用不同的距離函數來處理矢量的某個維度,並且將這些轉換爲C會太多工作。

那麼我的替代方案是什麼?使用Python C-API編寫C函數會擺脫開銷嗎?有沒有其他的方法來加速這個計算?

+0

我會建議Cython(答案與示例實現可能會在幾分鐘內)。我猜你算法已經儘可能地調整過了嗎? – delnan 2010-11-21 18:09:24

+0

@delnan:我已經在可能和適當的地方使用了緩存,所以我沒有看到任何保存距離計算的方法。 – 2010-11-21 18:17:48

+0

那麼......無關,什麼是'dataSample'和'var'? – delnan 2010-11-21 18:21:52

回答

1

下面用Cython代碼(我知道的__init__第一線不同的是,我用隨機的東西,因爲它取代我不知道var因爲它不怎樣都無所謂 - 你說__call__是瓶頸):通過一個簡單的setup.py(只是the example from the docs結構改變文件名)編譯

cdef class SquareErrorDistance: 
    cdef double _norm 

    def __init__(self, dataSample): 
     variance = round(sum(dataSample)/len(dataSample)) 
     if variance == 0: 
      self._norm = 1.0 
     else: 
      self._norm = 1.0/(2 * variance) 

    def __call__(self, double u, double v): # u and v are floats 
     return (u - v) ** 2 * self._norm 

,它在一個簡單的調查timeit基準測試中,它的性能比同等級的純Python高出近20倍。請注意,唯一更改爲cdef s的_norm字段和__call__參數。我認爲這很令人印象深刻。

+0

**這是 - 令人驚歎**。非常感謝。我實際上可以將這個(意思是Cython)應用於許多其他熱點。你只是讓我的一天:) – 2010-11-21 19:09:00

+1

@ Space_C0wb0y:總是很高興幫助:)如果你使用numpy重,也可以看看http://docs.cython。組織/ src目錄/教程/ numpy.html。 – delnan 2010-11-21 19:26:36

+0

您也可以聲明差異爲雙倍。它可能不會有很大的區別,但爲什麼不呢? – 2010-11-22 03:27:03

0

這可能幫助不大,但可以將其使用嵌套函數改寫:

def SquareErrorDistance(dataSample): 
    variance = var(list(dataSample)) 
    if variance == 0: 
     def f(u, v): 
      x = u - v 
      return x * x 
    else: 
     norm = 1.0/(2 * variance) 
     def f(u, v): 
      x = u - v 
      return x * x * norm 
    return f