传递一个字符串进行变异
Passing a character string to mutate
我已经在 SO 上寻找这个问题的答案,但未能找到解决我问题的方法。
我有一个包含多列的数据框,每一列至少有一个 NA。这些列的名称存储在字符向量 vars_na
中。对于其中的每一个,我想创建一个虚拟变量,如果缺少该观察值,则取值为 0,否则为 1。
下面是一个可复制的玩具示例和我目前使用的代码:
# creation of toy dataset
iris[1:5, 1] <- rep(NA, 5)
iris[1:10, 4] <- rep(NA, 10)
vars_na <- c("Sepal.Length", "Petal.Width")
for(var in vars_na){
iris <- iris %>%
mutate(dummy = ifelse(is.na(!!var), 0, 1)) %>%
rename_at(c("dummy"), list(~paste0("dummyna_", var)))
# 'rename_at' is just to differentiate between the several dummies created,
# and it works correctly
}
问题在于,新创建的虚拟对象会导致向量全为 1,因此它们无法正确考虑缺失值;确实:
head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species dummyna_Sepal.Length dummyna_Petal.Width
1 NA 3.5 1.4 NA setosa 1 1
2 NA 3.0 1.4 NA setosa 1 1
3 NA 3.2 1.3 NA setosa 1 1
4 NA 3.1 1.5 NA setosa 1 1
5 NA 3.6 1.4 NA setosa 1 1
6 5.4 3.9 1.7 NA setosa 1 1
但我想获得
Sepal.Length Sepal.Width Petal.Length Petal.Width Species dummyna_Sepal.Length dummyna_Petal.Width
1 NA 3.5 1.4 NA setosa 0 0
2 NA 3.0 1.4 NA setosa 0 0
3 NA 3.2 1.3 NA setosa 0 0
4 NA 3.1 1.5 NA setosa 0 0
5 NA 3.6 1.4 NA setosa 0 0
6 5.4 3.9 1.7 NA setosa 1 0
代码很简单,我相信它应该可以工作。我做错了什么?提前致谢。
问题是因为var
是一个字符,
像 is.na(!!var)
这样的东西最终会变成像 is.na("Sepal.Length")
这样的东西,
这总是错误的。
您可以使用 rlang::sym
* 将字符转换为可由 mutate
计算的符号,例如:
for (var in vars_na) {
var_sym <- rlang::sym(var)
new_name <- rlang::sym(paste0(var, "_na"))
iris <- iris %>%
mutate(!!new_name := as.integer(!is.na(!!var_sym)))
}
*rlang
包是大多数 non-standard 评估 dplyr
支持的基础,
参见 tidy evaluation。
我已经在 SO 上寻找这个问题的答案,但未能找到解决我问题的方法。
我有一个包含多列的数据框,每一列至少有一个 NA。这些列的名称存储在字符向量 vars_na
中。对于其中的每一个,我想创建一个虚拟变量,如果缺少该观察值,则取值为 0,否则为 1。
下面是一个可复制的玩具示例和我目前使用的代码:
# creation of toy dataset
iris[1:5, 1] <- rep(NA, 5)
iris[1:10, 4] <- rep(NA, 10)
vars_na <- c("Sepal.Length", "Petal.Width")
for(var in vars_na){
iris <- iris %>%
mutate(dummy = ifelse(is.na(!!var), 0, 1)) %>%
rename_at(c("dummy"), list(~paste0("dummyna_", var)))
# 'rename_at' is just to differentiate between the several dummies created,
# and it works correctly
}
问题在于,新创建的虚拟对象会导致向量全为 1,因此它们无法正确考虑缺失值;确实:
head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species dummyna_Sepal.Length dummyna_Petal.Width
1 NA 3.5 1.4 NA setosa 1 1
2 NA 3.0 1.4 NA setosa 1 1
3 NA 3.2 1.3 NA setosa 1 1
4 NA 3.1 1.5 NA setosa 1 1
5 NA 3.6 1.4 NA setosa 1 1
6 5.4 3.9 1.7 NA setosa 1 1
但我想获得
Sepal.Length Sepal.Width Petal.Length Petal.Width Species dummyna_Sepal.Length dummyna_Petal.Width
1 NA 3.5 1.4 NA setosa 0 0
2 NA 3.0 1.4 NA setosa 0 0
3 NA 3.2 1.3 NA setosa 0 0
4 NA 3.1 1.5 NA setosa 0 0
5 NA 3.6 1.4 NA setosa 0 0
6 5.4 3.9 1.7 NA setosa 1 0
代码很简单,我相信它应该可以工作。我做错了什么?提前致谢。
问题是因为var
是一个字符,
像 is.na(!!var)
这样的东西最终会变成像 is.na("Sepal.Length")
这样的东西,
这总是错误的。
您可以使用 rlang::sym
* 将字符转换为可由 mutate
计算的符号,例如:
for (var in vars_na) {
var_sym <- rlang::sym(var)
new_name <- rlang::sym(paste0(var, "_na"))
iris <- iris %>%
mutate(!!new_name := as.integer(!is.na(!!var_sym)))
}
*rlang
包是大多数 non-standard 评估 dplyr
支持的基础,
参见 tidy evaluation。