2012-11-19 73 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