2014-09-20 28 views
2

我想通过引用数据框列名并将它们插入到一个公式中来使代码段更加灵活,而不是直接调用名称。下面的示例工作,虽然要直接插入字段名称:如何在方程R中插入数据帧的列名?

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列并将它们正确地插入到等式中?

回答

2

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

此处的一种解决方法是将该公式创建为字符串,然后在事实后将其转换为公式。下面是我从不时使用的效用函数:

xyform <- function (y_var, x_vars) { 
# y_var: a length-one character vector 
# x_vars: a character vector of object names 
    as.formula(sprintf("%s ~ %s", y_var, paste(x_vars, collapse = " + "))) 
} 
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种选择:

要么你子集的data.frame,通过作为参数的列名,并使用dot符号为您的公式的左边项:

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

或者你使用SVM的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) 
} 
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 
2

以下是一些通过引用传递变量的方法,并将其插入Call公式中。第一行是从@Richard斯克里芬的功能复制

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斯克里芬的函数作为参数在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 
+0

如何'fun2New'任何不同于我的函数'foo'? – 2014-09-21 14:57:38

+0

@Richard Scriven我用'fun2New'作为'fun3'的参数来改变'Call'语句中的公式。我应该把这个函数放在'fun3'里面。但是,不知何故没有得到它的正确。无论如何,OP似乎不希望这种功能。所以,我没有为此工作。 – akrun 2014-09-21 15:45:29

+0

但是你是否从理查德的答案中复制了它,但没有归属? – 2014-09-21 16:05:22