【问题标题】:R while: mutate only groups in data.frame that do not match conditionR while:仅改变 data.frame 中不匹配条件的组
【发布时间】:2021-02-12 04:30:22
【问题描述】:

示例数据:

 df <- data.frame(Date = seq(as.Date("2020-01-01"), by = "day", length.out = 12),
             Phase = c(rep("stable",6),rep("instable",6)),
             n = (c(rep(5,5),4,3,6,6,5,6,5)))

我想返回一个 data.frame,其中包含 n == max(n) 的日期(对于每个组),但条件是每个组必须至少有 5 天。如果一个组少于5天,那么过滤器应该调整为n == max(n) | n == max(n) - 1等等...

所以这里是一个例子:

df %>%
  group_by(Phase) %>%
  dplyr::filter(n == max(n)) %>%
  ungroup()

    # A tibble: 8 x 3
  Date       Phase        n
  <date>     <chr>    <dbl>
1 2020-01-01 stable       5
2 2020-01-02 stable       5
3 2020-01-03 stable       5
4 2020-01-04 stable       5
5 2020-01-05 stable       5
6 2020-01-08 instable     6
7 2020-01-09 instable     6
8 2020-01-11 instable     6

您可以看到,在第一组stable(基于列Phase)中,我的目标至少达到了5天,但在第二组instable中没有达到

为此,我编写了一个 while 循环,在每次运行中降低条件,直到满足:

i <- 0
condition <- FALSE
while(!condition) {
  df_maxdays <- df %>%
    group_by(Phase) %>%
    dplyr::filter(n %in% (max(n, na.rm = T)-i):max(n, na.rm = T)) %>%
    mutate(nn = n()) %>%
    ungroup()
  
  i <- i + 1
  condition <- all(df_maxdays$nn >= 5)
}

df_maxdays
# A tibble: 11 x 4
   Date       Phase        n    nn
   <date>     <chr>    <dbl> <int>
 1 2020-01-01 stable       5     6
 2 2020-01-02 stable       5     6
 3 2020-01-03 stable       5     6
 4 2020-01-04 stable       5     6
 5 2020-01-05 stable       5     6
 6 2020-01-06 stable       4     6
 7 2020-01-08 instable     6     5
 8 2020-01-09 instable     6     5
 9 2020-01-10 instable     5     5
10 2020-01-11 instable     6     5
11 2020-01-12 instable     5     5

在我的 while 循环中,第二组 instable 现在包含 5 天,这是我想要的,但第一组现在还包含 n &gt;= (max(n)-1) 为真的天。我希望在第二次运行时过滤器仅针对尚未达到目标的组进行调整。该示例所需的输出是:

# A tibble: 11 x 4
       Date       Phase        n    nn
       <date>     <chr>    <dbl> <int>
     1 2020-01-01 stable       5     5
     2 2020-01-02 stable       5     5
     3 2020-01-03 stable       5     5
     4 2020-01-04 stable       5     5
     5 2020-01-05 stable       5     5
     7 2020-01-08 instable     6     5
     8 2020-01-09 instable     6     5
     9 2020-01-10 instable     5     5
    10 2020-01-11 instable     6     5
    11 2020-01-12 instable     5     5

【问题讨论】:

  • 我不明白你的目标。您能否添加您想要实现的预期最终输出?
  • @Edo 你是对的,这并不容易跟随......我更新了我的问题,希望现在更清楚了。
  • 逻辑对我来说仍然不清楚。带有“2020-01-06”的行在哪里结束?
  • 在您的示例数据中,两个阶段都有 6 天。 (请参阅您的代码中的 rep("instable",6)。)您能否更新由 df &lt;- 代码创建的示例数据以匹配您显示的示例数据?
  • @GregorThomas 没有打印出实际的df,在此之前有一些代码应用了过滤器:-)

标签: r while-loop dplyr


【解决方案1】:

如果我正确理解您的问题,您只需使用slice_max

library(dplyr)

df %>%
   group_by(Phase) %>% 
   slice_max(n, n = 5) %>% 
   ungroup()
#> # A tibble: 10 x 3
#>    Date       Phase        n
#>    <date>     <chr>    <dbl>
#>  1 2020-01-08 instable     6
#>  2 2020-01-09 instable     6
#>  3 2020-01-11 instable     6
#>  4 2020-01-10 instable     5
#>  5 2020-01-12 instable     5
#>  6 2020-01-01 stable       5
#>  7 2020-01-02 stable       5
#>  8 2020-01-03 stable       5
#>  9 2020-01-04 stable       5
#> 10 2020-01-05 stable       5

通过这种方式,您始终在每个组中至少保留 5 个最高的ns。 这与您显示的预期输出结果相同。唯一的区别是instable 在顶部,因为dplyr 的默认重新排序...

【讨论】:

  • 从凌乱的问题陈述中看透底层目标的方法!
  • 我不敢相信我在这件事上花了这么多时间,而这实际上很容易......非常感谢。所以只是为了澄清我得到了正确的一切。 slice_max 返回 n == max(n) 所在的所有行,但如果结果少于 5 行,它将返回 n &gt;= (max(n) -1) 所在的所有行?
  • 从技术上讲,slice_max(n,n = 5) 返回包含 n 最大值的 5 行。如果要达到 5 必须将条从 max(n) 降低到 max(n)-1,它就可以了。如果你有超过 5 行具有相同的值,它会保留它们。想象一下按 n 排序并剪掉前 5 行(或保留更多行以防平局).. 这就是 slice_max 所做的
  • @GregorThomas 我尽量说清楚,如果我没能做到这一点,很抱歉。
  • @FelixPhl 不用担心,有时人们会陷入以某种方式思考问题的陷阱,很难找到更简单的方式。我刚刚开始了解您对问题的看法,但无法像 Edo 这么快就看穿这个简单的解决方案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-22
  • 2022-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多