這個答案將涵蓋許多相同的要素,現有的答案,但這個問題(通過列名的功能)出現往往不夠,我想那裏是這個答案涵蓋了更全面的一點。
假設我們有一個非常簡單的數據幀:
dat <- data.frame(x = 1:4,
y = 5:8)
,我們想編寫創建一個新列z
是列x
和y
的總和的函數。
一個非常常見的障礙這裏塊是自然的(但不正確的)嘗試往往是這樣的:
foo <- function(df,col_name,col1,col2){
df$col_name <- df$col1 + df$col2
df
}
#Call foo() like this:
foo(dat,z,x,y)
的這裏的問題是,df$col1
不計算表達式col1
。它只是尋找df
中的一個字面,字面意思是col1
。在「遞歸(類似列表)對象」一節下的?Extract
中描述了此行爲。
最簡單,也是最經常被推薦的解決方案是簡單地從$
切換到[[
和傳遞函數的參數爲字符串:
new_column1 <- function(df,col_name,col1,col2){
#Create new column col_name as sum of col1 and col2
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column1(dat,"z","x","y")
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
這通常被認爲是「最佳實踐」,因爲它是最難的方法搞砸了。將列名作爲字符串傳遞的過程與您所能得到的一樣毫無疑義。
以下兩個選項更爲先進。許多流行的軟件包都使用這些技術,但使用它們以及需要更多的關心和技巧,因爲它們可以引入微妙的複雜性和意想不到的失敗點。 This哈德利的高級R書的一部分是這些問題的一個很好的參考。
如果你真的想節省打字所有這些報價的用戶,一個選擇可能是使用deparse(substitute())
裸,不帶引號的列名轉換爲字符串:
new_column2 <- function(df,col_name,col1,col2){
col_name <- deparse(substitute(col_name))
col1 <- deparse(substitute(col1))
col2 <- deparse(substitute(col2))
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column2(dat,z,x,y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
這是坦率地說,有點很可能愚蠢,因爲我們真的在做與new_column1
一樣的事情,只是將一些額外的工作轉換爲裸字符串。最後,如果我們想要得到真的是,我們可能會決定不是傳遞兩列的名稱來添加,而是希望更靈活,並允許其他兩個變量的組合。在這種情況下,我們可能會採取對涉及的兩列表達式中使用eval()
:
new_column3 <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
df[[col_name]] <- eval(substitute(expr),df,parent.frame())
df
}
只是爲了好玩,我還在使用deparse(substitute())
新列的名稱。在這裏,所有的下面方法:
> new_column3(dat,z,x+y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
> new_column3(dat,z,x-y)
x y z
1 1 5 -4
2 2 6 -4
3 3 7 -4
4 4 8 -4
> new_column3(dat,z,x*y)
x y z
1 1 5 5
2 2 6 12
3 3 7 21
4 4 8 32
所以,簡單的答案基本上是:通過data.frame列名字串,並且使用[[
選擇單個列。只有開始深入研究eval
,substitute
等,如果你真的知道你在做什麼。
有什麼辦法可以將列名不作爲字符串? – kmm 2010-04-14 23:13:02
您需要將列名引用爲字符或列的整數索引。只要傳遞'B'就會認爲B是一個對象本身。 – Shane 2010-04-14 23:14:56
我明白了。我不確定我是如何以複雜的替代品,eval等結尾的。 – kmm 2010-04-14 23:17:36