在R中不同类型的列之间应用ifelse()时保留列类型



这似乎是一项相当简单的任务,但在研究了ifelse()dplyr::if_else()的文档以及SO上关于将ifelse()应用于数据帧中多列的几篇类似文章后,我无法理解。

我的目标:我有以下数据框架,其中包含不同数据类型的列。在每一行上,我想将前3列中的值重置为NA,如果Column";有效的";表示错误。

问题:我使用dplyr::across()ifelse()根据需要更改值,但日期列date和因子列team被强制为数字(如下面的reprex所示(,这是不可取的。我知道dplyr::if_else()保留了数据类型,但它也不能跨不同数据类型的列工作。

我知道tdf[tdf$valid == FALSE, !grepl("valid", names(tdf))] <- NA可以实现我的目标,但我更喜欢一种不同的方法,可以在我的数据清理管道中使用。非常感谢!

library(dplyr)
tdf <- tibble(
date = c(as.Date("2021-12-10"), as.Date("2021-12-11")),
team = factor(1:2, labels = c("T1", "T2")),
score = 3:4,
valid = c(TRUE, FALSE)
)
tdf
#> # A tibble: 2 x 4
#>   date       team  score valid
#>   <date>     <fct> <int> <lgl>
#> 1 2021-12-10 T1        3 TRUE 
#> 2 2021-12-11 T2        4 FALSE
tdf %>% mutate(across(-valid, ~ ifelse(valid, ., NA)))
#> # A tibble: 2 x 4
#>    date  team score valid
#>   <dbl> <int> <int> <lgl>
#> 1 18971     1     3 TRUE 
#> 2    NA    NA    NA FALSE

创建于2021-12-10由reprex包(v2.0.1(

使用case_when中的默认(TRUE(选项,该选项根据类型返回NA

library(dplyr)
tdf %>%
mutate(across(-valid, ~ case_when(valid ~ .)))

-输出

# A tibble: 2 × 4
date       team  score valid
<date>     <fct> <int> <lgl>
1 2021-12-10 T1        3 TRUE 
2 NA         <NA>     NA FALSE

或者另一个选项是replace

tdf %>% 
mutate(across(-valid, ~ replace(., !valid, NA)))
# A tibble: 2 × 4
date       team  score valid
<date>     <fct> <int> <lgl>
1 2021-12-10 T1        3 TRUE 
2 NA         <NA>     NA FALSE

根据?ifelse

结果的模式可能取决于测试的值(参见示例(,结果的类属性(参见oldClass(取自测试,可能不适合从是和否中选择的值。

有时最好使用之类的构造

(tmp<-yes;tmp[!test]<-no[!test];tmp(

,可能扩展为处理测试中丢失的值。

这是一个尚未解决的问题:

@akrun给出了一个很好的解释,以及如何解决您的具体问题!

但如果你想保留ifelse:

Fabian Werner在2015年使用自定义的safe.ifelse为您的特定案例提供了唯一有效的解决方案(带日期和因素(

如何防止ifelse((将Date对象转换为数字对象

safe.ifelse <- function(cond, yes, no) {
class.y <- class(yes)
if (class.y == "factor") {
levels.y = levels(yes)
}
X <- ifelse(cond,yes,no)
if (class.y == "factor") {
X = as.factor(X)
levels(X) = levels.y
} else {
class(X) <- class.y
}
return(X)
}
tdf %>% mutate(across(-valid, ~ safe.ifelse(valid, ., NA)))
date       team  score valid
<date>     <fct> <int> <lgl>
1 2021-12-10 T1        3 TRUE 
2 NA         NA       NA FALSE

最新更新