R:如何使用数字索引循环变量名(就像在 Stata 中一样)
R: How to loop over variable names using number indexes (like in Stata)
我一直试图在 R 中复制以下 Stata 循环,但没有成功:
forvalues i=1/10 {
replace var`i'= a if other_var`i'==b
}
到目前为止,我认为这是最接近的尝试:
for(i in 1:10) {
df <- df %>%
mutate(get(paste("var",i,sep="")) =
ifelse(get(paste("other_var",i,sep=""))==b
,a
,get(paste("var",i,sep=""))))
}
但我收到以下错误:
Error: unexpected '=' in:
"survey_data <- survey_data %>%
mutate(paste("offer",i,"_accepted",sep="") ="
如果我将要变异的变量更改为一个简单的变量名,它就可以工作,所以我猜我的代码对于“变异的右侧”是可行的,但由于某种原因它不可行对于“左侧”。
这个解决方案非常不优雅,但我认为它完全符合您的要求。
var1 <- "x"
var2 <- "y"
var3 <- "z"
other_var1 <- 1
other_var2 <- 0
other_var3 <- 1
df <- data.frame(var1, other_var1, var2, other_var2, var3, other_var3)
for(i in 1:3){
var_name <- paste("df$var", i, sep = "")
other_var_name <- paste("df$other_var", i, sep = "")
if (eval(parse(text = other_var_name)) == 1){
assign(var_name, "a")
}
}
这里有三个关键成分。首先 paste()
函数在循环的当前迭代中创建变量的名称。其次,eval(parse(foo))
组合引用名称作为字符串存储在 foo
中的实际变量。第三,使用 assign()
为变量赋值(与使用 <-
相反)。
这看起来像 FAQ 7.21。
该答案最重要的部分是在结尾处说要改用列表。
尝试在 R 中处理一组全局变量会导致难以阅读甚至更难调试的复杂代码。
如果您改为将这些变量放入一个列表中,那么您可以按名称或位置访问它们,并使用 lapply
或 purrr
包(tidyverse 的一部分)等工具来处理所有内容在列表中(或使用 map_at
或 map_if
来自 purrr
的列表中的某些内容)。
如果告诉我们更多关于您想要完成的事情,我们可能会给出一个更简单的例子来说明如何做。
您可以执行以下操作:
df <- structure(list(var1 = c(1, 2, 3, 4),
var2 = c(1, 2, 3, 4),
var3 = c(1,2, 3, 4),
var4 = c(1, 2, 3, 4),
other_var1 = c(1, 0, 1, 0),
other_var2 = c(0,1, 0, 1),
other_var3 = c(1, 1, 0, 0),
other_var4 = c(0, 0, 1,1)),
class = "data.frame",
row.names = c(NA, -4L))
# var1 var2 var3 var4 other_var1 other_var2 other_var3 other_var4
# 1 1 1 1 1 1 0 1 0
# 2 2 2 2 2 0 1 1 0
# 3 3 3 3 3 1 0 0 1
# 4 4 4 4 4 0 1 0 1
## Values to replace based on OP original question
a <- 777
b <- 1
## Iter along all four variables avaible in df
for (i in 1:4) {
df <- within(df, {
assign(paste0("var",i), ifelse(get(paste0("other_var",i)) %in% c(b), ## Condition
a, ## Value if Positive
get(paste0("var",i)) )) ## Value if Negative
})
}
这导致以下输出:
# var1 var2 var3 var4 other_var1 other_var2 other_var3 other_var4
# 1 777 1 777 1 1 0 1 0
# 2 2 777 777 2 0 1 1 0
# 3 777 3 3 777 1 0 0 1
# 4 4 777 4 777 0 1 0 1
解决方案看起来不像单行解决方案,但它实际上是一个,一个相当密集的解决方案;因此,让我们看看它的基础组件是如何工作的。
within()
:我不想重复别人解释的很好,所以对于within()
的用法,我轻轻地推荐给你here。
第:assign(paste0("var",i), X)
部分。
这里我遵循 在他的回答中所做的,这意味着使用 paste0()
恢复变量的名称并为它们分配 X
的值(待解释)使用assign()
函数。
我们来谈谈X
。
在我引用 assign(paste0("var",i), X)
之前。实际上,X
等于 ifelse(get(paste0("other_var",i)) %in% c(b), a, get(paste0("var",i)) )
.
里面ifelse()
:
条件:
首先,我在循环时结合函数 get()
和 paste0()
恢复变量 other_var(i)
的值(i = 1,2,3,4)。然后,我使用 %in%
运算符检查分配给变量 b
的值(在我的示例中,数字 1)是否包含在变量 other_var(i)
中;这会根据条件是否满足生成 TRUE 或 FALSE。
ifelse()
函数的 TRUE
部分。
这是最简单的部分,如果满足条件则赋值,a
(在我的例子中等于777
)。
ifelse()
函数的 FALSE
部分。
get(paste0("var",i))
:是变量本身的值(意思是如果不满足条件,则保持变量不变)。
我一直试图在 R 中复制以下 Stata 循环,但没有成功:
forvalues i=1/10 {
replace var`i'= a if other_var`i'==b
}
到目前为止,我认为这是最接近的尝试:
for(i in 1:10) {
df <- df %>%
mutate(get(paste("var",i,sep="")) =
ifelse(get(paste("other_var",i,sep=""))==b
,a
,get(paste("var",i,sep=""))))
}
但我收到以下错误:
Error: unexpected '=' in:
"survey_data <- survey_data %>%
mutate(paste("offer",i,"_accepted",sep="") ="
如果我将要变异的变量更改为一个简单的变量名,它就可以工作,所以我猜我的代码对于“变异的右侧”是可行的,但由于某种原因它不可行对于“左侧”。
这个解决方案非常不优雅,但我认为它完全符合您的要求。
var1 <- "x"
var2 <- "y"
var3 <- "z"
other_var1 <- 1
other_var2 <- 0
other_var3 <- 1
df <- data.frame(var1, other_var1, var2, other_var2, var3, other_var3)
for(i in 1:3){
var_name <- paste("df$var", i, sep = "")
other_var_name <- paste("df$other_var", i, sep = "")
if (eval(parse(text = other_var_name)) == 1){
assign(var_name, "a")
}
}
这里有三个关键成分。首先 paste()
函数在循环的当前迭代中创建变量的名称。其次,eval(parse(foo))
组合引用名称作为字符串存储在 foo
中的实际变量。第三,使用 assign()
为变量赋值(与使用 <-
相反)。
这看起来像 FAQ 7.21。
该答案最重要的部分是在结尾处说要改用列表。
尝试在 R 中处理一组全局变量会导致难以阅读甚至更难调试的复杂代码。
如果您改为将这些变量放入一个列表中,那么您可以按名称或位置访问它们,并使用 lapply
或 purrr
包(tidyverse 的一部分)等工具来处理所有内容在列表中(或使用 map_at
或 map_if
来自 purrr
的列表中的某些内容)。
如果告诉我们更多关于您想要完成的事情,我们可能会给出一个更简单的例子来说明如何做。
您可以执行以下操作:
df <- structure(list(var1 = c(1, 2, 3, 4),
var2 = c(1, 2, 3, 4),
var3 = c(1,2, 3, 4),
var4 = c(1, 2, 3, 4),
other_var1 = c(1, 0, 1, 0),
other_var2 = c(0,1, 0, 1),
other_var3 = c(1, 1, 0, 0),
other_var4 = c(0, 0, 1,1)),
class = "data.frame",
row.names = c(NA, -4L))
# var1 var2 var3 var4 other_var1 other_var2 other_var3 other_var4
# 1 1 1 1 1 1 0 1 0
# 2 2 2 2 2 0 1 1 0
# 3 3 3 3 3 1 0 0 1
# 4 4 4 4 4 0 1 0 1
## Values to replace based on OP original question
a <- 777
b <- 1
## Iter along all four variables avaible in df
for (i in 1:4) {
df <- within(df, {
assign(paste0("var",i), ifelse(get(paste0("other_var",i)) %in% c(b), ## Condition
a, ## Value if Positive
get(paste0("var",i)) )) ## Value if Negative
})
}
这导致以下输出:
# var1 var2 var3 var4 other_var1 other_var2 other_var3 other_var4
# 1 777 1 777 1 1 0 1 0
# 2 2 777 777 2 0 1 1 0
# 3 777 3 3 777 1 0 0 1
# 4 4 777 4 777 0 1 0 1
解决方案看起来不像单行解决方案,但它实际上是一个,一个相当密集的解决方案;因此,让我们看看它的基础组件是如何工作的。
within()
:我不想重复别人解释的很好,所以对于within()
的用法,我轻轻地推荐给你here。
第:assign(paste0("var",i), X)
部分。
这里我遵循 paste0()
恢复变量的名称并为它们分配 X
的值(待解释)使用assign()
函数。
我们来谈谈X
。
在我引用 assign(paste0("var",i), X)
之前。实际上,X
等于 ifelse(get(paste0("other_var",i)) %in% c(b), a, get(paste0("var",i)) )
.
里面ifelse()
:
条件:
首先,我在循环时结合函数 get()
和 paste0()
恢复变量 other_var(i)
的值(i = 1,2,3,4)。然后,我使用 %in%
运算符检查分配给变量 b
的值(在我的示例中,数字 1)是否包含在变量 other_var(i)
中;这会根据条件是否满足生成 TRUE 或 FALSE。
ifelse()
函数的 TRUE
部分。
这是最简单的部分,如果满足条件则赋值,a
(在我的例子中等于777
)。
ifelse()
函数的 FALSE
部分。
get(paste0("var",i))
:是变量本身的值(意思是如果不满足条件,则保持变量不变)。