1

我需要创建约 110 个双精度为 19347 x 19347 的协方差矩阵,然后将它们加在一起。

这本身并不是很困难,对于较小的矩阵,以下代码可以正常工作。

covmat <- matrix(0, ncol=19347, nrow=19347)
files<-list.files("path/to/folder/")
for(name in files){
  text <- readLines(paste("path/to/folder/", name, sep=""),  n=19347, encoding="UTF-8")
   for(i in 1:19347){
    for(k in 1:19347){
      covmat[i, k]  <- covmat[i,k] + (as.numeric(text[i]) * as.numeric(text[k]))
    }
  }
}

为了节省内存,我不计算每个单独的矩阵,而是在遍历每个文件时将它们加在一起。

问题是当我在需要使用的真实数据上运行它时,它花费的时间太长了。实际上没有那么多数据,但我认为这是一项 CPU 和内存密集型工作。因此运行它约 10 小时不会计算结果。

我曾考虑尝试使用 Map Reduce (AWS EMR),但我得出的结论是,我认为这不是 Map Reduce 问题,因为它不是大数据问题。但是,如果我做错了,这是我一直在使用的映射器和减速器的代码。

#Mapper
text <- readLines("stdin",  n=4, encoding="UTF-8")
covmat <- matrix(0, ncol=5, nrow=5)

for(i in 1:5){
  for(k in 1:5){
     covmat[i, k]  <- (as.numeric(text[i]) * as.numeric(text[k]))
  }
}

cat(covmat)

#Reducer
trimWhiteSpace <- function(line) gsub("(^ +)|( +$)", "", line)
splitIntoWords <- function(line) unlist(strsplit(line, "[[:space:]]+"))
final <- matrix(0, ncol=19347, nrow=19347)
## **** could wo with a single readLines or in blocks
con <- file("stdin", open = "r")
while (length(line <- readLines(con, n = 1, warn = FALSE)) > 0) {

    line <- trimWhiteSpace(line)
    words <- splitIntoWords(line)
    final <- final + matrix(as.numeric(words), ncol=19347, nrow=19347)
}
close(con)
cat(final)

谁能建议如何解决这个问题?

提前致谢

编辑

感谢下面一些评论者的大力帮助,我已经修改了代码,因此效率更高。

files<-list.files("path/to/file")
covmat <- matrix(0, ncol=19347, nrow = 19347)
for(name in files){
   invec <- scan(paste("path/to/file", name, sep=""))
   covmat <- covmat + outer(invec,invec, "*")
}

这是我正在尝试处理的文件的示例。

1       0.00114582882882883
2      -0.00792611711711709
...                     ...
19346  -0.00089507207207207
19347  -0.00704709909909909

在运行程序时,每个文件仍需要约 10 分钟。有人对如何加快速度有任何建议吗?

我有 8gb 的内存,当程序运行时,R 只使用了 4.5gb 的内存,并且有少量空闲。

我正在运行 Mac OS X Snow Leopard 和 R 64bit v. 2.15

4

2 回答 2

4

我对您循环中的逻辑感到担忧。您正在计算一个本质上是 covmat + outer(in.vec) 的结果。

   text <- c("1", "5", "8")
    for(i in 1:3){
     for(k in 1:3){
       covmat[i, k]  <-  (as.numeric(text[i]) * as.numeric(text[k]))
     }
   }
 covmat
     [,1] [,2] [,3]
[1,]    1    5    8
[2,]    5   25   40
[3,]    8   40   64
 outer(as.numeric(text),as.numeric(text), "*")
     [,1] [,2] [,3]
[1,]    1    5    8
[2,]    5   25   40
[3,]    8   40   64

这并没有错,只是可以在 R 中大大简化的东西,如果这是你真正想要的,那么这个向量化函数可以替换整个内部两个循环:

invec <- scan(paste("path/to/folder/", name, sep="")
covmat <- outer(invec,invec, "*")

您还使用最外层循环覆盖连续文件的每个结果,这不是您所说的想要做的,因此您可能需要决定将这些矩阵存储在什么数据结构中,自然选择是列表:

matlist <- list()
files<-list.files("path/to/folder/")
    for(name in files){
         invec <- scan(paste("path/to/folder/", name, sep="")
         covmat <- outer(invec,invec, "*")
         matlist[[name]] <- covmat
                      }

现在“matlist”应该有与该目录中的文件一样多的矩阵。您可以按名称或按输入顺序访问它们。您可以使用以下方法检索名称:

names(matlist)
于 2012-06-10T15:21:20.957 回答
1

也许

covmat <- matrix(0, ncol=19347, nrow = 19347)
files <- paste("path/to/folder/", list.files("path/to/folder/"), sep = '')
for(name in files){
  vec <- scan(name,  nlines = 19347)
  mat <- outer(vec, vec, '*')
  covmat <- covmat + mat
}

我猜,但也许你真的想要类似的东西......

numFiles <- 110
mat <- matrix(0, ncol= numFiles, nrow = 19347)
files <- paste("path/to/folder/", list.files("path/to/folder/"), sep = '')
for(i in 1:numFiles){
  mat[i,] <- scan(files[i],  nlines = 19347)
}
covmat <- cov(mat)
于 2012-06-10T14:48:11.927 回答