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