この質問を参照して、関数のリストをのリストに適用する最も簡単な方法を見つけようとしていました値。基本的に、ネストされたlapply
。たとえば、ここではsd
とmean
を組み込みデータセットtrees
に適用します。
funs <- list(sd=sd, mean=mean)
sapply(funs, function(x) sapply(trees, x))
取得するため:
sd mean
Girth 3.138139 13.24839
Height 6.371813 76.00000
Volume 16.437846 30.17097
しかし、私は内側のfunction
を避けて、次のようなものを持ちたいと思っていました。
sapply(funs, sapply, X=trees)
X
が2番目ではなく最初のsapply
と一致するため、これは機能しません。 functional::Curry
でそれを行うことができます:
sapply(funs, Curry(sapply, X=trees))
しかし、私が見逃している位置と名前の一致でこれを行う賢い方法があるのではないかと期待していました。
mapply
はEllipsis...
を使用してベクトル(アトミックまたはリスト)を渡し、sapply, lapply, etc ...
のように名前付き引数(X)を渡さないため、sapplyの代わりにmapplyを使用する場合は、パラメーターにX = trees
という名前を付ける必要はありません。
funs <- list(sd = sd, mean = mean)
x <- sapply(funs, function(x) sapply(trees, x))
y <- sapply(funs, mapply, trees)
> y
sd mean
Girth 3.138139 13.24839
Height 6.371813 76.00000
Volume 16.437846 30.17097
> identical(x, y)
[1] TRUE
あなたはあなたが探していたものを手に入れるのに1通の手紙でした! :)
関数のデータフレームを作成できないため、funs
のリストを使用したことに注意してください。エラーが発生しました。
> R.version.string
[1] "R version 3.1.3 (2015-03-09)"
名前付きパラメーターを2つの異なるsapply
呼び出しと区別する他の方法がないため、基本的に何らかの匿名関数が必要になります。明示的な無名関数とCurry
メソッドについてはすでに説明しました。 magrittr
を使用することもできます
library(magrittr)
sapply(funs, . %>% sapply(trees, .))
# or .. funs %>% sapply(. %>% sapply(trees, .))
しかし、要点は、分割を行うためにそこに何かが必要なことです。 「問題」は、sapply
がlapply
にディスパッチすることです。これは 内部関数 であり、変化する値を関数呼び出しの開始として配置するように決定されているようです。パラメータを並べ替える何かが必要です。パラメータ名のセットが同じであるため、曖昧さの解消を処理するヘルパー関数がないと、それを分解することはできません。
mapply
関数を使用すると、リストを「MoreArgs」に渡すことができます。これにより、名前付きパラメーターの競合を回避できます。これは、ベクトル化する必要のある項目と修正される項目を分割することを目的としています。したがって、あなたはすることができます
mapply(sapply, funs, MoreArgs=list(X=trees))
# sd mean
# Girth 3.138139 13.24839
# Height 6.371813 76.00000
# Volume 16.437846 30.17097
purrr
を使用する別のアプローチは次のとおりです。
require(purrr)
funs <- list(sd=sd, mean=mean)
trees %>% map_df(~invoke_map(funs, ,.), .id="id")
重要:位置で一致するinvoke_map
の空の2番目の引数に注意してください。 ?purrr::invoke_map
の例を参照してください。
それはあなたに与えます:
Source: local data frame [3 x 3]
id sd mean
<chr> <dbl> <dbl>
1 Girth 3.138139 13.24839
2 Height 6.371813 76.00000
3 Volume 16.437846 30.17097
このアプローチでは、行名の代わりに、元の列を含む列id
が提供されます。
@ Floo0によって提示されたソリューションほど啓発的でもエレガントでもありませんが、 tidyr および dplyr を使用したさらに別のテイクがあります。
library(dplyr)
library(tidyr)
fns <- funs(sd = sd, mean = mean)
trees %>%
gather(property, value, everything()) %>%
group_by(property) %>%
summarise_all(fns)
# A tibble: 3 x 3
# property sd mean
# <chr> <dbl> <dbl>
# 1 Girth 3.138139 13.24839
# 2 Height 6.371813 76.00000
# 3 Volume 16.437846 30.17097
この一連の操作は、余分な冗長性を犠牲にして、意図を通知するというまともな仕事をします。