【问题标题】:R grouped for loop seq_along length - 1?R 分组为循环 seq_along 长度 - 1?
【发布时间】:2021-08-27 00:00:27
【问题描述】:

我正在尝试创建一个指标,用于指示项目被接受所需的“尝试”次数。我认为 for 循环是要走的路,但我在 R 中没有大量的循环经验,而且逻辑有点复杂。任何帮助/建议/反馈将不胜感激!

在玩具示例中,“accept”为“C”,向前迭代“try”的切换是提交 (A) 是否被重置 (B) 或提交 (A) 是否被接受 (C)。

在一个组内,如果事件顺序是 A > B 或 A > C,则将“try”向前迭代 1。否则,“try”计数应保持不变。显然,“真实”的例子比这个玩具例子要复杂得多。

目前,我只是想使尝试计数正确,而不用担心分组。

我不确定如何将 seq_along 限制为基本上停止在 [group_by %>% length(group) - 1]。有更好的选择吗?

df = data.frame(group = c(1,1,1,1,1,2,2,2,2), 
                 event = c("A","B","A","A","C","A","B","A","C"))

df$try <- 0
for (i in seq_along(df$event)){
    if (df$event[[i]] == "A" &  
          df$event[[i+1]] %in% c("B", "C"))
      {
        df$try[[i]] <- df$try + 1
    } else {
        df$try[[i]] <- df$try
    }
}

# this essentially shows the correct answer (win = try + 1, loss = try), 
# but has "df$event[[i + 1]] : subscript out of bounds", 
# and I need to save the outcome so I can access later

df$try <- 0
for (i in seq_along(df$event)){
    if (df$event[[i]] == "A" &  
          df$event[[i+1]] %in% c("B", "C"))
      {
        print("Win")
    } else {
        print("Loss")
    }
}

我对玩具示例的预期(最终)答案是:try = c(1,1,1,2,2,1,1,2,2);每组 1 和 2 需要 2 次“尝试”才能被接受

【问题讨论】:

    标签: r loops for-loop dplyr iteration


    【解决方案1】:

    您可以使用lead 获取dplyr 中的下一个值。试试这个 -

    library(dplyr)
    
    df %>%
      group_by(group) %>%
      mutate(result = cumsum(event == 'A' & lead(event) %in% c('B', 'C'))) %>%
      ungroup
    
    #  group event   try result
    #  <dbl> <chr> <dbl>  <int>
    #1     1 A         1      1
    #2     1 B         1      1
    #3     1 A         1      1
    #4     1 A         2      2
    #5     1 C         2      2
    #6     2 A         1      1
    #7     2 B         1      1
    #8     2 A         2      2
    #9     2 C         2      2
    

    在输出中保留try 列以供比较。

    【讨论】:

    • 谢谢!这非常好,并且看起来比循环更快(未经实际测试)。我使用max(cumsum ...) 来获得每个组的最终结果。我认为 dplyr::lead 对这个项目非常有用;我以前没见过!
    【解决方案2】:

    多加一个if可以解决“下标越界”的问题。

    if(i+1 > nrow(df){
    print('do nothing')
    } else if (
    #followed by your original code
    )
    

    我假设如果最后一行,值将只是 0。所以另一个 if 应该这样做。

    library(tidyverse)
    df <- data.frame(group = c(1,1,1,1,1,2,2,2,2), 
                    event = c("A","B","A","A","C","A","B","A","C"))
    
    
    temp <- data.frame(NULL)
    for(i in 1:nrow(df)){
      if(i+1 > nrow(df)){
        print('This is the last row')
        temp <- rbind(temp, 0)
      } else if(df$event[[i]] == 'A' &
         df$event[[i+1]] %in% c('B', 'C'))
      {
        temp <- rbind(temp, 1)
      } else {
        temp <- rbind(temp, 0)
      }
    }
    
    df2 <- cbind(df, temp) %>%
      mutate(
        cumulative_sum = cumsum(X1)
      )
    

    【讨论】:

    • 您好,感谢您提供这个额外的想法!不过,我不确定它如何与 group_by 一起使用。我对玩具示例的预期(最终)答案是:X1 = c(1,1,1,2,2,1,1,2,2)
    • 看来我们手头有两个问题:1.) Group_by 我相信你不确定如果你在实际工作中使用它是否可以解决“下标越界”问题,这将还涉及 group_by()。我对么? 2.) 结果虽然我的代码可以解决“下标越界问题”,但预期的答案并不是您想要的。我是否正确理解了这种情况?
    • 1.我计划探索“group_modify”和“group_map”,但正确:我没有按组解决迭代的确切想法。例如:使用 for 循环作为 group_modify iris %&gt;% group_by(Species) %&gt;% group_modify(~ { quantile(.x$Petal.Length, probs = c(0.25, 0.5, 0.75)) %&gt;% tibble::enframe(name = "prob", value = "quantile") }) 2 中的函数参数。答案接近我想要的,但我想使用尽可能少的步骤和额外的数据帧,因为这是一个非常大的数据集跨度>
    【解决方案3】:

    这似乎暂时有效:

    如果 i + 1 超出长度,则添加“中断”

    df$try <- 0
    for (i in seq_along(df$event)){
        if (i+1 == length(df$event)){
          break
          } else if (df$event[[i]] == "A" &  
              df$event[[i+1]] %in% c("B", "C"))
          {
            print("Win")
        } else (
            print("Loss")
        )
    }
    
    # updated toy df to show N tries differs:
    
    df = data.frame(group = c(1,1,1,1,1,1,1,2,2,2,2), 
                     event = c("A","B","A","A","B","A","C","A","B","A","C"))
    
    df$try <- 0
    for (i in seq_along(df$event)){
        if (i == length(df$event)){ # use i otherwise it doesn't catch the last switch
          break
          } else if (df$event[[i]] == "A" &  
              df$event[[i+1]] %in% c("B", "C"))
          {
            df$try[[i]] <- + 1
        } else (
            df$try[[i]]
        )
    }
    
    df %>% 
      group_by(group) %>% 
      mutate(N_tries = max(cumsum(try)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-20
      • 2020-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-07
      • 2015-07-25
      • 1970-01-01
      相关资源
      最近更新 更多