私は視覚化のためにほとんどggplot2
を使用します。通常は、プロット を対話的に設計します(つまり、NSEを使用する生のggplot2
コード)が、最終的には のプロットを受け取る関数にそのコードをラップアップしてしまいます。そして、これはいつも悪夢の少しです。 関数内のggplot2の遅延評価
したがって、一般的な状況は次のようになります。私はいくつかのデータを持っており、私は のプロットを作成しています(この場合は、のデータセットを とした非常に簡単な例です)。
library(ggplot2)
data(mpg)
ggplot(data = mpg,
mapping = aes(x = class, y = hwy)) +
geom_boxplot() +
geom_jitter(alpha = 0.1, color = "blue")
そして、私はプロットの設計が終了したら、私は通常、など 異なる変数やデータ、のためにそれを使用したいので、私は、引数として、プロットのため データと変数を受け取る関数を作成。しかしNSEのために、それは関数ヘッダのために であり、関数引数のために変数 をコピー/ペーストして置き換えるほど簡単ではありません。以下のように、それはうまくいかないでしょう。
mpg <- mpg
plotfn <- function(data, xvar, yvar){
ggplot(data = data,
mapping = aes(x = xvar, y = yvar)) +
geom_boxplot() +
geom_jitter(alpha = 0.1, color = "blue")
}
plotfn(mpg, class, hwy) # Can't find object
## Don't know how to automatically pick scale for object of type function. Defaulting to continuous.
## Warning: restarting interrupted promise evaluation
## Error in eval(expr, envir, enclos): object 'hwy' not found
plotfn(mpg, "class", "hwy") #
だから私はaes_string
NSEを使用していますaes
のintead(この例では、それはかなり簡単ですが、より複雑なプロットの を使用して、例えば、戻って、コードを修正する必要があり、多くの変換とレイヤーで、 これは悪夢になります)。
plotfn <- function(data, xvar, yvar){
ggplot(data = data,
mapping = aes_string(x = xvar, y = yvar)) +
geom_boxplot() +
geom_jitter(alpha = 0.1, color = "blue")
}
plotfn(mpg, "class", "hwy") # Now this works
この事は、私は非常に便利NSEを見つけてもlazyeval
ということです。だから 私はこのようなことをしたい。
plotfn(NULL, rep(letters[1:4], 250), 1:100) # And even this crazyness works
これは、多くの柔軟性を私のプロット機能を提供します
plotfn(mpg, "class", "hwy") # This still works
mpg <- mpg
plotfn <- function(data, xvar, yvar){
data_gd <- data.frame(
xvar = lazyeval::lazy_eval(substitute(xvar), data = data),
yvar = lazyeval::lazy_eval(substitute(yvar), data = data))
ggplot(data = data_gd,
mapping = aes(x = xvar, y = yvar)) +
geom_boxplot() +
geom_jitter(alpha = 0.1, color = "blue")
}
plotfn(mpg, class, hwy) # Now this works
。たとえば、 には、変数名(レイジー評価の悪用のようなもの)ではなく、引用または引用されていない変数名、さらには直接データの を渡すことができます。
しかし、これには大きな問題があります。関数はプログラムで を使用することはできません。
dynamically_changing_xvar <- "class"
plotfn(mpg, dynamically_changing_xvar, hwy)
## Error in eval(expr, envir, enclos): object 'dynamically_changing_xvar' not found
# This does not work, because it never finds the object
# dynamically_changing_xvar in the data, and it does not get evaluated to
# obtain the variable name (class)
だから、変数、またはデータの 異なる組み合わせに対して同じプロットを生成するために(例えばlapply)ループを使用することはできません。
私はさらに、怠惰な標準と標準でない標準の 評価を悪用し、これらをすべて組み合わせてみると、上記の柔軟性 とその機能をプログラムで使用することができます。 基本的には、tryCatch
最初にlazy_eval
式を各変数に使用し、失敗した場合は、解析済みの 式を評価することです。
plotfn <- function(data, xvar, yvar){
data_gd <- NULL
data_gd$xvar <- tryCatch(
expr = lazyeval::lazy_eval(substitute(xvar), data = data),
error = function(e) eval(envir = data, expr = parse(text=xvar))
)
data_gd$yvar <- tryCatch(
expr = lazyeval::lazy_eval(substitute(yvar), data = data),
error = function(e) eval(envir = data, expr = parse(text=yvar))
)
ggplot(data = as.data.frame(data_gd),
mapping = aes(x = xvar, y = yvar)) +
geom_boxplot() +
geom_jitter(alpha = 0.1, color = "blue")
}
plotfn(mpg, class, hwy) # Now this works, again
plotfn(mpg, "class", "hwy") # This still works, again
plotfn(NULL, rep(letters[1:4], 250), 1:100) # And this crazyness still works
# And now, I can also pass a local variable to the function, that contains
# the name of the variable that I want to plot
dynamically_changing_xvar <- "class"
plotfn(mpg, dynamically_changing_xvar, hwy)
したがって、前述の柔軟性に加えて、 の1ライナーなどを使用して、同じプロットの多くを異なる 変数(またはデータ)で作成することができます。
lapply(c("class", "fl", "drv"), FUN = plotfn, yvar = hwy, data = mpg)
## [[1]]
##
## [[2]]
##
## [[3]]
、それは非常に実用的ですが、私はこれは良い習慣ではないと思います。しかし、 それはいかに悪い練習ですか?それが私の重要な質問です。何が他の選択肢 私は両方の世界の最高のを使用することができますか?
もちろん、私はこのパターンが問題を引き起こすことがあります。例えば。
# If I have a variable in the global environment that contains the variable
# I want to plot, but whose name is in the data passed to the function,
# then it will use the name of the variable and not its content
drv <- "class"
plotfn(mpg, drv, hwy) # Here xvar on the plot is drv and not class
そして、いくつかの(多く?)他の問題。しかし、構文柔軟性の点で の利点が他の問題よりも優れているように思えます。これについての考えは?あなたが自由に文字列を混在させることができますので、
library(ggplot2)
data(mpg)
plotfn <- function(data, xvar, yvar){
data_gd <- NULL
data_gd$xvar <- tryCatch(
expr = lazyeval::lazy_eval(substitute(xvar), data = data),
error = function(e) eval(envir = data, expr = parse(text=xvar))
)
data_gd$yvar <- tryCatch(
expr = lazyeval::lazy_eval(substitute(yvar), data = data),
error = function(e) eval(envir = data, expr = parse(text=yvar))
)
ggplot(data = as.data.frame(data_gd),
mapping = aes(x = xvar, y = yvar)) +
geom_boxplot() +
geom_jitter(alpha = 0.1, color = "blue")
}
このような機能は、一般的に非常に有用であり、裸の変数名:
ベストプラクティスは、一対の関数を生成することです。 1つはNSEで、もう1つはSEです。これは 'vignette( 'nse')'で概説されています。これは 'aes'の代わりに' aes_'を使うことを意味します。 – Axeman
ありがとう、...、ええ、私は答えになるだろうと恐れていました。私はdplyr&coの利点を見ていますが。 "一貫した命名体系:SEは最後に_が付いたNSE名です"というのは、プログラミングやインタラクティブな作業のために別の関数を使用しなければならないというバグです。 – elikesprogramming