根据条件代入或求和

Substituting or summing based on condition

我有一个看起来像这样的数据集

df <- data.frame("id" = c("Alpha", "Alpha", "Alpha","Alpha","Beta","Beta","Beta","Beta"), 
                 "Year" = c(1970,1971,1972,1973,1974,1977,1978,1990), 
                 "Group" = c(1,NA,1,NA,NA,2,2,NA),
                 "Val" = c(2,3,3,5,2,5,3,5))

我想创建一个 "Val" 的累计和。我知道如何做简单的累加和

df <- df %>% group_by(id) %>% mutate(cumval=cumsum(Val))

但是,我希望我的最终数据看起来像这样

final <- data.frame("id" = c("Alpha", "Alpha", "Alpha","Alpha","Beta","Beta","Beta","Beta"), 
                 "Year" = c(1970,1971,1972,1973,1974,1977,1978,1990), 
                 "Group" = c(1,NA,1,NA,NA,2,2,NA),
                 "Val" = c(2,3,3,5,2,5,3,5),
                 "cumval" = c(2,5,6,11,2,7,5,10))

基本思路是,当两个 "Val" 相同时 "Group" 晚发生的(年份)替代前一个。 例如,在示例数据集中,观察 3 的 "cumval" 为 6 而不是 8,因为 1972 年的 "Val" 替换了 1970 年的 "Val"。Beta 也是如此。

在此先感谢您的帮助

在我看来,这需要一个 for 循环。首先,我们通过 id 列将数据帧拆分为两个列表。然后我们创建两个空列表。在 og 列表中,我们将放置第一个唯一的非 NA 组标识符所在的行。对于 alpha 这是第一行,对于 Beta 这是第二行。当值被替换时,我们将使用它从累计和中减去。

mylist <- split(df, f = df$id)

og <- list()
vals <- list()

df_num <- 1

我们将使用嵌套循环,外循环遍历列表中的每个对象(在本例中为数据帧),内循环遍历组列中的每个值。

我们需要跟踪行号,这是我们用 r 变量做的。我们最初在 for 循环外将其设置为 0,因此我们添加了 1。首先,我们检查我们是否位于数据框的第一行,在这种情况下,累积和等于 Val 列第一行中的值。然后在 if 测试中,我们使用另一个 if 测试来检查组 ID 是否为 NA。如果不是,则这是该数字的第一次出现,如果该数字再次出现,则表示将替换当前值。所以我们把这个数字保存到临时变量temp。我们还将包含值的行提取并保存到 og 列表。

在此之后,进入下一次迭代。我们检查当前组值是否为 NA。如果是,那么我们只需将该值添加到累计总和。如果它不等于 NA,我们检查该值是否为 NA 并且等于 temp 中存储的值。如果两者都是真的,那么这意味着我们需要替换。我们提取存储在 og 列表中的原始值并将其保存为旧值。然后我们从累积和中减去旧值并添加当前值。我们还将 og 中的原始值替换为当前替换值。这是因为如果需要再次替换该值,我们将需要减去当前值而不是原始值。

如果j为NA但不等于temp,那么这是一个新的Group实例。所以我们将具有原始值的行保存到 og 列表中,并保存 Group。总和继续正常,因为这不是替换值的实例。请注意,用于对 og 列表中的元素进行计数的变量 x 仅在将新出现的元素添加到列表时递增。因此,og[[x-1]] 将始终是替换值。

for (my_df in mylist) {

  x <- 1
  r <- 0

  for (j in my_df$Group) {

    r <- r + 1

    if (r == 1) {

      vals[[1]] <- my_df$Val[1]

      if (is.na(j)==FALSE) {
        og[[x]] <- df[r, c('Group', 'Val'), drop = FALSE]
        temp <- j 
        x <- x + 1
      }

      next
    }

    if (is.na(j)==TRUE) {

      vals[[r]] <- vals[[r-1]] + my_df$Val[r]

    } else if (is.na(j)==FALSE & j==temp) {

      old <- og[[x-1]]
      old <- old[,2]

      vals[[r]] <- vals[[r-1]] - old + df$Val[r]
      og[[x-1]] <- df[r, c('Group', 'Val'), drop = FALSE]

    } else {

      vals[[r]] <- vals[[r-1]] + my_df$Val[r]
      og[[x]] <- my_df[r, c('Group', 'Val')] 
      temp <- j
      x <- x + 1

    }

    }

  cumval <- unlist(vals) %>% as.data.frame()
  colnames(cumval) <- 'cumval'
  my_df <- cbind(my_df, cumval)
  mylist[[df_num]] <- my_df
  df_num <- df_num + 1
}

最后,我们通过使用 dplyr 包中的 bind_rows 将它们绑定在行上来组合列表中的两个数据框。然后我用 identical() 检查 Final 数据帧是否与你想要的输出相同,它的计算结果为 TRUE

final_df <- bind_rows(mylist)
identical(final_df, final)
[1] TRUE