10

Rで関数を連鎖させることは可能ですか?

サンプルデータ:

m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2)

たとえば、次のステートメントを置き換えたいと思います。

step1 <- mean(m)
step2 <- sum(step1)
res <- step2

または、

res <- sum(mean(m))

このようなもので:

res <- m@mean()@sum()

場合によっては、それで私のコードがかなり明確になります。

EDIT1これはダミーの例です。「sum」と「mean」をランダムに選びました。

ベンは%@%を使用して最初の答えを出しましたが、関数内で余分な引数を使用することはできません。

m %@% function1(arg1, arg2) %@% function2(arg1, arg2)

どうすればそれを回避できますか?

EDIT2例を追加する

require(xts)
require(PerformanceAnalytics)
xts.ts <- xts(rnorm(231),as.Date(13514:13744,origin="1970-01-01"))
plot(na.omit(lag( rollapply(xts.ts, width=rolling.per-1, FUN= function(x){sqrt(var(x))*sqrt(252)}), k=1)), main = "Dummy Example")

この例は、Charlesソリューションで正常に機能するようです。

`%@%` <- function(x, f) eval.parent(as.call(append(as.list(substitute(f)), list(x), 1)))
xts.ts %@% rollapply( width = rolling.per-1, FUN= function(x) x%@%var%@%sqrt * sqrt(252) ) %@% lag( k=1) %@% na.omit %@% plot(main = "Dummy Example")

私の場合はそれほど重要ではありませんが、言及すると、次のステートメントはチャールズの解決策では失敗します:

 xts.ts %@% names <- 'ts name' 
4

4 に答える 4

12

機能パッケージを試してください:

library(functional)
squared <- function(x)x*x
Compose(sum, squared)(m)
## [1] 44100
squared(sum(m))
## [1] 44100

編集:

ここでの引数に関する別の応答のコメントの質問については、引数を使用して構成する例です。 Curryこれも機能パッケージからのものです。

addn <- function(n, x) x + n
Compose(Curry(addn, 1), squared)(10)
## [1] 121
squared(addn(1, 10))
## [1] 121

編集2:

デバッグに関する質問についてdebugは、関数がカリー化されている場合に機能します。まだカリー化されていない場合は、次のようにラップしCurryます。

# this works since addn is curried
debug(addn)
Compose(Curry(addn, 1), squared)(10)

# to debug squared put it in a Curry -- so this works:
debug(squared)
Compose(Curry(addn, 1), Curry(squared))(10)
于 2012-07-04T15:07:00.520 に答える
9

ある種、しかし、それは慣用的ではなく、おそらく壊れやすい/良い考えではないと思います。(これは、上記の@RichieCottonのコメントによって暗示されていると思います。)

http://cran.r-project.org/doc/manuals/R-lang.htmlから:

10.3.4 特殊演算子

R では、ユーザー定義の中置演算子を使用できます。これらは、'%' 文字で区切られた文字列の形式です。文字列には、「%」以外の任意の印刷可能な文字を含めることができます。ここでは、文字列のエスケープ シーケンスは適用されません。

次の演算子が事前定義されていることに注意してください

 %% %*% %/% %in% %o% %x%
"%@%" <- function(x,f) {
    f(x)
}

sqr <- function(x) x^2
x <- 1:4

x %@% mean  ## 2.5
x %@% mean %@% sqr  ## 6.25
x %@% (mean %@% sqr)  ## fails

上記mで定義したように、おそらくあなたは何を考えていましたか?

 m %@% colMeans %@% sum  ## 21

ノート:

  • あなたの例は少しおかしいです。なぜなら、mean(x)常にスカラー(つまり、長さ1のベクトル)を返すため、常にsum(mean(x))同じになるからですmean(x)
  • 中置演算子は で囲む%必要があるため、単一のシンボルのようにコンパクトにすることはできません (そして%%既に使用されています)。
  • この種の連鎖は非連想的で、心配です-上記の例は機能しているように見えるので、Rは(明らかに)左から右に評価されますが、それが保証されているかどうかはわかりません...

編集:質問は、追加の引数をどのように組み込むことができるかを尋ねます。x %@% fun1(arg1) %@% fun2(arg2)推奨される構文 ( ) は、深刻な魔法がなければ機能しないと思います。これは、現時点で入手できる最も近いものです-元の関数の変更されたバージョンを作成するラッパー関数を作成します。

F <- function(f,...) {
    function(x) {
        f(x,...)
    }
}

テスト:

pow <- function(x,b=2) { x^b }
sqr <- function(x) x^2
x <- 1:4

x %@% F(mean,na.rm=TRUE)  ## 2.5
x %@% F(mean,na.rm=TRUE) %@% F(pow,3)  ## 16.25

(ここでは関数として使用していることに注意してください。これは、ショートカットFを上書きするため、状況によっては危険な場合があります)F==FALSE

于 2012-07-04T14:27:10.693 に答える
5

magrittrパッケージを使用します。ある関数の結果を引数として次の関数に渡す「パイプ」演算子があります。

m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2)

m %>% mean %>% sum

Ceci n'est pas un pipe!

于 2015-09-01T10:13:20.173 に答える
4

ベンの答えと同様ですが、引数を許可します。

`%@%` <- function(x, f) eval.parent(as.call(append(as.list(substitute(f)), list(x), 1)))

x %@% mean %@% sqr # => 6.25
c(1, 2, NA, 3, 4) %@% mean(na.rm=T) %@% sqr # => 6.25
m %@% colMeans() %@% sum() # => 21
于 2012-07-05T05:18:02.457 に答える