循环遍历字符向量以在函数中使用

时间:2018-01-16 15:47:55

标签: r loops

我正在进行方法比较研究,比较来自两个不同系统的测量结果。我的数据集有大量列,其中包含来自两个系统之一的测量值的变量。

aX和bX都是X的度量,但是来自系统a和b。我有大约80对像这样的变异。

我的数据的简化版本如下所示:

set.seed(1)
df <- data.frame(
  ID = as.factor(rep(1:2, each=10)),
  aX = rep(1:10+rnorm(10,mean=1,sd=0.5),2),
  bX = rep(1:10+rnorm(10,mean=1,sd=0.5),2),
  aY = rep(1:10+rnorm(10,mean=1,sd=0.5), 2),
  bY = rep(1:10-rnorm(10,mean=1,sd=0.5),2))

head(df)

  ID       aX       bX       aY         bY
1  1 1.686773 2.755891 2.459489 -0.6793398
2  1 3.091822 3.194922 3.391068  1.0513939
3  1 3.582186 3.689380 4.037282  1.8061642
4  1 5.797640 3.892650 4.005324  3.0269025
5  1 6.164754 6.562465 6.309913  4.6885298
6  1 6.589766 6.977533 6.971936  5.2074973

我试图循环遍历字符向量的元素,并使用元素指向数据框中的列。但是当我尝试调用循环中生成的变量名称的函数时,我不断收到错误消息。

为简单起见,我已经将循环更改为包含线性模型,因为这会产生与原始脚本中相同类型的错误。

#This line is only included to show that
#the formula used in the loop works when
#called with directly with the "real" column names

(broom::glance(lm(aX~bX, data = df)))$r.squared

[1] 0.9405218

#Now I try the loop

varlist <- c("X", "Y")

for(i in 1:length(varlist)){
  aVAR <- paste0("a", varlist[i])
  bVAR <- paste0("b", varlist[i]) 

  #VAR and cVAR appear to have names identical column names in the df dataframe
  print(c(aVAR, bVAR))

  #Try the formula with the loop variable names
  print((broom::glance(lm(aVAR~bVAR, data = df)))$r.squared)
  }

从循环内部调用函数时得到的错误消息因我调用的函数而异,所有错误的共同点是当我尝试使用字符向量(varlist)时出现的错误具体栏目。

错误消息示例:

rmcorr(ID, aVAR, bVAR, df)

Error in rmcorr(ID, aVAR, bVAR, df) : 
  'Measure 1' and 'Measure 2' must be numeric

broom::glance(lm(aVAR~bVAR, data = df))

Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : 
  contrasts can be applied only to factors with 2 or more levels
In addition: Warning message:
In storage.mode(v) <- "double" : NAs introduced by coercion

你能帮我理解循环中出了什么问题吗?或建议并展示另一种方式来完成我想要做的事情。

2 个答案:

答案 0 :(得分:2)

变量不在公式中评估(具有~的东西)。

您可以输入

bert ~ ernie

即使名为berternie的变量不存在也不会出错。符号/名称之间的公式存储关系并不试图评估它们。另请注意,我们这里没有使用引号。变量名称(或符号)不能与字符值互换(即aX"aX"非常不同。

因此,当从字符串值中汇总公式时,我建议您使用reformualte()函数。它采用右侧的名称向量和左侧的可选值。因此,您将使用

创建相同的公式
reformulate("ernie", "bert")
# bert ~ ernie

你可以使用你的lm

lm(reformulate(bVAR, aVAR), data = df)

答案 1 :(得分:1)

我懒得搜索关于如何以编程方式构造公式的副本,所以这是一个解决方案:

varlist <- c("X", "Y")

for(i in 1:length(varlist)){
  #make these symbols:
  aVAR <- as.symbol(paste0("a", varlist[i]))
  bVAR <- as.symbol(paste0("b", varlist[i])) 

  #VAR and cVAR appear to have names identical column names in the df dataframe
  print(c(aVAR, bVAR))

  #Try the formula with the loop variable names
  #construct the call to `lm` with `bquote` and `eval` the expression
  print((broom::glance(eval(bquote(lm(.(aVAR) ~ .(bVAR), data = df)))))$r.squared)
}