假设我想将列转换为数值,如果它们包含0、1、2、NA并且具有3个或更少的唯一值。
之前我用完成了这项工作
outcome_data<- outcome_data %>% dplyr::mutate_if(~any(c(0, 1, 2, NA) %in% .x) & length(unique(as.numeric(.x))) <= 3, as.numeric)
但目前还不清楚如何将.x作为across()
的第一个参数来创建复杂的if条件。以下提示错误:
未找到对象'.x'
outcome_data %>% mutate(across(any(c(0, 1, 2, NA) %in% .x) & length(unique(.x)) < 3), as.numeric))
为了用有效的下标向量对列进行子集设置,我们需要一个数字或字符向量,这里有一种使用which
和sapply
的方法
#devtools::install_github("tidyverse/dplyr")
library(dplyr, warn.conflicts = FALSE)
mtcars %>%
# which(sapply(., function(x) any(c(0, 1, 2, NA) %in% x) & n_distinct(x) < 3))
mutate(across(.cols = which(sapply(., function(x) n_distinct(x)<3)), as.character)) %>%
str()
来自?across
cols,.cols:tree选择要转换的列。由于across((用于summary((和mutate((等函数中,因此不能在对变量分组时进行选择或计算。
我感谢大家对此的回应。我同意,在我看来,across()
并不能让这类事情变得容易,需要额外的步骤。
以下是我解决问题的方法:
dummy_vars<- outcome_data %>% purrr::keep(~all(c("0", "1") %in% .x) & length(unique(.x)) <= 3) %>% names()
outcome_data<- outcome_data %>% dplyr::mutate(across(all_of(dummy_vars), as.numeric))
在dplyr
Github上有一系列关于这个主题的问题,所以他们现在实现了一个接受谓词的函数where()
。与across一样,它目前可通过remotes::install_github('tidyverse/dplyr')
使用。
按照A.Suliman的例子,我们现在可以使用:
library(dplyr)
mtcars %>%
mutate(across(.cols = where(~any(c(0, 1, 2, NA) %in% .x) & length(unique(as.numeric(.x))) <= 3),
as.character)) %>%
str()
#> 'data.frame': 32 obs. of 11 variables:
#> $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
#> $ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
#> $ disp: num 160 160 108 258 360 ...
#> $ hp : num 110 110 93 110 175 105 245 62 95 123 ...
#> $ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
#> $ wt : num 2.62 2.88 2.32 3.21 3.44 ...
#> $ qsec: num 16.5 17 18.6 19.4 17 ...
#> $ vs : chr "0" "0" "1" "1" ...
#> $ am : chr "1" "1" "1" "0" ...
#> $ gear: num 4 4 4 3 3 3 3 4 4 4 ...
#> $ carb: num 4 4 1 1 2 1 4 2 2 4 ...