我有大约450 000行的以下数据:
'data.frame': 451712 obs. of 7 variables:
$ mid: int 5732 5732 5732 5732 5732 5732 5732 5732 5732 5732 ...
$ id : int 25 26 28 29 30 31 33 36 37 38 ...
$ x : num 3197 5545 3205 6947 7264 ...
$ y : num 6138 5555 6209 5465 5230 ...
$ t : Factor w/ 2 levels "C","L": 2 2 2 2 2 2 2 2 2 2 ...
$ r : Factor w/ 5 levels "Aberrant","Both",..: 3 1 3 4 4 4 4 4 4 4 ...
$ c : num 1 0 1 2 2 2 2 3 2 2 ...
为什么以下操作需要很长时间(> 5分钟,我停止执行)
unsplit(split(data, data$mid), data$mid)
split
本身很快,但在合并数据时,它需要永远。如果我将数据截断为100 000行,那么我可以在10秒内得到结果,但随着行数的增加,时间不会增加。
答案 0 :(得分:7)
虽然看起来确实很奇怪,但您需要了解数据框的一件事是它们的速度非常慢。修改数据帧的每个操作都很昂贵,unsplit
正在做的是通过重新插入来修改每个拆分的数据帧。关于内部逻辑的一些要求每次修改时都要复制整个数据帧。这被称为unsplit
的一部分:
`split<-.data.frame`
function (x, f, drop = FALSE, ..., value)
{
ix <- split(seq_len(nrow(x)), f, drop = drop, ...)
n <- length(value)
j <- 0
for (i in ix) {
j <- j%%n + 1
x[i, ] <- value[[j]]
}
x
}
<bytecode: 0x7ffd5e282c68>
<environment: namespace:base>
x
这里是一个初始化为结果大小的data.frame,你可以看到我们基本上每次拆分都会插入它。由于您的数据框架很大,因此每个插入都非常昂贵。为了强调这可怕的原因,请考虑以下示例,其中我们基准覆盖数据帧中的列中的每个值,而不是使用等效矩阵执行完全相同的操作。即使我们做的完全相同,数据帧版本也要慢30倍!这是一个微小的数据框架。当data.frame很大时,您可以快速了解这是怎么回事。
df <- data.frame(a=seq(1:100), b=runif(100), c=sample(1:10, 100, rep=T))
mx <- as.matrix(df)
microbenchmark(for(i in 1:nrow(df)) df[i, 2] <- 1)
# Unit: milliseconds
# expr min lq median uq max neval
# for (i in 1:nrow(df)) df[i, 2] <- 1 4.018833 4.273562 4.584293 4.726672 23.46349 100
microbenchmark(for(i in 1:nrow(mx)) mx[i, 2] <- 1)
# Unit: microseconds
# expr min lq median uq max neval
# for (i in 1:nrow(mx)) mx[i, 2] <- 1 148.304 153.9795 158.5975 163.7065 277.861 100
顺便说一下,这就是为什么对于上述类型的操作,建议首先计算向量,最后将向量替换为数据帧列,以便只修改数据帧一次。
回复:使用data.table
或dplyr
,我强烈要求您将split
/ unsplit
所做的分析类型作为问题发布,我怀疑你我们会惊讶于这些软件包在解决您的问题方面的强大程度。