Углубиться в тайны оценки R ... Это тесно связано с моим предыдущим вопросом ( Как написать функцию R, которая оценивает выражение в кадре данных ]). Допустим, я хочу написать функцию topfn
, которая принимает фрейм данных и выражение, включающее имена столбцов этого фрейма данных. Я хочу передать оба этих аргумента другой функции fn
, которая фактически оценивает выражение в «среде» фрейма данных. И я хочу, чтобы оба fn
и topfn
работали правильно при передаче кадра данных и выражения
Моя первая попытка, как было предложено в ответе на вопрос выше , состоит в том, чтобы определить:
fn <- function(dfr, expr) {
mf <- match.call()
eval( mf$expr, envir = dfr )
}
И определить topfn
следующим образом:
topfn <- function(df, ex) {
mf <- match.call()
fn(df, mf$ex)
}
Теперь, если у меня есть фрейм данных
df <- data.frame( a = 1:5, b = 1:5 )
, внутренняя функция fn
работает нормально:
> fn(df,a)
[1] 1 2 3 4 5
Но topfn
не работает:
> topfn(df,a)
mf$ex
Чтобы исправить это, я сначала проверяю класс topfn (df, a)
,
> class(topfn(df,a))
[1] "call"
Это дает мне представление об уродливом взломе переопределить fn
следующим образом:
fn <- function(dfr, expr) {
mf <- match.call()
res <- eval(mf$expr, envir = dfr)
if(class(res) == 'call')
eval(expr, envir = dfr) else
res
}
И теперь обе функции работают:
> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5
Как я уже сказал, это выглядит ужасно. Есть ли лучший способ (или более стандартная идиома) заставить их работать? как предлагается в ответе на вышеупомянутый вопрос, это определить:
fn <- function(dfr, expr) {
mf <- match.call()
eval( mf$expr, envir = dfr )
}
И определить topfn
следующим образом:
topfn <- function(df, ex) {
mf <- match.call()
fn(df, mf$ex)
}
Теперь, если у меня есть фрейм данных
df <- data.frame( a = 1:5, b = 1:5 )
, внутренняя функция fn
работает нормально:
> fn(df,a)
[1] 1 2 3 4 5
Но topfn
не работает:
> topfn(df,a)
mf$ex
Чтобы исправить это, я сначала проверяю класс topfn (df, a)
,
> class(topfn(df,a))
[1] "call"
Это дает мне идею уродливого хака, чтобы переопределить fn
следующим образом:
fn <- function(dfr, expr) {
mf <- match.call()
res <- eval(mf$expr, envir = dfr)
if(class(res) == 'call')
eval(expr, envir = dfr) else
res
}
И теперь обе функции работают:
> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5
Как я уже сказал, это выглядит уродливым хаком. Есть ли лучший способ (или более стандартная идиома) заставить их работать? как предлагается в ответе на вышеупомянутый вопрос, это определить:
fn <- function(dfr, expr) {
mf <- match.call()
eval( mf$expr, envir = dfr )
}
И определить topfn
следующим образом:
topfn <- function(df, ex) {
mf <- match.call()
fn(df, mf$ex)
}
Теперь, если у меня есть фрейм данных
df <- data.frame( a = 1:5, b = 1:5 )
, внутренняя функция fn
работает нормально:
> fn(df,a)
[1] 1 2 3 4 5
Но topfn
не работает:
> topfn(df,a)
mf$ex
Чтобы исправить это, я сначала проверяю класс topfn (df, a)
,
> class(topfn(df,a))
[1] "call"
Это дает мне идею уродливого хака, чтобы переопределить fn
следующим образом:
fn <- function(dfr, expr) {
mf <- match.call()
res <- eval(mf$expr, envir = dfr)
if(class(res) == 'call')
eval(expr, envir = dfr) else
res
}
И теперь обе функции работают:
> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5
Как я уже сказал, это выглядит уродливым хаком. Есть ли лучший способ (или более стандартная идиома) заставить их работать?
> topfn(df,a)
mf$ex
Чтобы исправить это, я сначала проверяю класс topfn (df, a)
,
> class(topfn(df,a))
[1] "call"
Это дает мне идею уродливого хака для переопределения fn
следующим образом :
fn <- function(dfr, expr) {
mf <- match.call()
res <- eval(mf$expr, envir = dfr)
if(class(res) == 'call')
eval(expr, envir = dfr) else
res
}
И теперь обе функции работают:
> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5
Как я уже сказал, это выглядит уродливым взломом. Есть ли лучший способ (или более стандартная идиома) заставить их работать?
> topfn(df,a)
mf$ex
Чтобы исправить это, я сначала проверяю класс topfn (df, a)
,
> class(topfn(df,a))
[1] "call"
Это дает мне идею уродливого хака для переопределения fn
следующим образом :
fn <- function(dfr, expr) {
mf <- match.call()
res <- eval(mf$expr, envir = dfr)
if(class(res) == 'call')
eval(expr, envir = dfr) else
res
}
И теперь обе функции работают:
> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5
Как я уже сказал, это выглядит уродливым взломом. Есть ли лучший способ (или более стандартная идиома) заставить их работать? Я проконсультировался с документом Lumley с любопытным названием Standard NonStandard Evaluation Rules http://developer.r-project.org/nonstandard-eval.pdf , но после его прочтения не получил особого понимания. Также были бы полезны любые указатели на исходный код функций, которые я могу посмотреть в качестве примеров.