-->

重复距离矩阵计算有效(存储器明智)功能和额外大的距离的矩阵分块(Efficient (memory-

2019-07-03 23:05发布

我不知道是否有人可以看看下面的代码和小例子,并提出改进建议 - 与真正的大数据集时在代码中的特别是关于效率。

该函数采用一个data.frame和由分组变量(因子)拆分,然后计算每个组中的所有行的距离矩阵。

我并不需要保持距离矩阵 - 只有一些统计数据即平均值,直方图..,那么他们可以被丢弃。

我不知道很多关于内存分配等,我想知道什么是做到这一点的最好办法,因为我将与10.000合作 - 100.000每组病例。 任何想法将不胜感激!

此外,这将是包括bigmemory或其他一些大型的数据处理包入的功能是万一我遇到严重的内存问题的最痛苦的样子?

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

编辑:我编辑了标题,以反映分块问题我张贴作为一个答案..

Answer 1:

我拿出那些特大型矩阵是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"

该函数计算体的平均距离,但你可以改变其他任何事情,但如果你想真正拯救我相信某种filebacked bigmemory矩阵是为了矩阵..荣誉对链接的想法和阿里他的帮助!

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)

不知道我是否应该已经张贴此作为一个编辑,而不是答案。它确实解决了我的问题,但我真的不指定它这样..



Answer 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更改为类似: 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作为替代矩阵等)



文章来源: Efficient (memory-wise) function for repeated distance matrix calculations AND chunking of extra large distance matrices