R中的高效数据帧迭代
假设我有一个500万行的数据框,有两列(为了简单起见,这个数据框只有十行): 然后取新向量的长度(在本例中,10+10+10+10+1+10+7+2)=60 *注意,我不需要向量本身,只要它的长度就足够了。因此,如果有人有更明智的逻辑方法来获得长度,这是受欢迎的 从本质上讲,所做的是为数据帧中的每一行选择一个从开始到结束的序列,并将所有这些序列组合起来,然后过滤出唯一的值 因此,我采用了这样一种方法:R中的高效数据帧迭代,r,R,假设我有一个500万行的数据框,有两列(为了简单起见,这个数据框只有十行): 然后取新向量的长度(在本例中,10+10+10+10+1+10+7+2)=60 *注意,我不需要向量本身,只要它的长度就足够了。因此,如果有人有更明智的逻辑方法来获得长度,这是受欢迎的 从本质上讲,所做的是为数据帧中的每一行选择一个从开始到结束的序列,并将所有这些序列组合起来,然后过滤出唯一的值 因此,我采用了这样一种方法: length(unique(c(apply(df, 1, function(x) {
length(unique(c(apply(df, 1, function(x) {
return(as.numeric(x[1]):as.numeric(x[2]))
}))))
在我的500万行数据帧上,速度非常慢
有更快更有效的解决方案吗?奖金,请尝试添加系统时间
用户系统运行时间
19.946 0.620 20.477假设您的数据已排序,则此操作应该有效
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
library(dplyr)#用于滞后函数
带(df,sum(end-pmax(start,lag(end,1,默认值=0)+1)+1))
#[1] 60
图书馆(微基准)
微基准(
初学者={with(df,sum(end-pmax(start,lag(end,1,默认值=0)+1)+1))},
r2evans={vec假设您的数据已排序,则此操作应该有效
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
library(dplyr)#用于滞后函数
带(df,sum(end-pmax(start,lag(end,1,默认值=0)+1)+1))
#[1] 60
图书馆(微基准)
微基准(
初学者={with(df,sum(end-pmax(start,lag(end,1,默认值=0)+1)+1))},
r2evans={vec另一种方法:
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
这得益于使用矩阵而不是数据帧
哦,系统时间在这里没有那么大帮助:-)
system.time({
mm另一种方法:
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
这得益于使用矩阵而不是数据帧
哦,系统时间在这里没有那么大帮助:-)
system.time({
mm如果你有500万行数字数据要开始,你应该使用矩阵,而不是数据。frame
不是新向量的长度只是差的总和(加1)?和(df$end-df$start+1)
?@konvas;与前一个endNo之前的一些开始不同,因为存在重叠。在df数据帧中,第四行是41-50,第五行是42-51。根据您的方法,唯一数字的总数将(50-41+1)+(51-42+1)=20,而它应该是41-51,或(51-41+1)=11。@Richard Scriven好的,即使转换为矩阵,也应该有更快的方法。顺便说一句,我正在编写的脚本的另一部分生成了一个数据帧。如果一开始有500万行数字数据,那么应该使用矩阵,而不是数据。帧不是新向量的长度,只是差异之和(加1)?sum(df$end-df$start+1)
?@konvas;与前一个endNo之前的一些开始不太一样,因为有重叠。在df数据框中,第四行是41-50,第五行是42-51。按照您的方法,唯一数字的总数是(50-41+1)+(51-42+1)=20,而它应该是41-51,或(51-41+1)=11。@Richard Scriven好的,即使转换为matrix,也应该有更快的方法。顺便说一句,我正在编写的脚本的另一部分已经生成了一个数据帧。很好的基准测试,虽然您没有包括mm Good catch,但现在我包括了所有三个的数据的形成,它仍然将matrix
实现继续。编辑即将到来…我认为这是不对的,因为数据已经在data.frame中,所以我的答案不需要转换(或创建)data.frame,而你的答案需要将data.frame转换为矩阵..有趣的是,如果数据已经形成,我们正在竞相减少执行时间(您的基准测试),现在使用矩阵而不是data.frames只提高了25%的速度——我对此印象深刻并感到惊讶(dplyr
真是神奇)。我不确定这与dplyr
本身的基准有多大关系,虽然您没有包括mm Good catch,但是现在我包括了所有三个的数据的形成,它仍然将矩阵
实现放在前面。即将编辑…我认为这是不对的,因为数据已经在data.frame中,所以我的答案不需要转换(或创建)data.frame,而你的答案需要将data.frame转换为矩阵..有趣的是,如果数据已经形成(你的基准),我们正在竞争减少执行时间,现在在data.frames上使用矩阵的速度仅提高了25%——我对此印象深刻,也感到惊讶(dplyr
真是神奇)。我不确定这与dplyr
本身有多大关系。我也看到了高最大时间。我运行了几次,发现异常值在我的和你的中出现了大约相同的次数。也许我们看到了定时不方便的垃圾收集的工件。耸肩对于更准确的基准,有必要了解更多关于实际数据。如果OP能提供一些,那就太好了,尽管我在接下来的几个小时里不会在我的办公桌上进行测试。@初学者好吧,我会给你的。我觉得这很有趣。我将把.RData文件链接到Dropbox。预先警告一下,你可能需要一些软件包,比如Biostring(只需快速搜索如何下载),IRanges,BioGenerics,parallel。所以继续运行wild!记住!您必须先按起始位置排序!而且,是的,只需使用load(file=)
,它将作为原始变量加载。data@r2evans好吧,我会给你的。我觉得这很有趣。我将把.RData文件链接到Dropbox。事先警告一下,你可能需要一些软件包,比如Biostrings(只需在谷歌上快速搜索如何下载),IRanges,BioGenerics,parallel。所以继续运行wild!记住!您必须先按起始位置排序!而且,是的,只需使用load(file=)
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
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