2014-04-01 73 views
0

用Cython功能我想轉換原來的Python功能的一部分,用Cython提高了計算時間。我想爲循環組件編寫一個cython函數,因爲它佔用了時間(正如ipython lprun慷慨地告訴我的那樣)。然而,這個函數需要不同大小的矩陣..我看不出如何輕鬆地將它們傳遞給靜態類型的cython。可變大小的矩陣輸入

for index1 in range(0,num_products): 
    for index2 in range(0,num_products): 
     cond_prob = (data[index1] * data[index2]).sum()/max(col_sums[index1], col_sums[index2]) 
     prox[index1][index2] = cond_prob 

此問題是由於num_products每年都會發生變化,所以矩陣(數據)大小是可變的。

什麼是最好的策略嗎?

  1. 我應該寫兩個C函數。一個使用memalloc創建一個特定維度的矩陣,然後一個在所創建的矩陣上執行循環?
  2. 在這種情況下是否有一些花哨的cython/numpy巫術來幫助?我可以編寫一個C函數來獲取內存中可變大小的Numpy Array並傳遞大小嗎?
+1

喜還用Cython你可以做的東西像num_products = data.shape [0]或類似的,所以你的循環的長度將適合你。不過,我不太確定你將要改進循環的方式將會非常有用,因爲你在cython循環中使用了numpy函數。你在努力做什麼似乎非常直截了當......以上表達式是你的原始python代碼?因爲如果是這樣,你可以通過忽略for循環來優化它,從而使其更快。 – Magellan88

+0

有幾個問題:數組'data'和'prox'的「形狀」是什麼?他們都是數組嗎? 'num_products'通常有多大? –

+0

感謝您的意見。好點重新:矢量化而不是循環numpy數組!數據=(170 x 800),因此prox是800 x 800 – sanguineturtle

回答

3

用Cython碼是(戰略)靜態類型,但是這並不意味着數組必須有一個固定的大小。在傳統的C傳遞多維數組的功能,可也許有點尷尬,但在用Cython你應該能夠做到像下面這樣:

注意我把函數和變量名從你的follow-up question.

import numpy as np 
cimport numpy as np 
cimport cython 

@cython.boundscheck(False) 
@cython.cdivision(True) 
def cooccurance_probability_cy(double[:,:] X): 
    cdef int P, i, j, k 
    P = X.shape[0] 
    cdef double item 
    cdef double [:] CS = np.sum(X, axis=1) 
    cdef double [:,:] D = np.empty((P, P), dtype=np.float) 

    for i in range(P): 
     for j in range(P): 
      item = 0 
      for k in range(P): 
       item += X[i,k] * X[j,k] 
      D[i,j] = item/max(CS[i], CS[j]) 
    return D 

在另一方面,只使用numpy的也應該是這個問題相當快,如果你使用了正確的功能和一些廣播。事實上,由於計算複雜度由矩陣乘法爲主,我發現下面的比用Cython碼以上(np.inner採用了高度優化的BLAS例程)要快得多:

def new(X): 
    CS = np.sum(X, axis=1, keepdims=True) 
    D = np.inner(X,X)/np.maximum(CS, CS.T) 
    return D 
+0

優秀的解釋:Cython ...我已經更新了後續問題(http:// stackoverflow。COM /問題/ 22853837 /爲什麼 - 犯規 - numba - 提高 - 這迭代)與你用Cython功能 – sanguineturtle

+0

@sanguineturtle,在此期間我編輯我的答案:原來,禁用範圍檢查在顯著更好的性能用Cython作用的結果。我還發現,普通的Numpy仍然更快,你應該檢查'')'' –

2

您是否嘗試過擺脫了在numpy的循環?

你方程式的第一部分,例如,你可以嘗試:

(data[ np.newaxis,:] * data[:,np.newaxis]).sum(2) 

如果記憶是一個問題,你也可以使用np.einsum()函數。 對於第二部分,如果你還沒有嘗試過,可能還可能會製造出一種粗糙的表情(比較困難)。

+0

好主意! ...明天我會試試這個帖子 – sanguineturtle