【问题标题】:mutate based on conditional sum in a group基于组中的条件和进行变异
【发布时间】:2018-09-16 17:46:25
【问题描述】:

假设我有一个这样的数据框:

set.seed(1)
n <- 20
df <- data.frame(ID = sample(1:5, n, replace = TRUE),
             Fac1 = sample(letters[1:5], n, replace = TRUE),
             Fac2 = sample(LETTERS[10:15], n, replace = TRUE),
             Val1 = sample(1:10, n, replace = TRUE)) %>% 
  arrange(ID) %>% group_by(ID,Fac1) %>% 
  summarise(Val1 = sum(Val1),Fac2 = first(Fac2)) %>%
  group_by(ID,Fac2) %>% 
  mutate(Val2 = sum(Val1))
df
   ID Fac1 Val1 Fac2 Val2
1   1    b    9    N    9
2   1    c    9    O    9
3   2    a    4    K    4
4   2    b   10    M   18
5   2    c    4    L    4
6   2    d    8    M   18
7   2    e   10    N   10
8   3    d   14    N   14
9   4    b    8    L   22
10  4    c   14    L   22
11  4    d    9    K    9
12  4    e    6    N    6
13  5    a   13    M   13
14  5    b    3    N    3

ID 是一个分组变量。 Fac1 值为 e 的行应将 Fac2 值更改为与组中 Fac1 为 b 或 c 的另一行相同,如果两行的 Val 2 之和大于 20。(我已经将其简化为您可能不明白为什么而只是与我合作)。
这是我迄今为止尝试过的:

result <- df %>% group_by(ID) %>% 
  mutate(Fac2 = case_when(
    Fac1 == "e" & 
      sum(Val2,ifelse(Fac1 %in% c("b","c"), Val2, 0)) > 20 ~
      ifelse(sum(Val2,ifelse(Fac1 %in% c("b","c"),Val2,0)) > 20,
             as.character(Fac2),
             NA_character_),
    TRUE ~ as.character(Fac2)
  ))

它不能正常工作,因为它是对组中 Val2 的第一个值求和,而不是仅在 Fac1 为 b 或 c 时才这样做。

有什么想法吗?

添加期望的结果:

   ID Fac1 Val1 Fac2 Val2
1   1    b    9    N    9
2   1    c    9    O    9
3   2    a    4    K    4
4   2    b   10    M   18
5   2    c    4    L    4
6   2    d    8    M   18
7   2    e   10    M   10 **Changed to M b/c row 4 is M and 10 + 18 > 20
8   3    d   14    N   14
9   4    b    8    L   22
10  4    c   14    L   22
11  4    d    9    K    9
12  4    e    6    L    6 **Changed to L b/c row 10 is L and 6 + 22 > 20
13  5    a   13    M   13
14  5    b    3    N    3

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    我能够使用此代码获得所需的结果。我创建了一个新列,其中包含用于替换 Fac2 的值的测试结果,这不是完全必要的,但使其更具可读性和可调试性。 关键是使用first(na.omit()) 从同一组中满足条件的不同行中获取值。

    result <- df %>% group_by(ID) %>% 
      mutate(Max_bc_Val = ifelse(Val2 == max(ifelse(Fac1 %in% c("b","c"),
                                              Val2,0)),
                          ifelse(Fac1 %in% c("b","c"),
                                 as.character(Fac2),NA),NA)) %>% 
      mutate(Fac2 = case_when(
        Fac1 == "e" ~ ifelse(is.na(first(na.omit(Max_bc_Val))),
                             NA_character_,
                             first(na.omit(Max_bc_Val))),
        TRUE ~ as.character(Fac2)))   
    

    这可行,但似乎不是最好的解决方案。还有其他想法吗?

    【讨论】:

      【解决方案2】:

      我很难遵循您希望将值更改为的内容。

      但是当我有多个条件或需要按顺序做出决定时,我会使用循环和一系列 if 语句来遍历数据框。我更喜欢while 循环,所以我将在示例中使用它。

      counter <- 1
      stopper <- nrow(df)
      while (counter <= stopper) {
      
       fac1 <- df$Fac1[counter1]
      
       if (fac1 == 'e') {
      
        if ([INSERT NEXT CONDITION]) #Change whichever value your trying to change using the counter to reference the correct row.
        else #Change whichever value your trying to change using the counter to reference the correct row.
      
       }
      
      counter <- counter + 1
      }
      

      对我来说,简化代码让我更容易跟踪正在做出的决定。它还允许做出难以使用函数的复杂决策。

      【讨论】:

      • 谢谢,但条件取决于有一个分组的数据框,这就是我在不迭代行时遇到问题的部分。我添加了一个期望结果的示例。希望有帮助
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-28
      • 2019-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多