基于组中条件和的mutate

时间:2018-04-06 16:23:43

标签: r dplyr

说我有这样的数据框:

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的组中的另一行相同,如果大于20,则将两行的Val 2相加。(我是简化到这一点,你可能不明白为什么,但只是与我合作。) 这是我到目前为止所尝试的:

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

2 个答案:

答案 0 :(得分:0)

我很难跟踪你想要改变的值。

但是当我有一个需要在序列中进行的多个条件或决定时,我使用循环和一系列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
}

对我而言,简化代码使我更容易跟踪正在做出的决策。它还允许难以使函数处理的复杂决策。

答案 1 :(得分:0)

我能够使用此代码获得所需的结果。我创建了一个新列,其中包含测试结果,用于替换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)))   

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