2013-02-23 2 views
4

Я создал следующую функцию/пример как общий способ отображения метки переменных в таблицах и так далее:оценка экспрессии Defer без использования `quote`

#' Function to prettify the output of another function using a `var.labels` attribute 
#' This is particularly useful in combination with read.dta et al. 
#' @param dat A data.frame with attr `var.labels` giving descriptions of variables 
#' @param expr An expression to evaluate with pretty var.labels 
#' @return The result of the expression, with variable names replaced with their labels 
#' @examples 
#' testDF <- data.frame(a=seq(10),b=runif(10),c=rnorm(10)) 
#' attr(testDF,"var.labels") <- c("Identifier","Important Data","Lies, Damn Lies, Statistics") 
#' prettify(testDF, quote(str(dat))) 
prettify <- function(dat, expr) { 
    labels <- attr(dat,"var.labels") 
    for(i in seq(ncol(dat))) colnames(dat)[i] <- labels[i] 
    attr(dat,"var.labels") <- NULL 
    eval(expr) 
} 

Я предпочел бы пользователь не должен цитировать однако переданное выражение.

replicate делает только что, используя этот код:

eval.parent(substitute(function(...) expr)) 

Но я не понимаю, как это работает, и как это характерно для попытки повторить без понимания, мои попытки просто скопировать этот код или подправлять с ним все провалилось.

Как написать функцию с неоценимым выражением в качестве входных данных, не требуя от пользователя выражения quote? Я предполагаю, что ответ будет сильно зависеть от ленивой оценки.

+0

О том, что 'replicate' делает, я ничего не проверял, но я думаю, что' функцию (...) 'способ передать дополнительные параметры в выражении, и' eval.parent' оценивает его в родительской среде, а не в среде функций. Вероятно, это будет причина, по которой это не будет работать в вашем случае, поскольку 'dat' не находится в родительской среде. – Aaron

+0

Кроме того, в предлагаемом редактировании @ user2103369 предполагает, что 'replicate' отличается, потому что он использует' sapply' для получения нескольких оценок, поэтому ему нужна функция, а не вызов. – Aaron

ответ

5

Ответ с Eval и замена

Я думаю, что сделать это в этом случае вам просто нужно eval(substitute(expr)). expr - это обещание, и мы можем либо получить стоимость обещания, используя expr напрямую, либо содержание обещания, используя substitute. См. http://cran.r-project.org/doc/manuals/R-lang.html#Promise-objects. Содержание обещания - call, поэтому мы просто eval, чтобы получить новый результат.

prettify <- function(dat, expr) { 
    labels <- attr(dat,"var.labels") 
    for(i in seq(ncol(dat))) colnames(dat)[i] <- labels[i] 
    attr(dat,"var.labels") <- NULL 
    eval(substitute(expr)) 
} 

> prettify(testDF, str(dat)) 
'data.frame': 10 obs. of 3 variables: 
$ Identifier     : int 1 2 3 4 5 6 7 8 9 10 
$ Important Data    : num 0.336 0.9479 0.1379 0.94 0.0484 ... 
$ Lies, Damn Lies, Statistics: num 1.398 0.654 0.268 -0.397 -0.41 ... 

В предлагаемом редактировании, @ user2103369 предполагает, что replicate отличается тем, что он использует sapply получить несколько оценок, поэтому она нуждается в функции, а не вызов.

Различного поведение, когда аргумент по умолчанию

Интересно, что обещание действует по-разному в зависимости от того, если аргумента является аргументом или добавлен пользователем по умолчанию; Смотри ниже. Я думаю, что SoDA решает это, но у меня нет его под рукой. Эта функция печатает значение обещания, оценивает его с помощью eval, а затем оценивает его напрямую.

foo <- function(a, b=a+1) { 
    print(substitute(b)) 
    print(eval(substitute(b))) 
    b 
} 

Оценка его непосредственно приводит к ошибке, когда пользователь поставляет это значение.

> foo(a=2, b=a+1) 
a + 1 
[1] 3 
Error in foo(a = 2, b = a + 1) : object 'a' not found 

Но значение по умолчанию работает.

> foo(a=2) 
a + 1 
[1] 3 
[1] 3 

В предлагаемом редактировании, @ user2103369 говорит, что аргумент по умолчанию вычисляется внутри функция, в то время как явный аргумент вычисляется в вызывающем кадре. Таким образом, в этом случае значение, предоставленное пользователем, терпит неудачу, потому что a не отображается в вызывающем фрейме.

Альтернативный метод с использованием функции

Однако для меня (хотя ОП не согласен, я оставляю эту часть для будущих читателей этого ответа), это чувствует, как случай, где это более естественно использовать как второй параметр; для одного, это означает, что пользователь не должен знать, что он называется dat внутри функции.

prettify <- function(dat, FUN) { 
    f <- match.fun(FUN) 
    labels <- attr(dat,"var.labels") 
    for(i in seq(ncol(dat))) colnames(dat)[i] <- labels[i] 
    attr(dat,"var.labels") <- NULL 
    f(dat) 
} 

Тогда его можно назвать с анонимной функцией, которая является именно то, что вы ищете, я думаю, за исключением того, что пользователь должен ввести function(x), а также.

> prettify(testDF, function(x) str(x)) 
'data.frame': 10 obs. of 3 variables: 
$ Identifier     : int 1 2 3 4 5 6 7 8 9 10 
$ Important Data    : num 0.296 0.707 0.883 0.821 0.724 ... 
$ Lies, Damn Lies, Statistics: num -1.1506 0.4846 -1.824 -0.397 0.0898 ... 

Или в простых случаях, как в вашем примере, только с именем функции.

> prettify(testDF, str) 
'data.frame': 10 obs. of 3 variables: 
$ Identifier     : int 1 2 3 4 5 6 7 8 9 10 
$ Important Data    : num 0.296 0.707 0.883 0.821 0.724 ... 
$ Lies, Damn Lies, Statistics: num -1.1506 0.4846 -1.824 -0.397 0.0898 ... 
+0

Я думал о наличии функции в качестве аргумента (в этом случае, определенно, вы захотите написать в каком-то действии '...'), но версия выражения кажется намного проще использовать для меня, и поэтому мой вопрос остается. –

+0

Достаточно честный. Я чувствую, что он должен просто работать без 'eval', поскольку' expr' является обещанием и не будет оцениваться до его вызова, но в моих тестах это не так. Хотел бы, чтобы у меня была копия SoDA передо мной, чтобы я мог перечитать, как это работает. – Aaron

+0

Благодаря @ user2103369 за предложение некоторых изменений. Я включил их контент. (На мой взгляд, комментирование - это лучший способ взаимодействовать с респондентом о содержании сообщения, прямое редактирование - для незначительных проблем с орфографией/грамматикой или когда ответчик больше не активен.) – Aaron

Смежные вопросы