Rの高レベル関数 - 公式のコンポースオペレーターまたはカレー関数はありますか?
-
19-09-2019 - |
質問
RでCompose演算子を作成できます。
`%c%` = function(x,y)function(...)x(y(...))
このように使用する:
> numericNull = is.null %c% numeric
> numericNull(myVec)
[2] TRUE FALSE
しかし、この種のことを行うための公式の機能セットがあるかどうか、およびRでカリーするなどの他の操作があるかどうかを知りたいと思います。
私のカレー機能:
> curry=function(...){
z1=z0=substitute(...);z1[1]=call("list");
function(...){do.call(as.character(z0[[1]]),
as.list(c(eval(z1),list(...))))}}
> p = curry(paste(collapse=""))
> p(letters[1:10])
[1] "abcdefghij"
これは、EG Aggregateに特に最適です。
> df = data.frame(l=sample(1:3,10,rep=TRUE), t=letters[1:10])
> aggregate(df$t,df["l"],curry(paste(collapse="")) %c% toupper)
l x
1 1 ADG
2 2 BCH
3 3 EFIJ
私は以下よりもはるかにエレガントで編集可能だと思います:
> aggregate(df$t, df["l"], function(x)paste(collapse="",toupper(x)))
l x
1 1 ADG
2 2 BCH
3 3 EFIJ
基本的に知りたい - これはすでにRのために行われていますか?
解決
Rの機能プログラミングの標準的な場所は、今では functional
図書館。
図書館から:
機能:カレー、作曲、およびその他の高次関数
例:
library(functional)
newfunc <- Curry(oldfunc,x=5)
クラン:https://cran.r-project.org/web/packages/function/index.html
PS:このライブラリは置き換えます ROxigen
図書館。
他のヒント
これらの関数は両方ともに存在します roxygen
パッケージ (こちらのソースコードを参照してください)Peter Danenbergから(もともと基づいていた R-HELPでのバイロンエリスのソリューション):
Curry <- function(FUN,...) {
.orig = list(...);
function(...) do.call(FUN,c(.orig,list(...)))
}
Compose <- function(...) {
fs <- list(...)
function(...) Reduce(function(x, f) f(x),
fs,
...)
}
の使用に注意してください Reduce
R.で機能的なプログラミングを実行しようとするときに非常に役立つ機能。 Map
と Filter
).
カレーの例(この使用法がわずかに異なる):
> library(roxygen)
> p <- Curry(paste, collapse="")
> p(letters[1:10])
[1] "abcdefghij"
ユーティリティを示す例を次に示します Compose
(3つの異なる関数を文字に適用します):
> Compose(function(x) x[length(x):1], Curry(paste, collapse=""), toupper)(letters)
[1] "ZYXWVUTSRQPONMLKJIHGFEDCBA"
そして、あなたの最後の例は次のように機能します:
> aggregate(df[,"t"], df["l"], Compose(Curry(paste, collapse=""), toupper))
l x
1 1 ABG
2 2 DEFH
3 3 CIJ
最後に、同じことをする方法があります plyr
(簡単に実行することもできます by
また aggregate
すでに示されているように):
> library(plyr)
> ddply(df, .(l), function(df) paste(toupper(df[,"t"]), collapse=""))
l V1
1 1 ABG
2 2 DEFH
3 3 CIJ
変数の「名前」を正確に通過させる場合、より複雑なアプローチが必要です。
たとえば、そうする場合 plot(rnorm(1000),rnorm(1000))
その後、x軸とy軸に素敵なラベルが得られます。この別の例はです data.frame
> data.frame( rnorm(5), rnorm(5), first=rpois(5,1), second=rbinom(5,1,0.5) )
rnorm.5. rnorm.5..1 first second
1 0.1964190 -0.2949770 0 0
2 0.4750665 0.8849750 1 0
3 -0.7829424 0.4174636 2 0
4 1.6551403 1.3547863 0 1
5 1.4044107 -0.4216046 0 0
data.frameが有用な名前を列に割り当てたわけではありません。
カレーのいくつかの実装はこれを適切に行わず、読み取れない列名とプロットラベルにつながる場合があります。代わりに、私は今、このようなものを使用しています:
Curry <- function(FUN, ...) {
.orig = match.call()
.orig[[1]] <- NULL # Remove first item, which matches Curry
.orig[[1]] <- NULL # Remove another item, which matches FUN
function(...) {
.inner = match.call()
.inner[[1]] <- NULL # Remove first item, which matches Curry
do.call(FUN, c(.orig, .inner), envir=parent.frame())
}
}
これは非常に複雑ですが、正しいと思います。 match.call
すべてのARGSをキャッチし、どのような表現がARGSを定義したかを完全に覚えています(これは素敵なラベルに必要です)。問題は、それがあまりにも多くのargを捕まえることです - ただ ...
しかし、 FUN
. 。また、呼ばれている関数の名前を覚えています(Curry
).
したがって、これらの最初の2つのエントリをで削除する必要があります .orig
となることによって .orig
本当にに対応しています ...
議論。それが私たちがする理由です .orig[[1]]<-NULL
2回 - 毎回エントリを削除し、他のすべてを左にシフトします。
これにより定義が完了し、次のことを行うことができます まさに 上記と同じです
Curry(data.frame, rnorm(5), rnorm(5) )( first=rpois(5,1) , second=rbinom(5,1,0.5) )
に関する最後のメモ envir=parent.frame()
. 。これを使用して、「.inner」または「.orig」と呼ばれる外部変数がある場合、問題が発生しないようにしました。これで、すべての変数がカレーが呼ばれる場所で評価されます。