層別で計算する
Text Update: 11/10, 2018 (JST)

Packages and Datasets

本ページではR version 3.4.4 (2018-03-15)の標準パッケージ以外に以下の追加パッケージを用いています。
 

Package Version Description
tidyverse 1.2.1 Easily Install and Load the ‘Tidyverse’

 
また、本ページでは以下のデータセットを用いています。
 

Dataset Package Version Description
iris datasets 3.4.4 Edgar Anderson’s Iris Data

 

標準パッケージを用いる方法

標準パッケージで層別統計量を計算するにはapply関数群のtapply関数を用います。統計用の計算結果が一つの値(長さ1になる)の場合と複数の値(長さ2以上)になる場合では、層別の統計量算出後に型変換する場合は処理方法が異なりますので、その点についても記載しておきます。
 

平均値を計算する

R に標準で組み込まれているirisデータセットを用いてSepal.Length(萼片の長さ)の平均値をSpecies(品種)毎に計算してみます。

with(iris, tapply(Sepal.Length, Species, mean, na.rm = TRUE))
##     setosa versicolor  virginica 
##      5.006      5.936      6.588

 
tapply関数の返り値はアレイ型ですが、mean関数の返り値が長さ1のベクトル型ですので、その後に型の変換処理を行いたい場合は以下のように比較的簡単にできます。
 

マトリクス型に変換する

as.matrix(with(iris,
               tapply(Sepal.Length, Species, mean, na.rm = TRUE)))
##             [,1]
## setosa     5.006
## versicolor 5.936
## virginica  6.588

 

データフレーム型に変換する

as.data.frame(
  as.matrix(with(iris,
                 tapply(Sepal.Length, Species, mean, na.rm = TRUE))))
## # A tibble: 3 x 1
##      V1
## * <dbl>
## 1  5.01
## 2  5.94
## 3  6.59

 

五数要約を計算する

同様にfivenum関数で五数要約(最小値、第1四分位数、中央値、第3四分位数、最大値)を計算してみましょう。

with(iris, tapply(Sepal.Length, Species, fivenum, na.rm = TRUE))
## $setosa
## [1] 4.3 4.8 5.0 5.2 5.8
## 
## $versicolor
## [1] 4.9 5.6 5.9 6.3 7.0
## 
## $virginica
## [1] 4.9 6.2 6.5 6.9 7.9

 
fivenum関数のように返り値の長さが1より大きいベクトルの場合は、平均値を計算した時とは異なり型を変換するにはひと手間必要です。
 

マトリクス型に変換する

tapply関数の返り値は複数の値を持つアレイ型ですのでdo.call関数を用いて行方向に結合する必要があります。

do.call(rbind, 
        with(iris, tapply(Sepal.Length, Species, fivenum, na.rm = TRUE)))
##            [,1] [,2] [,3] [,4] [,5]
## setosa      4.3  4.8  5.0  5.2  5.8
## versicolor  4.9  5.6  5.9  6.3  7.0
## virginica   4.9  6.2  6.5  6.9  7.9

 

データフレーム型に変換する

データフレーム型に変換する場合は、一度、マトリクス形式に変換してから再変換する必要があります。

as.data.frame(do.call(rbind, 
                      with(iris, tapply(Sepal.Length, Species,
                                        fivenum, na.rm = TRUE))))
## # A tibble: 3 x 5
##      V1    V2    V3    V4    V5
## * <dbl> <dbl> <dbl> <dbl> <dbl>
## 1   4.3   4.8   5     5.2   5.8
## 2   4.9   5.6   5.9   6.3   7  
## 3   4.9   6.2   6.5   6.9   7.9

 

追加パッケージを用いる方法

dplyrパッケージを用いることでパイプ( %>% )処理による分かりやすい処理が可能になります。
 

平均値を計算する

標準パッケージを用いる方法 と同様の処理をdplyrパッケージを用いて処理すると以下のように全ての数値変数に対して一度に処理できるようになります。

require(tidyverse)

iris %>% 
  dplyr::group_by(Species) %>% 
  dplyr::summarise_if(is.numeric, mean, na.rm = TRUE)
## # A tibble: 3 x 5
##   Species    Sepal.Length Sepal.Width Petal.Length Petal.Width
##   <fct>             <dbl>       <dbl>        <dbl>       <dbl>
## 1 setosa             5.01        3.43         1.46       0.246
## 2 versicolor         5.94        2.77         4.26       1.33 
## 3 virginica          6.59        2.97         5.55       2.03

 

五数要約を計算する

dplyr::summarise関数では「返り値の長さが1」である関数のみしか使えませんので、返り値の長さが5つある五数要約(quantile関数)を平均値の計算の時のように計算することはできません。なお、mean関数のように全ての数値変数に対して一度に処理することはできませんので注意してください。
 

方法1

quantile関数の返り値をリスト型にしてからdplyr::summarise関数に渡しcbind関数で列方向に展開します。

require(tidyverse)

iris %>% 
  dplyr::group_by(Species) %>% 
  dplyr::summarize(qt = list(quantile(Sepal.Length, na.rm = TRUE))) %>%
  cbind(do.call(rbind, .$qt)) %>%
  dplyr::select(-qt)
## # A tibble: 3 x 6
##   Species     `0%` `25%` `50%` `75%` `100%`
##   <fct>      <dbl> <dbl> <dbl> <dbl>  <dbl>
## 1 setosa       4.3  4.8    5     5.2    5.8
## 2 versicolor   4.9  5.6    5.9   6.3    7  
## 3 virginica    4.9  6.22   6.5   6.9    7.9

 

方法2

dplyr::doを用いてリスト型の返り値をcbind関数で展開します。よりdplyr的な処理です。

require(tidyverse)

iris %>%
  dplyr::group_by(Species) %>% 
  dplyr::do(qt = quantile(.$Sepal.Length, na.rm = TRUE)) %>%
  cbind(do.call(rbind, .$qt)) %>%
  dplyr::select(-qt)
## # A tibble: 3 x 6
##   Species     `0%` `25%` `50%` `75%` `100%`
## * <fct>      <dbl> <dbl> <dbl> <dbl>  <dbl>
## 1 setosa       4.3  4.8    5     5.2    5.8
## 2 versicolor   4.9  5.6    5.9   6.3    7  
## 3 virginica    4.9  6.22   6.5   6.9    7.9