【问题标题】:Continual summation of a column in R until condition is met连续求和 R 中的一列,直到满足条件
【发布时间】:2021-04-13 12:49:24
【问题描述】:

我正在努力学习 R,这是我在这个论坛上的第一篇文章。

我目前有一个包含填充向量“x”和未填充向量“计数器”的数据框,如下所示:

x <- c(NA,1,0,0,0,0,1,1,1,1,0,1)

df <- data.frame("x" = x, "counter" = 0)

    x counter
1  NA       0
2   1       0
3   0       0
4   0       0
5   0       0
6   0       0
7   1       0
8   1       0
9   1       0
10  1       0
11  0       0
12  1       0

我在尝试编写代码时遇到了令人惊讶的困难,该代码将简单地填充计数器,以便计数器对 x 中累积的连续 1 求和,但在 x 为零时恢复为零。因此,我想按照上面的例子计算如下:

    x counter
1  NA       NA
2   1       1
3   0       0
4   0       0
5   0       0
6   0       0
7   1       1
8   1       2
9   1       3
10  1       4
11  0       0
12  1       1

我尝试过使用 lag() 和 ifelse(),无论是否使用 for 循环,但似乎离可行的解决方案越来越远(虽然 lag 让我很接近,但数字并未按预期计算。 ...我的 ifelse 和 for 循环最终以长度为 1 的 NA_real_、NA 或 1 向量结束。我也考虑过 cumsum - 但不确定如何将范围限定为 1 - 并且搜索和查看了类似的帖子,例如 How to add value to previous row if condition is met;但是,我仍然无法弄清楚我期望的一项非常简单的任务。

诚然,我处于早期 R 学习曲线的低谷,非常感谢社区中任何人可以提供的任何帮助和建设性反馈。谢谢。

【问题讨论】:

    标签: r for-loop if-statement lag cumsum


    【解决方案1】:

    你可以使用:

    library(dplyr)
    
    df %>%
      group_by(x1 = cumsum(replace(x, is.na(x), 0) == 0)) %>%
      mutate(counter = (row_number() - 1) * x) %>%
      ungroup %>%
      select(-x1)
    
    #       x counter
    #   <dbl>   <dbl>
    # 1    NA      NA
    # 2     1       1
    # 3     0       0
    # 4     0       0
    # 5     0       0
    # 6     0       0
    # 7     1       1
    # 8     1       2
    # 9     1       3
    #10     1       4
    #11     0       0
    #12     1       1
    

    解释步骤-

    • 创建一个新列 (x1),将 x 中的 NA 替换为 0,并在 x = 0 时将组值加 1(使用 cumsum)。
    • 对于每个组,用 0 减去行号并乘以 x。这种乘法是必要的,因为它将有助于将 counter 保持为 0,其中 x = 0counter 保持为 NA,其中 xNA

    【讨论】:

    • 感谢@Ronak Shah。我花了相当多的时间试图了解您的解决方案是如何工作的(并且确实有效),但只是无法弄清楚 mutate(counter = (row_number() - 1) * x) 如何/为什么最终“变异”计数器列以反映x 列中连续 1 的正确数量。我对 counter = row_number() - 1) * x 实际上如何让我们到达那里感到困惑。非常感谢任何启发。
    • 我在答案中添加了一些解释。我建议您逐行运行代码以更好地理解答案。
    【解决方案2】:

    欢迎@cpanagakos。

    dplyr::lag 中,无法使用仍然不存在的列。 (它不能引用自己。) https://www.reddit.com/r/rstats/comments/a34n6b/dplyr_use_previous_row_from_a_column_thats_being/

    例如:

    library(tidyverse)
    
    
    df <- tibble("x" = c(NA, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1))
    
    # error: lag cannot refer to a column that still doesn't exist
    df %>%
      mutate(counter = case_when(is.na(x) ~ coalesce(lag(counter), 0),
                                 x == 0   ~ 0,
                                 x == 1   ~ lag(counter) + 1))
    #> Error: Problem with `mutate()` input `counter`.
    #> x object 'counter' not found
    #> i Input `counter` is `case_when(...)`.
    

    因此,如果您有一个“重置”计数器的标准,则需要编写一个公式来在需要重置时更改组,然后引用 row_number,它将在组内的 1 处重新启动(就像@Ronald Shah 和其他人建议的那样):

    Create sequential counter that restarts on a condition within panel data groups

    df %>%
      group_by(x1 = cumsum(!coalesce(x, 0))) %>%
      mutate(counter = row_number() - 1) %>%
      ungroup()
    #> # A tibble: 12 x 3
    #>        x    x1 counter
    #>    <dbl> <int>   <dbl>
    #>  1    NA     1      NA
    #>  2     1     1       1
    #>  3     0     2       0
    #>  4     0     3       0
    #>  5     0     4       0
    #>  6     0     5       0
    #>  7     1     5       1
    #>  8     1     5       2
    #>  9     1     5       3
    #> 10     1     5       4
    #> 11     0     6       0
    #> 12     1     6       1
    

    这将是在 R 中使用 for 循环是合理的少数情况之一:因为替代方案在概念上更难理解。

    【讨论】:

    • 感谢两位的回复。我将研究和消化您使用的每个功能,以更好地理解解决方案。与此同时,@crestor 评论说,这将是在 R 中使用循环是合理的少数情况之一 - 是否有更直接的解决方案可以使用循环提供,如建议的那样?再次感谢您的帮助。
    • 顺便说一句,你们每个人在我的数据集中提供的代码确实有效! (现在只是想更好地理解它)
    • @cpanagakos 你可以选择一个作为答案并投赞成票。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-02
    • 2020-08-29
    • 1970-01-01
    • 1970-01-01
    • 2013-12-28
    相关资源
    最近更新 更多