Я пытаюсь написать функцию для приема data.frame ( x
) и column
от нее. Функция выполняет некоторые вычисления для x и позже возвращает другой data.frame. Я застрял на передовом методе передачи имени столбца функции.
Два минимальных примера fun1
и fun2
приведенные ниже дают желаемый результат, позволяя выполнять операции x$column
, используя max()
в качестве примера. Однако оба полагаются на, казалось бы (по крайней мере, для меня) неизящный
- позвонить
substitute()
и, возможно,eval()
- необходимость передачи имени столбца как вектора символов.
fun1 <- function(x, column){
do.call("max", list(substitute(x[a], list(a = column))))
}
fun2 <- function(x, column){
max(eval((substitute(x[a], list(a = column)))))
}
df <- data.frame(B = rnorm(10))
fun1(df, "B")
fun2(df, "B")
Я хотел бы иметь возможность вызывать функцию fun(df, B)
, например, как. Другие варианты, которые я рассмотрел, но не пробовал:
- Передайте
column
как целое число номера столбца. Думаю, этого бы избежатьsubstitute()
. В идеале функция могла бы принять и то, и другое. with(x, get(column))
, но, даже если это сработает, я думаю, что для этого все равно потребуетсяsubstitute
- Используйте
formula()
иmatch.call()
, ни с одним из которых у меня нет большого опыта.
Подвопрос : Что do.call()
предпочтительнее eval()
?
B
будет предполагать, что B сам является объектом.[[
решение было единственным, которое сработало для меня.Этот ответ будет охватывать многие из тех же элементов, что и существующие ответы, но эта проблема (передача имен столбцов функциям) возникает достаточно часто, поэтому я хотел, чтобы был ответ, который охватывал бы вещи немного более полно.
Предположим, у нас есть очень простой фрейм данных:
и мы хотели бы написать функцию, которая создает новый столбец,
z
который представляет собой сумму столбцовx
иy
.Очень распространенный камень преткновения заключается в том, что естественная (но неправильная) попытка часто выглядит так:
Проблема здесь в том
df$col1
, что выражение не вычисляетсяcol1
. Он просто ищет столбец вdf
буквальном названииcol1
. Это поведение описано в?Extract
разделе «Рекурсивные (списковые) объекты».Самое простое и наиболее часто рекомендуемое решение - просто переключиться с
$
на[[
и передать аргументы функции в виде строк:Это часто считается «лучшей практикой», так как это метод, который труднее всего испортить. Передача имен столбцов в виде строк настолько однозначна, насколько это возможно.
Следующие два варианта являются более продвинутыми. Многие популярные пакеты используют такие методы, но их правильное использование требует большей осторожности и навыков, поскольку они могут внести тонкие сложности и непредвиденные точки отказа. Этот раздел книги Хэдли Advanced R является отличным справочником по некоторым из этих вопросов.
Если вы действительно хотите избавить пользователя от ввода всех этих кавычек, одним из вариантов может быть преобразование пустых имен столбцов без кавычек в строки, используя
deparse(substitute())
:Честно говоря, это, вероятно, немного глупо, поскольку мы действительно делаем то же самое, что и в
new_column1
, только с кучей дополнительной работы по преобразованию простых имен в строки.Наконец, если мы хотим по- настоящему фантазировать, мы могли бы решить, что вместо того, чтобы передавать имена двух столбцов для добавления, мы хотели бы быть более гибкими и разрешить другие комбинации двух переменных. В этом случае мы, скорее всего, прибегнем к использованию
eval()
выражения, включающего два столбца:Ради интереса, я все еще использую
deparse(substitute())
для имени нового столбца. Здесь будет работать все следующее:Итак, краткий ответ в основном таков: передавайте имена столбцов data.frame в виде строк и используйте их
[[
для выбора отдельных столбцов. Только начать углубляясьeval
,substitute
и т.д. , если вы действительно знаете , что вы делаете.источник
Лично я считаю, что передавать столбец в виде строки довольно некрасиво. Мне нравится делать что-то вроде:
что даст:
Обратите внимание на то, что спецификация data.frame не является обязательной. вы даже можете работать с функциями ваших столбцов:
источник
Другой способ - использовать
tidy evaluation
подход. Довольно просто передать столбцы фрейма данных в виде строк или простых имен столбцов. Подробнее об этомtidyeval
здесь .Используйте имена столбцов как строки
Используйте пустые имена столбцов
Создано 01.03.2019 пакетом REPEX (v0.2.1.9000)
источник
В качестве дополнительной мысли, если необходимо передать имя столбца без кавычек пользовательской функции, возможно, это также
match.call()
может быть полезно в этом случае в качестве альтернативыdeparse(substitute())
:Если в названии столбца допущена опечатка, безопаснее будет остановиться на ошибке:
Создано 11.01.2019 пакетом REPEX (v0.2.1)
Я не думаю, что буду использовать этот подход, поскольку существует дополнительная типизация и сложность, чем просто передача указанного имени столбца, как указано в приведенных выше ответах, но это подход.
источник