Этот ответ будет охватывать многие из тех же элементов, что и существующие ответы, но эта проблема (передача имен столбцов функциям) возникает достаточно часто, поэтому я хотел, чтобы был ответ, который охватывал бы вещи немного более всесторонне.
Предположим, у нас очень простой фрейм данных:
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
Это часто считается «лучшей практикой», так как это метод, который сложнее всего испортить. Передача имен столбцов в виде строк - это однозначно, насколько это возможно.
Следующие два параметра более продвинуты. Многие популярные пакеты используют методы такого рода, но их использование хорошо требует большей осторожности и навыков, поскольку они могут внести незначительные сложности и непредвиденные точки отказа. Этот раздел книги Advanced R от Hadley является отличным справочником по некоторым из этих проблем.
Если вы действительно хотите избавить пользователя от ввода всех этих кавычек, один из вариантов может заключаться в том, чтобы преобразовать имена столбцов без кавычек в строки, используя 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
и т. Д., Если вы действительно знаете, что делаете.