在R中循环遍历变量名

6
我遇到了循环问题。这个问题应该很容易解决,但是《R for Stata Users》(我使用Stata编程已经有几年了)、Roger Peng的视频和Google似乎都没有帮助到我。你们中的某个人能否向我解释一下我错在哪里?
我正在尝试编写一个循环,通过运行 'thresholds' 数据帧来提取三组列的信息。我可以通过三次编写相同的代码段来实现我想要的功能,但是随着代码变得更加复杂,这将变得非常繁琐。
以下是'thresholds'的示例(由友好的读者添加的dput输出):
    threshold_1_name      threshold_1_dir threshold_1_value
1   overweight            >                25
2   possible malnutrition <                31
3   Q1                    >                998
4   Q1                    >                998
5   Q1                    >                998
6   Q1                    >                998
    threshold_1_units threshold_2_name threshold_2_dir threshold_2_value threshold_2_units
1   kg/m^2            obese               >             30                kg/m^2
2   cm                <NA>                >             NA                   
3   <NA>              Q3                  >             998                  
4                     Q3                  >             998                  
5                     Q3                  >             998                  
6                     Q3                  >             998  

这段代码实现了我想要的功能:
newvars1 <- paste(thresholds$varname, thresholds$threshold_1_name, sep = "_")
noval <- is.na(thresholds$threshold_1_value)
newvars1 <- newvars1[!noval]

newvars2 <- paste(thresholds$varname, thresholds$threshold_2_name, sep = "_")
noval <- is.na(thresholds$threshold_2_value)
newvars2 <- newvars2[!noval]

newvars3 <- paste(thresholds$varname, thresholds$threshold_3_name, sep = "_")
noval <- is.na(thresholds$threshold_3_value)
newvars3 <- newvars3[!noval]

以下是我尝试循环的方式:

variables <- NULL
for (i in 1:3) {
  valuevar <- paste("threshold", i, "value", sep = "_")
  namevar <- paste("threshold", i, "name", sep = "_")
  newvar <- paste("varnames", i, sep = "")
  for (j in 1:length(thresholds$varname)) { 
    check <- is.na(thresholds[valuevar[j]])
    if (check == FALSE) {
      newvars <- paste(thresholds$varname, thresholds[namevar], sep = "_")
    }
  }
  variables <- c(variables, newvars)
}

这里是我收到的错误信息:

Error: unexpected '}' in "}"

我认为我调用“i”的方式有些问题,但是我不确定该如何正确地做。随着我从Stata切换到R,我的习惯使用本地变量正在困扰着我。
编辑以添加友好读者的dput输出:
thresholds <- structure(list(varname = structure(1:6, .Label = c("varA", "varB", 
"varC", "varD", "varE", "varF"), class = "factor"), threshold_1_name = c("overweight", 
"possible malnutrition", "Q1", "Q1", "Q1", "Q1"), threshold_1_dir = c(">", 
"<", ">", ">", ">", ">"), threshold_1_value = c(25L, 31L, 998L, 
998L, 998L, 998L), threshold_1_units = c("kg/m^2", "cm", NA, 
NA, NA, NA), threshold_2_name = c("obese", "<NA>", "Q3", "Q3", 
"Q3", "Q3"), threshold_2_dir = c(">", ">", ">", ">", ">", ">"
), threshold_2_value = c(30L, NA, 998L, 998L, 998L, 998L), threshold_2_units = c("kg/m^2", 
"cm", NA, NA, NA, NA)), .Names = c("varname", "threshold_1_name", 
"threshold_1_dir", "threshold_1_value", "threshold_1_units", 
"threshold_2_name", "threshold_2_dir", "threshold_2_value", "threshold_2_units"
), row.names = c(NA, -6L), class = "data.frame")

