R中的高效数据帧迭代

R中的高效数据帧迭代,r,R,假设我有一个500万行的数据框,有两列(为了简单起见,这个数据框只有十行): 然后取新向量的长度(在本例中,10+10+10+10+1+10+7+2)=60 *注意,我不需要向量本身,只要它的长度就足够了。因此,如果有人有更明智的逻辑方法来获得长度,这是受欢迎的 从本质上讲,所做的是为数据帧中的每一行选择一个从开始到结束的序列,并将所有这些序列组合起来,然后过滤出唯一的值 因此,我采用了这样一种方法: length(unique(c(apply(df, 1, function(x) {

假设我有一个500万行的数据框,有两列(为了简单起见,这个数据框只有十行):

然后取新向量的长度(在本例中,10+10+10+10+1+10+7+2)=60

*注意,我不需要向量本身,只要它的长度就足够了。因此,如果有人有更明智的逻辑方法来获得长度,这是受欢迎的

从本质上讲,所做的是为数据帧中的每一行选择一个从开始到结束的序列,并将所有这些序列组合起来,然后过滤出唯一的值

因此,我采用了这样一种方法:

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