5

テーブルなどに変数ラベルを表示する一般的な方法として、次の関数/例を作成しました。

#' 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ですか? 答えは遅延評価に大きく依存すると思います。

4

1 に答える 1

5

eval と代入で答える

この場合、これを行うには、必要なだけだと思いますeval(substitute(expr))。 はプロミスであり、直接expr使用してプロミスの値を取得するか、 を使用してプロミスの内容を取得できます。詳細については、 http://cran.r-project.org/doc/manuals/R-lang.html#Promise-objectsを参照してください。promise の内容は であるため、新しい結果を取得するだけです。exprsubstitutecalleval

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するため異なることを示唆しているため、呼び出しではなく関数が必要です。

デフォルト引数時の異なる動作

興味深いことに、引数がデフォルトの引数であるか、ユーザーが追加したかによって、promise の動作が異なります。下記参照。SoDAはこれに対処していると思いますが、手元にありません。この関数は promise の値を出力し、それを で評価して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したがって、この場合、呼び出しフレームに表示されないため、ユーザーが指定した値は失敗します。

関数を使用した別の方法

ただし、私にとっては(OPは同意しませんが、この回答の将来の読者のためにこの部分を残しています)、これは、次のように関数を2番目のパラメーターとして使用する方が自然な場合のように感じます。1 つには、これは、ユーザーが関数内で呼び出されていることを知る必要がないことを意味し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 ...
于 2013-02-23T15:06:35.873 に答える