5

Hadleyの有望な関数型プログラミングR ライブラリである purrr は初めてです。グループ化および分割されたデータフレームを取得し、変数に対して t 検定を実行しようとしています。サンプル データセットを使用した例は、次のようになります。

mtcars %>% 
  dplyr::select(cyl, mpg) %>% 
  group_by(as.character(cyl)) %>% 
  split(.$cyl) %>% 
  map(~ t.test(.$`4`$mpg, .$`6`$mpg))

これにより、次のエラーが発生します。

Error in var(x) : 'x' is NULL
In addition: Warning messages:
1: In is.na(x) : is.na() applied to non-(list or vector) of type 'NULL'
2: In mean.default(x) : argument is not numeric or logical: returning NA

仕組みを誤解しているだけmapですか?または、これについて考えるより良い方法はありますか?

4

3 に答える 3

10

期待される結果を完全には理解していませんが、これが答えの出発点になるかもしれません。 map()frompurrr.x式の引数で使用されます。

これは、あなたがただでやろうとしていると私が思うことを達成する1つの方法ですpurrr.

mtcars %>%
  split(as.character(.$cyl)) %>%
  map(~t.test(.x$mpg)) 

でも、purrr::by_slice()相性抜群dplyr::group_by()

library(purrr)
library(dplyr)

mtcars %>% 
  dplyr::select(cyl, mpg) %>% 
  group_by(as.character(cyl)) %>%
  by_slice(~ t.test(.x$mpg))

purrrまたは、 を使用して完全にスキップすることもできますdplyr:::summarise()

library(purrr)
library(dplyr)

mtcars %>% 
  dplyr::select(cyl, mpg) %>% 
  group_by(as.character(cyl)) %>%
  summarise(t_test = data_frame(t.test(.$mpg)))

ネストされたものdata.frameがわかりにくい場合は、結果の簡単な要約をbroom取得するのに役立ちます。data.frame

purrr+ broom+tidyr

library(broom)
library(tidyr)
mtcars %>%
  group_by(as.character(cyl)) %>%
  by_slice(~tidy(t.test(.x$mpg))) %>%
  unnest()

dplyr+broom

library(broom)

mtcars %>% 
  dplyr::select(cyl, mpg) %>% 
  group_by(as.character(cyl)) %>%
  do(tidy(t.test(.$mpg)))

コメントへの応答を含めるように編集されました

パイプを使用すると、すぐに夢中になります。purrrウォルトは彼の答えで素晴らしい仕事をしたと思いますが、私は-tyの答えを提供したことを確認したかった. pipeRの使用が過度に混乱しないことを願っています。

library(purrr)
library(dplyr)
library(broom)
library(tidyr)
library(pipeR)

mtcars %>>%
  (split(.,.$cyl)) %>>%
  (split_cyl~
    names(split_cyl) %>>%
     (
       cross_d(
         list(against=.,tested=.),
         .filter = `==`
       )
     ) %>>%
     by_row(
       ~tidy(t.test(split_cyl[[.x$tested]]$mpg,split_cyl[[.x$against]]$mpg))
     )
  ) %>>%
  unnest()
于 2016-02-22T22:08:04.157 に答える
6

特に、複数の入力を必要とするパイプを扱う場合 (Haskell の Arrows はここにはありません)、最初にタイプ/シグネチャーで推論し、次にロジックを関数にカプセル化し (単体テストできます)、簡潔なチェーンを書く方が簡単だと思います。 .

この場合、考えられるすべてのベクトルのペアを比較したいので、ベクトルのペア (つまり 2 つのリスト) を取り、それらの 2-way t.test を返す関数を作成するという目標を設定します。

これが完了したら、接着剤が必要です。したがって、計画は次のとおりです。

  1. ベクトルのリストを取り、2 因子 t 検定を実行する関数を記述します。
  2. mtcars からベクトルをフェッチする関数/パイプを作成します (簡単)。
  3. 上記をペアのリストにマッピングします。

コードを記述する前に、この計画を立てることが重要です。R は厳密に型指定されていないという事実によって、物事は何とか難読化されていますが、このようにして、最初に「型」について、次に実装について推論します。

ステップ1

t.test はドットを取るのでpurrr:lift、リストを取るために使用します。リストの要素の名前を一致させたくないので、 を使用します.unnamed = TRUEt.testまた、アリティが 2の関数を使用していることをさらに明確にします(ただし、コードが機能するためにこの追加の手順は必要ありません)。

t.test2 <- function(x, y) t.test(x, y)
liftedTT <- lift(t.test2, .unnamed = TRUE)

ステップ2

ステップ 1 で取得した関数を、単純なペアを取る関数チェーンにラップします (ここではインデックスを使用します。cyl ファクター レベルを使用するのは簡単なはずですが、理解する時間がありません)。

doTT <- function(pair) {
  mtcars %>%
    split(as.character(.$cyl)) %>%
    map(~ select(., mpg)) %>% 
    extract(pair) %>% 
    liftedTT %>% 
    broom::tidy
}

ステップ 3

すべてのレゴピースの準備ができたので、構成は簡単です。

1:length(unique(mtcars$cyl)) %>% 
  combn(2) %>% 
  as.data.frame %>% 
  as.list %>% 
  map(~ doTT(.))

$V1
  estimate estimate1 estimate2 statistic      p.value parameter conf.low conf.high
1 6.920779  26.66364  19.74286  4.719059 0.0004048495  12.95598 3.751376  10.09018

$V2
  estimate estimate1 estimate2 statistic      p.value parameter conf.low conf.high
1 11.56364  26.66364      15.1  7.596664 1.641348e-06  14.96675 8.318518  14.80876

$V3
  estimate estimate1 estimate2 statistic      p.value parameter conf.low conf.high
1 4.642857  19.74286      15.1  5.291135 4.540355e-05  18.50248 2.802925  6.482789

ここには、主に因子レベルを使用して出力に保持する (そして 2 番目の関数でグローバルを使用しない) クリーンアップする必要がある部分がかなりありますが、必要なものの核心はここにあると思います。私の経験では、迷子にならない秘訣は、内側から外側に向かって作業することです。

于 2016-02-23T08:28:12.360 に答える