Я пытаюсь записать функцию для принятия data.frame (x
) и a 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()
?
Вы можете просто использовать имя столбца напрямую:
df <- data.frame(A=1:10, B=2:11, C=3:12)
fun1 <- function(x, column){
max(x[,column])
}
fun1(df, "B")
fun1(df, c("B","A"))
Нет необходимости использовать замену, eval и т. Д.
Вы даже можете передать желаемое функция как параметр:
fun1 <- function(x, column, fn) {
fn(x[,column])
}
fun1(df, "B", max)
В качестве альтернативы, использование [[
также работает для выбора одного столбца за раз:
df <- data.frame(A=1:10, B=2:11, C=3:12)
fun1 <- function(x, column){
max(x[[column]])
}
fun1(df, "B")
Лично я считаю, что передавать столбец в виде строки довольно некрасиво. Мне нравится делать что-то вроде:
get.max <- function(column,data=NULL){
column<-eval(substitute(column),data, parent.frame())
max(column)
}
, что даст:
> get.max(mpg,mtcars)
[1] 33.9
> get.max(c(1,2,3,4,5))
[1] 5
Обратите внимание, что спецификация data.frame является необязательной. вы даже можете работать с функциями ваших столбцов:
> get.max(1/mpg,mtcars)
[1] 0.09615385