1
你的错误是在这一行缺少一个右括号 for (j in 1:length(thresholds$varname) { - Blue Magister
@BlueMagister 我没有看到那个。他的代码第11行包含了那个的闭合符。 - Brandon Bertelsen
@BrandonBertelsen 第11行关闭了花括号,但是for语句没有闭合括号。 - Blue Magister
你能提供一下你正在使用的数据框的样本吗?类似于复制粘贴 dput(head(thresholds)) 这样的内容?请参考这里以获得一个好的可重现的示例。 - Blue Magister
3个回答

6
我看到的第一个问题是在if(check = "FALSE")中,这是一个赋值=,如果你要测试一个条件,它需要是==。此外,引用单词"FALSE"意味着你正在测试一个变量是否为字符串值(字面上的单词FALSE),而不是逻辑值,逻辑值应该是没有引号的FALSE
第二个问题被@BlueMagister正确指出,你在for(j in 1:length(...)){结尾处缺少)
请注意# bad!
  for (j in 1:length(thresholds$varname)) { 
    check <- is.na(thresholds[valuevar[j]])
    if (check = "FALSE") { # bad!
      newvars <- paste(thresholds$varname, thresholds[namevar], sep = "_")
    }
  }

看起来不错!

  for (j in 1:length(thresholds$varname)) { 
    check <- is.na(thresholds[valuevar[j]])
    if (check == FALSE) { # good!
      newvars <- paste(thresholds$varname, thresholds[namevar], sep = "_")
    }
  }

但由于这是一个if语句,您可以使用非常简单的逻辑,尤其是在逻辑(TRUE / FALSE值)上。

看到#更好了!

  for (j in 1:length(thresholds$varname)) { 
    check <- is.na(thresholds[valuevar[j]])
    if (!check) { # better!
      newvars <- paste(thresholds$varname, thresholds[namevar], sep = "_")
    }
  }

感谢您解释这个问题。这个解释非常清晰和有帮助! - Struggling_with_R
1
如果这个回答解决了你的问题,请考虑点击勾选标记,向其他用户表明这是最佳答案。 - Joshua Ulrich
1
@JoshuaUlrich:我认为是相反的,因为"FALSE"是字符,逻辑检查被转换为字符,然后逻辑上的FALSE就变成了"FALSE"。 - Aaron left Stack Overflow
@Aaron:正确,"如果两个参数是不同类型的原子向量,则将一个强制转换为另一个的类型,优先级(递减)顺序为字符、复数、数字、整数、逻辑和原始数据。" - Joshua Ulrich
@BrandonBertelsen:当然是?"=="。:) 详细信息部分的倒数第三段。 - Joshua Ulrich
显示剩余2条评论

1

你的for循环中显然缺少一个括号。为了避免这种错误,建议你考虑使用支持大括号匹配的编辑器。


0

我认为最简单的方法就是编写一个函数,执行您所需的非循环代码。 供参考,这是使用您问题编辑中的dput输出的代码输出。

> newvars1 <- paste(thresholds$varname, thresholds$threshold_1_name, sep = "_")
> newvars1 <- newvars1[!is.na(thresholds$threshold_1_value)]
> newvars2 <- paste(thresholds$varname, thresholds$threshold_2_name, sep = "_") 
> newvars2 <- newvars2[!is.na(thresholds$threshold_2_value)]
> c(newvars1, newvars2)
 [1] "varA_overweight"            "varB_possible malnutrition"
 [3] "varC_Q1"                    "varD_Q1"                   
 [5] "varE_Q1"                    "varF_Q1"                   
 [7] "varA_obese"                 "varC_Q3"                   
 [9] "varD_Q3"                    "varE_Q3"                   
[11] "varF_Q3"  

这是函数的样子:

unlist(lapply(1:2, function(k) {
  newvars <- paste(thresholds$varname, 
                   thresholds[[paste("threshold", k, "name", sep="_")]], sep = "_")
  newvars <- newvars[!is.na(thresholds[[paste("threshold", k, "value", sep="_")]])]
}))
# [1] "varA_overweight"            "varB_possible malnutrition"
# [3] "varC_Q1"                    "varD_Q1"                   
# [5] "varE_Q1"                    "varF_Q1"                   
# [7] "varA_obese"                 "varC_Q3"                   
# [9] "varD_Q3"                    "varE_Q3"                   
#[11] "varF_Q3"  

我试图弄清楚你的循环中发生了什么,但其中有很多东西对我来说都不合理;如果我要以那种方式循环,这就是我会写的方式。

variables <- NULL
for (i in 1:2) {
  valuevar <- paste("threshold", i, "value", sep = "_")
  namevar <- paste("threshold", i, "name", sep = "_")
  newvars <- c()
  for (j in 1:nrow(thresholds)) { 
    if (!is.na(thresholds[[valuevar]][j])) {
      newvars <- c(newvars, paste(thresholds$varname[j], 
                                  thresholds[[namevar]][j], sep = "_"))
    }
  }
  variables <- c(variables, newvars)
}
variables

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接