2012-11-19 78 views
2

我不知道是否有人可以看看下面的代碼和最小的例子,並提出改進建議 - 特別是關於工作時代碼的效率具有非常大的數據集。重複距離矩陣計算的高效(記憶方式)功能和超大距離矩陣的分塊

該函數接受一個data.frame並將其拆分爲一個分組變量(factor),然後計算每個組中所有行的距離矩陣。

我不需要保留距離矩陣 - 只有一些統計數據,即均值,直方圖..,然後他們可以被丟棄。

我對存儲器分配等知之甚少,不知道怎麼做纔是最好的辦法,因爲我將每組處理10.000 - 100.000個案例。任何想法將不勝感激!

另外,如果遇到嚴重的內存問題,將大內存或其他大型數據處理軟件包包含到函數中會是最痛苦的方式嗎?

FactorDistances <- function(df) { 
    # df is the data frame where the first column is the grouping variable. 
    # find names and number of groups in df (in the example there are three:(2,3,4) 
    factor.names <- unique(df[1]) 
    n.factors <-length(unique(df$factor)) 
    # split df by factor into list - each subset dataframe is one list element 
    df.l<-list() 
    for (f in 1:n.factors) {df.l[[f]]<-df[which(df$factor==factor.names[f,]),]} 
    # use lapply to go through list and calculate distance matrix for each group 
    # this results in a new list where each element is a distance matrix 
    distances <- lapply (df.l, function(x) dist(x[,2:length(x)], method="minkowski", p=2)) 
    # again use lapply to get the mean distance for each group 
    means <- lapply (distances, mean) 
    rm(distances) 
    gc() 
    return(means) 
} 

df <- data.frame(cbind(factor=rep(2:4,2:4), rnorm(9), rnorm(9))) 
FactorDistances(df) 
# The result are three average euclidean distances between all pairs in each group 
# If a group has only one member, the value is NaN 

編輯:我編輯了標題,以反映分塊問題我張貼作爲一個答案..

+0

翻翻碼,我開始懷疑它可能沒有做你想要完成的事情。然而,在代碼中缺乏任何評論使我們無法理解你認爲每條線將構建什麼。 –

+0

對不起,我現在添加了評論(並清除了一些混亂) - 希望現在更清楚! – maja

回答

4

我想出了一個塊的解決方案,那些特大型矩陣dist()如果有其他人發現它有幫助(或者認爲它有問題,請!)。它比DIST()顯著慢,但就是那種無關緊要的,因爲它應該永遠只能使用時DIST()拋出一個錯誤 - 通常是下列之一:

"Error in double(N * (N - 1)/2) : vector size specified is too large" 
"Error: cannot allocate vector of size 6.0 Gb" 
"Error: negative length vectors are not allowed" 

的函數計算的平均距離對於矩陣,但你可以將其改變爲其他任何東西,但是如果你想實際保存矩陣,我相信某種類型的文件備份bigmemory矩陣是爲了..爲這個想法和阿里幫助他的榮譽link

FunDistanceMatrixChunking <- function (df, blockSize=100){ 
    n <- nrow(df) 
    blocks <- n %/% blockSize 
    if((n %% blockSize) > 0)blocks <- blocks + 1 
    chunk.means <- matrix(NA, nrow=blocks*(blocks+1)/2, ncol= 2) 
    dex <- 1:blockSize 
    chunk <- 0 
    for(i in 1:blocks){  
    p <- dex + (i-1)*blockSize 
    lex <- (blockSize+1):(2*blockSize) 
    lex <- lex[p<= n] 
    p <- p[p<= n] 
    for(j in 1:blocks){ 
     q <- dex +(j-1)*blockSize 
     q <- q[q<=n]  
     if (i == j) {  
     chunk <- chunk+1 
     x <- dist(df[p,]) 
     chunk.means[chunk,] <- c(length(x), mean(x))} 
     if (i > j) { 
     chunk <- chunk+1 
     x <- as.matrix(dist(df[c(q,p),]))[lex,dex] 
     chunk.means[chunk,] <- c(length(x), mean(x))} 
    } 
    } 
    mean <- weighted.mean(chunk.means[,2], chunk.means[,1]) 
    return(mean) 
} 
df <- cbind(var1=rnorm(1000), var2=rnorm(1000)) 
mean(dist(df)) 
FunDistanceMatrixChunking(df, blockSize=100) 

不知道我是否應該已經張貼此作爲一個編輯,而不是答案。它確實解決了我的問題,但我真的不指定它這樣..

+0

發佈它作爲答案是正確的電話。感謝您將您的解決方案帶回社區。 –

2

的一點想法:

  • unique(df[1])可能工作(通過忽略data.frame財產你的名單),但讓我緊張,很難閱讀。 unique(df[,1])會更好。
  • for (f in 1:n.factors) {df.l[[f]]<-df[which(df$factor==factor.names[f,]),]}可以用split完成。
  • 如果您擔心內存,絕對不要存儲每個級別的整個距離矩陣,然後計算每個因子級別的總結統計數據!將你的樂器改成如下形式:lapply (df.l, function(x) mean(dist(x[,2:length(x)], method="minkowski", p=2)))

如果你需要一個以上的彙總統計,同時計算並返回一個列表:

lapply (df.l, function(x) { 
    dmat <- dist(x[,2:length(x)], method="minkowski", p=2) 
    list(mean=mean(dmat), median=median(dmat)) 
}) 

看看是否能在任何地方得到你。如果沒有,你可能需要更專業化(避免lapply,存儲你的data.frames矩陣代替,等等)

+0

(1.)'split',當然! (2.),而你最後一段代碼正是我所尋找的,因爲我計算的不僅僅是平均值,而且不知道如何讓它們出來! (3.)雖然代碼現在可以在合理的大小下正常工作,但它確實以「無法分配2.9 Gb大小的向量」結束,所以我需要找到另一種解決方案。你是什​​麼意思,「避免lapply?」我不認爲data.frames是一個內存明智的問題,只是距離矩陣.. – maja

+0

您可能與'lapply'一致,取決於垃圾收集是否在輪之間運行(它可能會...... R是相當不錯)。所以不要擔心這一點。對於你的2.9Gb問題,我想知道哪個組觸發了錯誤,並且自己運行了距離矩陣計算。如果仍然產生錯誤,那麼你知道在哪裏集中。或者只是獲得一個擁有大量內存的Amazon EC2集羣並在其上運行它。 2.9Gb不是*那麼大。 –

+0

謝謝!錯誤是由一個40Kby40K的距離矩陣觸發的,但除了上面的組之外,我還打算做所有的對(200K),希望不採取抽樣。在我嘗試EC2之前,我會嘗試以塊形式進行。我需要手段,但也需要直方圖,但如果我確保休息時間相同,我可以「總結」一下。我發現這個[鏈接](http://stevemosher.wordpress.com/2012/04/12/nick-stokes-distance-code-now-with-big-memory/)看起來很有幫助,雖然我是不知道我可以從filebacked.big.matrix中獲得直方圖,所以我將從塊選項開始。 – maja