【问题标题】:Filter on sequential condition till another condition is met按顺序条件过滤,直到满足另一个条件
【发布时间】:2021-07-29 06:38:41
【问题描述】:

如何创建满足两个条件的过滤器:

  1. 删除值下降到前一天 80% 以上的所有行。
  2. 继续删除下降后的行,直到值再次上升超过 50
data <- tibble(date = seq.Date(as.Date("2021-01-01"),as.Date("2021-01-01")+14,1),
       value = c(89,86,87,76,10,90,92,83,12,15,23,51,32, 88, 92)
       ) %>% 
  mutate(diff = (value-lag(value, default = first(value)))/lag(value, default = first(value)))

最终输出应该是:

  date       value    diff
   <date>     <dbl>   <dbl>
 1 2021-01-01    89  0     
 2 2021-01-02    86 -0.0337
 3 2021-01-03    87  0.0116
 4 2021-01-04    76 -0.126 
 5 2021-01-06    90  8     
 6 2021-01-07    92  0.0222
 7 2021-01-08    83 -0.0978
 8 2021-01-12    51  1.22  
 9 2021-01-13    32 -0.373 
10 2021-01-14    88  1.75  
11 2021-01-15    92  0.0455

【问题讨论】:

  • 这是一个不需要的列,我最终会在最终输出中删除
  • 还有一件事!如果说连续值为 100、5(减少 95%)、10(增加 100%)、15(增加 50%)、16.5(增加 10%)、33(增加 200%),您的预期结果是什么。
  • 只有 100 会保留,直到值再次超过 50,所以c(100,5,10,15,16.5,33,51,40) 的序列只有c(100, 51, 40)
  • 实际上,即使下面的答案有效,它也不能很好地概括,特别是如果你从小于 50 的值开始。我放弃了思考过程并使用了新的任务标准这需要在 shinyapp 中完成。我认为这可能是一个有缺陷的思考过程:)
  • 再一次打扰你,(实际上我发现这个既有趣又具有挑战性)A = c(102,100,50,60,20,100,5,10, 15,1,33,50,53) 的理想输出是因为这里的值下降了两次,下降了 80% 并且只上升一次?

标签: r filter dplyr time-series


【解决方案1】:

这是一种使用data.table::rleid的方法

library(dplyr)

data <- tibble(
  date = seq.Date(as.Date("2021-01-01"), as.Date("2021-01-01") + 14, 1),
  value = c(43,47,87,76,10,90,92,83,12,15,23,51,32, 88, 92)
)

data %>%
  mutate(diff = (value - lag(value, default = first(value))) /
      lag(value, default = first(value))) %>%
  mutate(to_remove = diff <= -.8) %>%
  # calculate the index of removing to group rows after first removing rows
  mutate(group_remove = data.table::rleid(to_remove)) %>%
  # for those groups as long as no line reach value 50
  # to_continue_remove variable is assign FALSE
  group_by(group_remove) %>%
  mutate(to_continue_remove = (group_remove > 1) & !to_remove &
      cumsum(value >= 50) == 0) %>%
  # filter remove rows for 1st condition diff < 80%
  filter(!to_remove) %>%
  # continue filter rows after removed rows that haven't reach 50 yet
  filter(!to_continue_remove)

#> # A tibble: 11 x 6
#> # Groups:   group_remove [3]
#>    date       value    diff to_remove group_remove to_continue_remove
#>    <date>     <dbl>   <dbl> <lgl>            <int> <lgl>             
#>  1 2021-01-01    43  0      FALSE                1 FALSE             
#>  2 2021-01-02    47  0.0930 FALSE                1 FALSE             
#>  3 2021-01-03    87  0.851  FALSE                1 FALSE             
#>  4 2021-01-04    76 -0.126  FALSE                1 FALSE             
#>  5 2021-01-06    90  8      FALSE                3 FALSE             
#>  6 2021-01-07    92  0.0222 FALSE                3 FALSE             
#>  7 2021-01-08    83 -0.0978 FALSE                3 FALSE             
#>  8 2021-01-12    51  1.22   FALSE                5 FALSE             
#>  9 2021-01-13    32 -0.373  FALSE                5 FALSE             
#> 10 2021-01-14    88  1.75   FALSE                5 FALSE             
#> 11 2021-01-15    92  0.0455 FALSE                5 FALSE

reprex package (v2.0.0) 于 2021-05-10 创建

更新:调整解决方案,如果起始值低于 50,则不从第一组中删除行

【讨论】:

  • 请注意,如果在满足删除条件之前前几个元素小于 50,则此方法不起作用。
  • 可以分享失败案例的样本吗?
  • c(43,47,87,76,10,90,92,83,12,15,23,51,32, 88, 92)替换之前数据集中的Value列。前两个条目不应在最终输出中排除。过滤值列后应该有c(43,47,87,76,90,92,83,51,32, 88, 92)
猜你喜欢
  • 2019-09-19
  • 1970-01-01
  • 1970-01-01
  • 2015-07-28
  • 2014-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多