在 R 的管道中有条件地过滤

Filter conditionally in a pipe in R

我有很多数据框,每个都有几列。其中两列是 timevalue.

最小示例

library(tidyverse)

df <- approx(seq(1,10,1), c(1,5,7,11,4,12,30, 20, 10, 9)) %>% 
      as.data.frame() %>% 
      rename(time = x, value = y)

目标

我想从每个数据框中删除所有行,从第一次开始 value > 10

当数据框包含 values > 10 时,解决方案如下:

df <- df %>% 
         filter(row_number() <= first(which(value > 10))-1)

但是,也有value不超过10的数据帧,例如

df <- approx(seq(1,10,1), c(1,5,7,1,4,2,1, 2, 1, 9)) %>% 
      as.data.frame() %>% 
      rename(time = x, value = y)

在这种情况下,不应过滤数据帧(因为未达到 value 阈值)。但是,当我使用上面的 filter 解决方案时,它 returns 一个空数据框。

问题

如何在 dplyr 管道内解决这个问题?是否可以进行条件过滤?

您可以在 filter 中编写条件语句:

library(dplyr)

df %>% 
    filter(if(any(value > 10)) row_number() <= which.max(value > 10)-1 else TRUE)

slice中写同样的逻辑:

df %>% 
   slice(if(any(value > 10)) seq_len(which.max(value > 10)-1) else seq_len(n()))

微基准测试

在速度方面,filterslice没有太大的区别:

df <- approx(seq(1,10^5,1), 
             round( runif(10^5, min = 1, max = 10^10) ) ) %>% 
      as.data.frame()

library(microbenchmark)

microbenchmark(
  filter = df %>% filter(if(any(value > 10)) row_number() <= which.max(value > 10)-1 else TRUE),
  slice = df %>% slice(if(any(value > 10)) seq_len(which.max(value > 10)-1) else seq_len(n())), times = 10000)

Unit: microseconds
  expr     min       lq     mean   median       uq      max neval
 filter 551.522 570.2715 655.7250 586.3530 621.5590 13575.81 10000
 slice 614.276 633.6840 735.0398 654.2455 695.3795 14123.43 10000