2012-10-05 44 views
2

我正在嘗試爲我的數據創建一個新的距離函數。但是,與stats包的dist函數相比,我的代碼的性能非常低。例如,查看歐幾里得距離的結果:在R中優化我自己的距離函數

mydist = function (x){ 

    euclidean = function (a, b){ 
    sqrt(sum((a-b)^2)) 
    } 

    distances = matrix(0, nrow=nrow(x), ncol=nrow(x)) 
    for (i in 1:nrow(x)) 
    for (j in 1:(i-1)){ # <- corrected this 
     if (j > 0){ 
     distances[i,j]=euclidean(x[i,], x[j,]) 
     distances[j,i]=distances[i,j] 
     } 
    } 

    distances 
} 


m=matrix(1:800, ncol=2) 
system.time(as.dist(mydist(m))) 
    usuário sistema decorrido 
    0.714  0.000  0.716  # <- updated values with corrected version 

system.time(dist(m)) 
    usuário sistema decorrido 
    0.004  0.000  0.002 

我不會使用歐幾里得距離。例如,我正在開發一個新的,使用一些特定於我的數據的統計信息,比代理包的數據更加複雜。數據集中有數百個變量和數千個示例(行)。不能等待幾個小時來計算距離。

我已經嘗試使用外與應用的另一個代碼。它比兩個循環更快,但仍然非常慢。任何人都可以提出任何建議嗎?

+0

除非您使用一些全新的距離度量標準,否則您可能會更好地探索維基百科。在R和/或C中有現有代碼的度量函數有很多。您的距離函數實際上是時間瓶頸嗎?在選擇將其應用於數據集的方法之前,也應該確定這一點。 –

回答

1

超速的事情了,關鍵是

  • 或者您的距離函數可以很容易地量化。如果是這樣的話,看看? outer,和/或? rep
    這種方法可以相當快,但也消耗內存。

  • apply會將兩個循環基本上歸結爲一個,但實際的向量化通常要快得多。

  • 或者您可能想要使用例如內聯C代碼,請參閱內聯包。

  • 您意外地計算了所需距離的兩倍(您進行對稱複製,但ij均循環遍歷整個1 : nrow (x))。

2

的關鍵是從整個矩陣而不是每個單獨的行中減去每一行。由於減法是按列方式完成的,因此只需轉置矩陣。

m=matrix(1:800, ncol=2) 
system.time(a<-as.dist(mydist(m))) 
# user system elapsed 
# 1.32 0.00 1.32 

t.m<-t(m) 
system.time(x<-as.dist(apply(m,1,function(x) sqrt(colSums((x - t.m)^2))))) 
# user system elapsed 
# 0.04 0.00 0.03 

any(x!=a) # FALSE 

但是,如果你真的想要速度,你應該使用C庫。

+0

@ user1348438:我明白,這裏的歐幾里得函數只是對其他函數的最小替換?你能澄清一下嗎? – cbeleites