web-dev-qa-db-ja.com

関数のリストを値のリストに適用する

この質問を参照して、関数のリストをのリストに適用する最も簡単な方法を見つけようとしていました値。基本的に、ネストされたlapply。たとえば、ここではsdmeanを組み込みデータセット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))

しかし、私が見逃している位置と名前の一致でこれを行う賢い方法があるのではないかと期待していました。

27
BrodieG

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)"
26
Julien Navarre

名前付きパラメーターを2つの異なるsapply呼び出しと区別する他の方法がないため、基本的に何らかの匿名関数が必要になります。明示的な無名関数とCurryメソッドについてはすでに説明しました。 magrittrを使用することもできます

 library(magrittr)
 sapply(funs, . %>%  sapply(trees, .))
 # or .. funs %>% sapply(. %>%  sapply(trees, .))

しかし、要点は、分割を行うためにそこに何かが必要なことです。 「問題」は、sapplylapplyにディスパッチすることです。これは 内部関数 であり、変化する値を関数呼び出しの開始として配置するように決定されているようです。パラメータを並べ替える何かが必要です。パラメータ名のセットが同じであるため、曖昧さの解消を処理するヘルパー関数がないと、それを分解することはできません。

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
14
MrFlick

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が提供されます。

5
Rentrop

@ 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

この一連の操作は、余分な冗長性を犠牲にして、意図を通知するというまともな仕事をします。

1
egnha