我需要创建〜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和reducer的代码我一直在玩,如果我做错了。
#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的RAM,当程序运行时R只使用4.5GB,并且有少量免费。
我正在运行Mac OS X Snow Leopard和R 64bit v.2.15
答案 0 :(得分: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)
答案 1 :(得分: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)