用“For循环”填充矩阵耗时太长
Posted
技术标签:
【中文标题】用“For循环”填充矩阵耗时太长【英文标题】:Filling a Matrix with "For Loop" Taking Too Long 【发布时间】:2014-02-09 02:11:08 【问题描述】:我正在尝试使用 for 循环创建一个大约 1,000,000 x 5 的数据框,但已经 5 个多小时了,我认为它不会很快完成。我正在使用 rjson 库从大型 json 文件中读取数据。有人可以帮助我以更快的方式填充此数据框吗?
library(rjson)
# read in data from json file
file <- "/filename"
c <- file(file, "r")
l <- readLines(c, -1L)
data <- lapply(X=l, fromJSON)
# specify variables that i want from this data set
myvars <- c("url", "time", "userid", "hostid", "title")
newdata <- matrix(data[[1]][myvars], 1, 5, byrow=TRUE)
# here's where it goes wrong
for (i in 2:length(l))
newdata <- rbind(newdata, data[[i]][myvars])
newestdata <- data.frame(newdata)
【问题讨论】:
你在R Inferno的第二个圈子里。 查看 R inferno。随着每次循环迭代和消耗资源,您正在增长newdata
。最好为你的 1000000 x 5 矩阵预先分配内存,然后填写信息。
...但惯用的方式类似于do.call(rbind,data)
。请参阅 data.table 包中的 rbindlist
以获得更快的速度。
R 是更改时复制,因此您将成倍增加每个循环所需的时间。在lapply
或类似的东西上使用rbindlist
(来自data.table
)。
data <- sapply(X=l, fromJSON)
应该这样做,但您可能需要转置结果。
【参考方案1】:
这需要很长时间,因为循环的每次迭代都在创建一个新的、更大的对象。试试这个:
slice <- function(field, data) unlist(lapply(data, `[[`, field))
data.frame(Map(slice, myvars, list(data)))
这将创建一个 data.frame 并保留您的原始数据类型:字符、数字等,如果重要的话。将所有内容强制转换为矩阵会强制将所有内容转换为字符类。
【讨论】:
这适用于我较小的测试数据集,但不适用于我实际的大型数据集。这里有什么问题?这是我得到的错误。 "data.frame 中的错误(buzz = c("azcentral.com/community/phoenix/articles/…", : 参数暗示不同的行数:1349674、1339352" 你能更准确地说“不起作用”吗?如果您收到错误消息,您可以分享吗?您的文件中是否存在不包含所有五个条目的记录? 上面贴出了错误信息。运行以下行时出现此错误:“newdata 长度(数据)为 1349674 所以,是的,您有缺少条目的记录。尝试用这个替换上面的slice
:slice <- function(field, data) unlist(lapply(lapply(data, "[[", field), function(x) if (is.null(x)) NA else x))
【参考方案2】:
如果没有数据,很难确定,但您正在做的一些事情相对较慢。这应该更快,但同样,没有数据,我无法测试:
newdata <- vapply(data, `[`, character(5L), myvars)
我还假设您的data
是character
,我认为它必须基于title
。
另外,正如其他人所指出的,你的速度慢的原因是你正在增长一个对象,这需要 R 不断重新分配内存。 vapply
会提前分配内存,因为它知道每次迭代结果的大小,以及有多少项。
【讨论】:
以上是关于用“For循环”填充矩阵耗时太长的主要内容,如果未能解决你的问题,请参考以下文章
matlab 如何将for每循环一次产生的矩阵合并成一个大矩阵