使用dplyr重新编码多个列

8

我有一个数据框,其中我重新编码了几列,将999设为NA

dfB <-dfA %>%
  mutate(adhere = if_else(adhere==999, as.numeric(NA), adhere)) %>%
  mutate(engage = if_else(engage==999, as.numeric(NA), engage)) %>%
  mutate(quality = if_else(quality==999, as.numeric(NA), quality)) %>%
  mutate(undrstnd = if_else(undrstnd==999, as.numeric(NA), undrstnd)) %>%
  mutate(sesspart = if_else(sesspart==999, as.numeric(NA), sesspart)) %>%
  mutate(attended = if_else(attended>=9, as.integer(NA), attended))

我希望使用mutate_at()和一系列列以及recode()来替代if_else(),但我不知道如何设置条件。我认为可以根据一些mutate_all的示例,使用类似于999=NA的方式--但我还需要让NA与.x的类型匹配,我不确定如何使其类型敏感。

我尝试了:

y <- data.frame(y1=c(1,2,999,3,4), y2=c(1L, 2L, 999L, 3L, 4L), y3=c(T,T,F,F,T))
z <- y %>%
    mutate_at( vars(y1:y2), funs(recode(.,`999` = as.numeric(NA))))

但我收到了一个警告:“未替换的值被视为NA,因为.x不兼容。请详尽说明替换内容或提供.default”,我可以看到它适用于数字列,但不适用于整数列y2。

> z
  y1 y2    y3
1  1 NA  TRUE
2  2 NA  TRUE
3 NA NA FALSE
4  3 NA FALSE
5  4 NA  TRUE
5个回答

9

我认为这与列的类型有关。我使用了mutate_if来将所有整数列转换为数字列,然后将recoded值设置为NA_real_。看起来工作正常。

library(dplyr)

y <- data.frame(y1=c(1,2,999,3,4), y2=c(1L, 2L, 999L, 3L, 4L), y3=c(T,T,F,F,T))

z <- y %>%
  mutate_if(is.integer, as.numeric) %>%
  mutate_at(vars(y1:y2), funs(recode(.,`999` = NA_real_)))
z
#   y1 y2    y3
# 1  1  1  TRUE
# 2  2  2  TRUE
# 3 NA NA FALSE
# 4  3  3 FALSE
# 5  4  4  TRUE

谢谢,www。这确实解决了警告问题。它强制将所有内容转换为实数,并避免了以前整数列的错误NA类型。我曾经考虑过这个问题。我的代码中还有其他部分依赖于这些列是整数,我需要在重新编码后将它们重置为整数。我希望能找到一种方法使NA值响应每列数字的类型。 - D. Bontempo

7
我有些难以理解您想要达成的目标,如果这不是您想要的,请告诉我。


library(dplyr)

y <- data.frame(y1=c(1,2,999,3,4), y2=c(1L, 2L, 999L, 3L, 4L), y3=c(T,T,F,F,T))

y

#>    y1  y2    y3
#> 1   1   1  TRUE
#> 2   2   2  TRUE
#> 3 999 999 FALSE
#> 4   3   3 FALSE
#> 5   4   4  TRUE

z <- y %>%
  mutate_at(vars(y1:y2), ~ifelse(. == 999, NA, .))

z

#>   y1 y2    y3
#> 1  1  1  TRUE
#> 2  2  2  TRUE
#> 3 NA NA FALSE
#> 4  3  3 FALSE
#> 5  4  4  TRUE

谢谢evertr。这确实解决了问题。它保留了if_else()而不是使用recode() - 但我可以接受这个结果。我可以像你建议的那样使用“.”来避免转换为数字。我不清楚为什么它没有抱怨true的NA是错误的类型。在我的原始代码中,我必须使用as.numeric(NA)或as.integer(NA)来避免错误。你知道为什么它在这里没有报错吗? - D. Bontempo
啊,好的。我看到你使用了ifelse(),它的类型检查方式与if_else()不同。你知道如何在不将整个数据框转换为实数的情况下使用if_else()吗? - D. Bontempo
@D.Bontempo 你可以使用 mutate_if(is.numeric, ...),它也匹配整数,这样你就不必选择所有变量(就像 @www 的解决方案一样,但不需要转换任何内容)。@everetr 我建议你从你的解决方案中删除 as.numeric,因为没有必要进行类型转换。那么它就值得加1分了;-) - Tino
@Tino,请看我在代码下面的评论。我已经说过,如果需要的话可以省略as.numeric。我不知道@D. Bontempo是否需要转换。 - ardaar
@D.Bontempo 请看我在代码下面的评论。您可以省略 as.numeric,以避免将 y$y2integer 转换为 numeric - ardaar
显示剩余3条评论

7

现在,在dplyr中,由于funs已被弃用,这是新的使用方法:

z <- y %>%
  mutate_if(is.integer, as.numeric) %>%
  mutate_at(vars(y1:y2), list(~recode(.,`999` = NA_real_)))

funs替换为list,并在recode前插入一个~

2
如果只调用一个函数,则不需要使用list() - ardaar

7

目前,基于dplyr文档

across() 取代了"scoped variants"系列函数,如summarise_at()、summarise_if()和summarise_all()。

因此,现在建议使用mutateacross

正如Chris LeBoa所说,如果你只想将一个烦人的值转换为NA,那么函数na_if()可能是最好的选择:

y <- data.frame(y1=c(1,2,999,3,4), y2=c(1L, 2L, 999L, 3L, 4L), y3=c(T,T,F,F,T))

y
   y1  y2    y3
1   1   1  TRUE
2   2   2  TRUE
3 999 999 FALSE
4   3   3 FALSE
5   4   4  TRUE
 
z <- y %>%
    mutate(across(
        y1:y2,
        ~na_if(., 999)
    ))

z
  y1 y2    y3
1  1  1  TRUE
2  2  2  TRUE
3 NA NA FALSE
4  3  3 FALSE
5  4  4  TRUE

同样地,如果您真的想要在多个列中重新编码值,您可以按照示例来自bcarothers的方法进行操作:
df1 <- tibble(Q7_1=1:5,
              Q7_1_TEXT=c("let's","see","grogu","this","week"),
              Q8_1=6:10,
              Q8_1_TEXT=rep("grogu",5),
              Q8_2=11:15,
              Q8_2_TEXT=c("grogu","is","the","absolute","best"))

df2 <- df1 %>%
    mutate(across(
        starts_with("Q8") & ends_with("TEXT"),
        ~recode(., "grogu"="mando")
    ))

1

如果您正在尝试将某些内容重新编码为NA,则na_if()函数也可以起作用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接