首页 > 解决方案 > 根据多个其他列更改各个列 - R

问题描述

我正在尝试根据其他列中的条件找到一种方便的方法来更改列中的值,以便当存在 NA 并且满足条件时,它将替换该值。我有大约 6 列,类似于 A:D,然后是一个二进制列。还有与这些特定行相关的其他数据,例如(日期、位置等)

我在下面做了一些虚拟代码

`%notin%` <- Negate(`%in%`)
ops <- c("Zoo", "Fun", "Party")

df <- data.frame(A = c("Zoo", "Beer", "Rave", "Fun", "school"),
                 B = c("school", NA, "Beer", "exams", "Beer"),
                 C = c("Fun", NA, NA, "Party", "Rave"),
                 D = c(NA, NA, NA, "Rave", NA), 
                 X = c(1,0,1,0,0))

df$B[which((df$A %notin% ops | df$B %notin% ops |
                           df$C %notin% ops) & df$X == 0 & is.na(df$B))] <- "HELP"
df$C[which((df$A %notin% ops & df$B %notin% ops &
                           df$C %notin% ops) & df$X == 0 & 
                          df$B != "HELP" & is.na(df$C))] <- "HELP"
df$D[which((df$A %notin% ops & df$B %notin% ops &
                           df$C %notin% ops) & df$X == 0 & 
                          df$B != "HELP" & df$C != "HELP" &
                          is.na(df$D))] <- "HELP"

如您所见,此代码逐渐变得更加混乱和难以遵循。当我发现新问题时,它会以这种方式逐渐增长......我知道必须有一种更干净的方式来写这个,但我无法为我的生活弄明白。我对 tidyverse(ish) 非常熟悉——更不用说寻找 data.table 解决方案了……但基本的 R 解决方案也将是天赐之物。

目前,我还有其他几个带有类似条件的编码块(这就是为什么拥有一个真正有效的解决方案只是清理这段代码的巨大飞跃)。

编辑:在要求解释我正在尝试做的事情时,让我更清楚地解释一下。

当我想要更改满足某些条件的行值时,我想要一个更优雅的解决方案。在这里,每一行是一个分类调查响应,其中ops包含我感兴趣的 3 个分类变量。X 是一个虚拟变量(实际上只是布尔值)。

为方便起见(并且为了不混淆下面的答案,我将稍微更改 df 。

df <- data.frame(A = c("Zoo", "Beer", "Rave", "Fun", "school", "blah"),
                 B = c("school", NA, "Beer", "exams", "Beer", "blah"),
                 C = c("Fun", NA, NA, "Party", "Rave", NA),
                 D = c(NA, NA, NA, "Rave", NA, NA), 
                 X = c(1,0,1,0,0,1))

目标是更改第一个 NA 如果该行不包含 ops & X==0

但是,我也不想更改所有 NA - 如果第一个 NA 满足条件(即行包含 ops & X == 0),我只想更改第一个 NA 并且我不知道一个 NA 将出现在数据,但我确实知道在第一个 NA 之后,如果有更多列,其余的将是 NA,直到 X。

如果我们取第 5 行:

ops 不在 A, B, C, D & X == 0 & is.na(D) 因此 [5,5] == "HELP"

如果我们取第 2 行:

ops不在A, B, C,D & B is.na & C is.na, D is.na & X==0 但我只想改变NA的第一次出现

添加的新行 (6)

ops 不在 A、B、C、D 但 X == 0 中。在这种情况下,我仍然希望“帮助”出现在第一个 NA 所在的位置。

我不知道我是否让这更令人困惑 - 抱歉不是计算机科学家,但这基本上是我试图实现的逻辑结构,而不必更改每一行。根据不同的条件,我有 2 次使用不同版本的“帮助”再执行 2 次,然后排除了“帮助”这个词......所以它开始变得难以解析。

标签: rdataframetidyverse

解决方案


这是一个稍微更简洁且在我看来更易于阅读的解决方案:

library(tidyverse)

df %>% 
  mutate(B = case_when((!A %in% ops | !B %in% ops | !C %in% ops) & X == 0 & is.na(B) ~ "HELP",
                       TRUE ~ B),
         C = case_when((!A %in% ops | !B %in% ops | !C %in% ops) & X == 0 & B != "HELP" & is.na(C) ~ "HELP",
                       TRUE ~ C),
         D = case_when(!A %in% ops & !B %in% ops & !C %in% ops & X == 0 & B != "HELP" & C != "HELP" & is.na(D) ~ "HELP",
                       TRUE ~ D))

这给了我们:

    A      B     C    D X
1    Zoo school   Fun <NA> 1
2   Beer   HELP  <NA> <NA> 0
3   Rave   Beer  <NA> <NA> 1
4    Fun  exams Party Rave 0
5 school   Beer  Rave HELP 0

请注意,df %>% mutate(!variable %in% vector)可以用作%notin% <- Negate(%in%的替代品)


推荐阅读