如何将数据帧列名插入等式R?

时间:2014-09-20 23:47:36

标签: r variables

我试图通过引用数据框列名并将它们插入等式而不是直接调用名称来使代码段更灵活。以下示例有效,但我必须直接插入字段名称:

require(e1071)

class = c(0.25, 0.34, 0.55)
field1 = c(23, 33, 34)
field2 = c(44, 55, 32)

df = data.frame(class, field1, field2)

mysvm = svm(class ~ field1 + field2, data = df)

以下示例有效,我不知道原因:

require(e1071)

class = c(0.25, 0.34, 0.55)
field1 = c(23, 33, 34)
field2 = c(44, 55, 32)

df = data.frame(class, field1, field2)

name1 = names(df)[2]
name2 = names(df)[3]

mysvm = svm(class ~ name1 + name2, data = df)

如何引用数据框中的第2列和第3列并将其正确插入等式?

5 个答案:

答案 0 :(得分:2)

变量name1包含一个等于names(df)[2]的字符串,假设它是"foo"。当svm收到带有formula的{​​{1}}对象时,它会搜索名为name1的对象,并用该值替换该对象。也就是说,name1正试图在长度为一的字符向量svm上“回归”变量class,这当然没有意义。

这里的一个解决方法是将公式创建为字符串,然后在事后将其转换为公式。这是我不时使用的实用功能:

"foo"

答案 1 :(得分:2)

我不确定你是否关心公式如何在通话输出中读取,但是为了评估它你可以做到

> foo <- function(n1, n2) {
      as.formula(paste("class~", paste(n1, n2, sep = "+")))
  }
> foo(name1, name2)
# class ~ field1 + field2
# <environment: 0x4d0da58>
> svm(foo(name1, name2), data = df)
#
# Call:
# svm(formula = foo(name1, name2), data = df)
#
#    
# Parameters:
#    SVM-Type:  eps-regression 
#  SVM-Kernel:  radial 
#        cost:  1 
#       gamma:  0.5 
#     epsilon:  0.1 
#
# Number of Support Vectors:  3

答案 2 :(得分:2)

这里有2个选项:

您可以通过作为参数提供的列名称对data.frame进行子集化,并对公式的左侧术语使用dot表示法:

svm_func <- function(ll=c("field1","field1"),xx=df){
  print(df[,c("class",ll)])
  svm(class ~ ., data = df[,c("class",ll)])
}

或者您使用slam的forumla版本,类似于其他解决方案,但在这里我使用do.call将公式创建概括为任意数量的参数:

svm_func_form <- function(ll=list("field1","field1"),xx=df){
  left_term <- do.call(paste,list(ll,collapse="+"))
  form <- as.formula(paste("class",left_term,sep="~"))
  svm(formula =form,data =xx)
}

答案 3 :(得分:2)

以下是一些通过引用传递变量并将其插入Call公式的方法。第一行是从@Richard Scriven的函数

复制而来的
 fun1 <- function(n1, n2){
 form1 <- as.formula(paste("class~", paste(n1, n2, sep = "+")))
 do.call("svm", list(form1, quote(df)))
 }    

 fun1(name1, name2)

 #Call:
 #svm(formula = class ~ field1 + field2, data = df)


 #Parameters:
 # SVM-Type:  eps-regression 
 # SVM-Kernel:  radial 
 #  cost:  1 
 # gamma:  0.5 
 # epsilon:  0.1 


 #Number of Support Vectors:  3

或者

 fun2 <- function(n1, n2){
 form1 <- as.formula(paste("class~", paste(n1, n2, sep="+")))
 eval(substitute(svm(f, df), list(f = form1)))
 }  

 fun2(name1, name2)

 #Call:
 #svm(formula = class ~ field1 + field2, data = df)


 #Parameters:
 # SVM-Type:  eps-regression 
 # SVM-Kernel:  radial 
 #  cost:  1 
 # gamma:  0.5 
 #  epsilon:  0.1 


 #Number of Support Vectors:  3

或者您可以将@Rchard Scriven的函数作为fun3

中的参数传递
 fun2New <- function(n1, n2){
  as.formula(paste("class~", paste(n1, n2, sep="+")))
  }



 fun3 <- function(formula, data, ...){
 Call <- match.call(expand.dots = TRUE)
 Call[[1]] <- as.name("svm")
 Call$formula <- as.formula(terms(formula))
 eval(Call)
 }

 fun3(fun2New(name1, name2), df)

 #Call:
 #svm(formula = class ~ field1 + field2, data = df)


 #Parameters:
 # SVM-Type:  eps-regression 
 # SVM-Kernel:  radial 
 #  cost:  1 
 # gamma:  0.5 
 # epsilon:  0.1 


 #Number of Support Vectors:  3

答案 4 :(得分:1)

使用您自己的代码,只需使用get(name1)而不是name1!

> mysvm = svm(class ~ get(name1) + get(name2), data = df)
> mysvm

Call:
svm(formula = class ~ get(name1) + get(name2), data = df)


Parameters:
   SVM-Type:  eps-regression 
 SVM-Kernel:  radial 
       cost:  1 
      gamma:  0.5 
    epsilon:  0.1 


Number of Support Vectors:  3