我试图通过引用数据框列名并将它们插入等式而不是直接调用名称来使代码段更灵活。以下示例有效,但我必须直接插入字段名称:
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列并将其正确插入等式?
答案 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