2016-10-06 42 views
3

考慮分數爲S的大型數據框,其中包含以下條目。每行代表參與者A,B,CD的子集之間的比賽。在Python中進行高效的大規模競爭評分

A  B C D 
0.1 0.3 0.8 1 
    1 0.2 NaN NaN 
0.7 NaN 2 0.5 
NaN 4 0.6 0.8 

閱讀上述矩陣的方法是:看第一行,參與者A在這輪得分0.1B打進0.3,等等。

我需要建立一個三角矩陣C其中C[X,Y]存儲多少好參與者X比參與者Y。更具體地說,C[X,Y]將保持XY之間的得分差異的平均值%。

從上面的例子:

C[A,B] = 100 * ((0.1 - 0.3)/0.3 + (1 - 0.2)/0.2) = 33% 

我的矩陣S是巨大的,所以我希望能採取JIT的優勢(Numba?)或內置在numpypandas方法。我當然想避免嵌套循環,因爲S有數百萬行。

上述有效算法是否有名稱?

回答

3

讓我們來看一個基於NumPy的解決方案,因此我們假設輸入數據位於名爲a的數組中。現在,4個這樣的變量的成對組合的數目將是4*3/2 = 6。我們可以使用np.triu_indices()生成與這些組合對應的ID。然後,我們用這些指數索引a列。我們執行減法和除法,並簡單地將忽略受NaN影響的結果的列與np.nansum()一起添加爲期望的輸出。

因此,我們必須像這樣的實現 -

R,C = np.triu_indices(a.shape[1],1) 
out = 100*np.nansum((a[:,R] - a[:,C])/a[:,C],0) 

採樣運行 -

In [121]: a 
Out[121]: 
array([[ 0.1, 0.3, 0.8, 1. ], 
     [ 1. , 0.2, nan, nan], 
     [ 0.7, nan, 2. , 0.5], 
     [ nan, 4. , 0.6, 0.8]]) 

In [122]: out 
Out[122]: 
array([ 333.33333333, -152.5  , -50.  , 504.16666667, 
     330.  , 255.  ]) 

In [123]: 100 * ((0.1 - 0.3)/0.3 + (1 - 0.2)/0.2) # Sample's first o/p elem 
Out[123]: 333.33333333333337 

如果需要輸出爲(4,4)陣列,我們可以使用Scipy's squareform -

In [124]: from scipy.spatial.distance import squareform 

In [125]: out2D = squareform(out) 

讓我們轉換爲熊貓數據框以獲得良好的視覺反饋 -

In [126]: pd.DataFrame(out2D,index=list('ABCD'),columns=list('ABCD')) 
Out[126]: 
      A   B   C D 
A 0.000000 333.333333 -152.500000 -50 
B 333.333333 0.000000 504.166667 330 
C -152.500000 504.166667 0.000000 255 
D -50.000000 330.000000 255.000000 0 

讓我們手工計算[B,C],並檢查回來 -

In [127]: 100 * ((0.3 - 0.8)/0.8 + (4 - 0.6)/0.6) 
Out[127]: 504.1666666666667