假设我有一个500万行数据帧,有两列,为了简单起见,这个数据帧只有十行:
df <- data.frame(start=c(11,21,31,41,42,54,61,63), end=c(20,30,40,50,51,63,70,72))
我希望能够在数字向量中生成以下数字:
11 to 20, 21 to 30, 31 to 40, 41 to 50, 51, 54-63, 64-70, 71-72
然后取新矢量的长度(在这种情况下,10 + 10 + 10 + 10 + 1 + 10 + 7 + 2)= 60
*注意,我不需要矢量本身,只需它的长度即可。因此,如果某人有更智能的逻辑方法来获得长度,那就很受欢迎了。
基本上,完成的是数据帧中的每一行,从开始到结束的序列,以及所有这些序列的组合,然后过滤UNIQUE值。
所以我使用了一种方法:
length(unique(c(apply(df, 1, function(x) {
return(as.numeric(x[1]):as.numeric(x[2]))
}))))
在我的五百万行数据框中证明非常慢。
更快更有效的解决方案?奖金,请尝试添加系统时间。
用户系统已用完 19.946 0.620 20.477
答案 0 :(得分:2)
这应该有效,假设您的数据已经过排序。
library(dplyr) # for the lag function
with(df, sum(end - pmax(start, lag(end, 1, default = 0)+1) + 1))
#[1] 60
library(microbenchmark)
microbenchmark(
beginneR={with(df, sum(end - pmax(start, lag(end, 1, default = 0)+1) + 1))},
r2evans={vec <- pmax(mm[,1], c(0,1+head(mm[,2],n=-1))); sum(mm[,2]-vec+1);},
times = 1000
)
Unit: microseconds
expr min lq median uq max neval
beginneR 37.398 41.4455 42.731 44.0795 74.349 1000
r2evans 31.788 35.2470 36.827 38.3925 9298.669 1000
因此矩阵仍然更快,但不多(并且此处仍未包含转换步骤)。我想知道为什么@ r2evans的答案中的最大持续时间与所有其他值(实际上很快)相比如此之高
答案 1 :(得分:2)
另一种方法:
mm <- as.matrix(df) ## critical for performance/scalability
(vec <- pmax(mm[,1], c(0,1+head(mm[,2],n=-1))))
## [1] 11 21 31 41 51 54 64 71
sum(mm[,2] - vec + 1)
## [1] 60
(这应该很好地扩展,当然比data.frames更好。)
修改:在我更新代码以使用矩阵而没有apply
调用之后,我对其实现进行了快速基准测试,与其他答案相比(这也是正确的):< / p>
library(microbenchmark)
library(dplyr)
microbenchmark(
beginneR={
df <- data.frame(start=c(11,21,31,41,42,54,61,63),
end=c(20,30,40,50,51,63,70,72))
with(df, sum(end - pmax(start, lag(end, 1, default = 0)+1) + 1))
},
r2evans={
mm <- matrix(c(11,21,31,41,42,54,61,63,
20,30,40,50,51,63,70,72), nc=2)
vec <- pmax(mm[,1], c(0,1+head(mm[,2],n=-1)))
sum(mm[,2]-vec+1)
}
)
## Unit: microseconds
## expr min lq median uq max neval
## beginneR 230.410 238.297 244.9015 261.228 443.574 100
## r2evans 37.791 40.725 44.7620 47.880 147.124 100
这大大受益于使用矩阵而不是data.frames。
哦,系统时间在这里没有用: - )
system.time({
mm <- matrix(c(11,21,31,41,42,54,61,63,
20,30,40,50,51,63,70,72), nc=2)
vec <- pmax(mm[,1], c(0,1+head(mm[,2],n=-1)))
sum(mm[,2]-vec+1)
})
## user system elapsed
## 0 0 0