2014-09-20 45 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