使用 mutate 和 for-loop 自动分配变量名
Automatic variable name assignment with mutate and for-loop
我有一个包含 40 个变量的数据框 G1_a
、G1_b
、...直到 G20_a
、G20_b
(来自一项调查)。我想创建 20 个新变量 G1
... G20
来总结现有变量。
data <- data.frame(G1_a = c(0, 0, 0, 1, NA),
G1_b = c(0, 0, 1, 1, NA),
G2_a = c(0, 0, 0, 1, NA),
G2_b = c(0, 0, 1, 1, NA))
# Reshaping without for-loop:
data <- data %>%
mutate(G1 = case_when(
G1_a == 1 ~ "own_offer",
G1_b == 1 ~ "no_offer",
T ~ NA_character_
))
data <- data %>%
mutate(G2 = case_when(
G2_a == 1 ~ "own_offer",
G2_b == 1 ~ "no_offer",
T ~ NA_character_
))
我想在 for 循环中自动创建新变量,例如:
# Reshaping with for-loop:
for(i in 1:2) {
data <- data %>%
mutate(assign(paste0("G", i), case_when(
get(paste0("G", i, "_a")) == 1 ~ "own_offer",
get(paste0("G", i, "_b")) == 1 ~ "no_offer",
T ~ NA_character_
)))
}
我的问题包括两部分:
1) assign
和 mutate
可以合并吗?我知道像 mutate(df, !!varname := Petal.width * n)
(参见 here)这样的动态分配参数名称的方法。但是,我无法将它与我想要 运行 的数据重塑相结合。
2) dplyr
是否允许 paste0
与 case_when
和 mutate
一起使用?
这有点棘手,但我认为这是执行此操作的原则方法。最终结果是一个包含所需列的 数据框 ,从而避免了所有 get()
/assign()
令人头疼的问题(并且不会使工作区因大量派生数据而变得杂乱无章)变量。)有几个步骤,我们使用 tidyr::gather()
和 tidyr::spread()
更改数据框的形状(宽 -> 长 -> 部分宽 -> 宽)。如果看起来势不可挡,请尝试在不同的中间点停止管道序列,看看到目前为止取得了什么成果。
library(tidyr)
library(dplyr)
dds <- (dd
%>% mutate(case=seq(n())) ## need a variable to distinguish rows in original data set
%>% gather(var,val,-case) ## -> long format: {case, var={G1_a,G1_b,...}, val={0,1,NA}}
%>% separate(var,c("var","response")) ## split to "G1","G2" + "a", "b"
%>% spread(response,val) ## convert back to semi-wide: {case, var, a, b}
## now collapse rows to categorical value, as above
%>% mutate(offer=case_when(a==1 ~ "own_offer",
b==1 ~ "no_offer",
TRUE ~ NA_character_))
%>% select(-c(a,b)) ## clean up now-redundant variables
%>% spread(var,offer) ## convert back to wide format: {case, G1, G2, ...}
%>% select(-case) ## now redundant
)
结果
G1 G2
1 <NA> <NA>
2 <NA> <NA>
3 no_offer no_offer
4 own_offer own_offer
5 <NA> <NA>
我有一个包含 40 个变量的数据框 G1_a
、G1_b
、...直到 G20_a
、G20_b
(来自一项调查)。我想创建 20 个新变量 G1
... G20
来总结现有变量。
data <- data.frame(G1_a = c(0, 0, 0, 1, NA),
G1_b = c(0, 0, 1, 1, NA),
G2_a = c(0, 0, 0, 1, NA),
G2_b = c(0, 0, 1, 1, NA))
# Reshaping without for-loop:
data <- data %>%
mutate(G1 = case_when(
G1_a == 1 ~ "own_offer",
G1_b == 1 ~ "no_offer",
T ~ NA_character_
))
data <- data %>%
mutate(G2 = case_when(
G2_a == 1 ~ "own_offer",
G2_b == 1 ~ "no_offer",
T ~ NA_character_
))
我想在 for 循环中自动创建新变量,例如:
# Reshaping with for-loop:
for(i in 1:2) {
data <- data %>%
mutate(assign(paste0("G", i), case_when(
get(paste0("G", i, "_a")) == 1 ~ "own_offer",
get(paste0("G", i, "_b")) == 1 ~ "no_offer",
T ~ NA_character_
)))
}
我的问题包括两部分:
1) assign
和 mutate
可以合并吗?我知道像 mutate(df, !!varname := Petal.width * n)
(参见 here)这样的动态分配参数名称的方法。但是,我无法将它与我想要 运行 的数据重塑相结合。
2) dplyr
是否允许 paste0
与 case_when
和 mutate
一起使用?
这有点棘手,但我认为这是执行此操作的原则方法。最终结果是一个包含所需列的 数据框 ,从而避免了所有 get()
/assign()
令人头疼的问题(并且不会使工作区因大量派生数据而变得杂乱无章)变量。)有几个步骤,我们使用 tidyr::gather()
和 tidyr::spread()
更改数据框的形状(宽 -> 长 -> 部分宽 -> 宽)。如果看起来势不可挡,请尝试在不同的中间点停止管道序列,看看到目前为止取得了什么成果。
library(tidyr)
library(dplyr)
dds <- (dd
%>% mutate(case=seq(n())) ## need a variable to distinguish rows in original data set
%>% gather(var,val,-case) ## -> long format: {case, var={G1_a,G1_b,...}, val={0,1,NA}}
%>% separate(var,c("var","response")) ## split to "G1","G2" + "a", "b"
%>% spread(response,val) ## convert back to semi-wide: {case, var, a, b}
## now collapse rows to categorical value, as above
%>% mutate(offer=case_when(a==1 ~ "own_offer",
b==1 ~ "no_offer",
TRUE ~ NA_character_))
%>% select(-c(a,b)) ## clean up now-redundant variables
%>% spread(var,offer) ## convert back to wide format: {case, G1, G2, ...}
%>% select(-case) ## now redundant
)
结果
G1 G2
1 <NA> <NA>
2 <NA> <NA>
3 no_offer no_offer
4 own_offer own_offer
5 <NA> <NA>