---
title: "データの要約1 (記述統計量)"
---
データを入手したら,分析を行う前にまずデータの概観を把握することが重要。データセットにどのような変数が含まれているかを確認し,それぞれの変数の記述統計量 (平均値,分位点,分散など)を求め,必要であれば変数間の相関関係を調べてみる。これにより,欠損値や異常値が含まれていないかということや,どのような仮説を検証することができそうかなど,分析の方向性を決めることができる。
ここでは,Rに含まれているirisデータを例に,データの要約統計量を求める方法を説明する。
Rのパッケージ,`tidyverse`と`stargazer`を利用するのであらかじめインストールしておく。
まず,インストールしたパッケージを読み込む。
```{r}
library(tidyverse)
library(stargazer)
```
## データの概観
練習としてRに組み込まれているサンプル・データ`iris`を概観してみよう。まず,サンプル・データ`iris`を読み込む。
```{r}
data(iris)
```
`iris`というデータフレームが読み込まれる。irisデータには,植物のアヤメ150個体について,種類 (3分類),萼片 (がくへん)の長さと幅,花弁 (かべん)の長さと幅の5つの変数が記録されている。このデータは,機械学習による分類などの練習用データとしてよく用いられているデータである。
|変数名|説明|
|-|-|
|`Sepal.Length`|萼片の長さ|
|`Sepal.Width`|萼片の幅|
|`Petal.Length`|花弁の長さ|
|`Petal.Width`|花弁の幅|
|`Species`|アヤメの種類|
データにどのような変数が含まれているかは,小規模データであればEnvironmentタブからスプレッド・シートを表示させれば把握できる。大規模なデータは,スプレッド・シートを表示させるだけでも時間がかかることがあるので,`glimpse()`関数を使うのが良い。
```{r}
glimpse(iris)
```
irisデータは,行数 (観測数)が150,列数 (変数の数)が5であることがわかる。また,それぞれの変数のはじめのいくつかの観測値を見ることができるので,データのイメージがつかめる。`<dbl>`や`<fct>`はそれぞれの変数の型で,`<dbl>`は実数型 (double, numericと同じ),`<fct>`はファクター型であることを表している。
:::{.callout-tip}
### 変数の型について
変数の型には,実数型 (numeric/double),ファクター型 (factor)のほかに,文字列型 (character)`<chr>`や論理型 (logical)`<lgl>`などがある。Rでは通常,あまり厳密に変数の型を気にする必要はない。ただし,変数が数値型だと思って演算を行おうとすると,文字列型になっていてエラーになるということはよくあるので。数値型か文字型かくらいは意識しよう。
:::
## 要約統計表の作成
### summary()関数
データ全体のイメージがつかめたら,次は記録されている変数の要約統計表を作成してみよう。`summary()`関数を用いれば,データフレームに含まれるすべての変数の要約統計量を表示させることができる。
```{r}
summary(iris)
```
数値型の変数については,最小値(Min.),第一四分位(1st Qu.),中央値(Median),平均値(Mean),第三四分位(3rd Qu.),最大値(Max)が表示される (`summary()`関数では,分散や標準偏差は表示されない)。また,ファクター型の変数については,度数分布表が表示される。
### 特定の変数を取り出す
特定の変数についてのみ,要約統計量を求めたい場合は,`select()`関数を使えば良い。
```{r}
summary(select(iris, Sepal.Length, Sepal.Width))
```
`select()`関数は,データフレームから指定した変数だけを取り出したデータフレームを作成する。第1引数には変数を取り出すデータフレームを,第2引数以降は取り出したい変数名をカンマで区切って指定する。たとえば,`select(dataframe, a, b)`は`dataframe$a`と`dataframe$b`の2つの変数が含まれるデータフレームとなる。逆にデータフレームから指定した変数を除外したいときには,第2引数以降で変数名に`-`をつけて指定する。たとえば,`select(dataframe, -a)`はdataframeから変数`a`を除いたデータフレームとなる。また,変数は列番号で指定することも可能である。たとえば,`select(dataframe, 2:4)`は`dataframe`から2列目から4列目までの変数を取り出したデータフレームとなる。
この処理は,パイプを使って以下のように書くこともできる。
```{r}
iris |>
select(Sepal.Length, Sepal.Width) |>
summary()
```
パイプというのは,関数を`|>`でつなげることにより,前の関数の結果を次の関数の第1引数として渡す。複数の処理を一度に行うことができ,無駄な中間オブジェクトを作成する必要がないため便利。この例だと,`iris`というデータフレームが2行目の`select()`関数の第1引数として渡されるので,2行目では`iris`から`Sepal.Length`, `Sepal.Width`の二つの変数を取り出すことになる。さらに,その結果が3行目の`summary()`関数に渡されるため,`Sepal.Length`, `Sepal.Width`の要約統計量が表示される。
### summarize()関数{#summarize}
より柔軟にカスタマイズして要約統計表を作成したい場合には,`summarize()`関数を用いる。`summarize()`関数は,結果をデータフレームで返し,たとえば以下のように使う。
```{r}
summarize(iris,
萼片長平均 = mean(Sepal.Length),
萼片長標準偏差 = sd(Sepal.Length),
花弁長平均 = mean(Petal.Length),
花弁長標準偏差 = sd(Petal.Length)
)
```
`summarize()`関数の第1引数には要約統計量を求めたいデータフレーム名を指定する。第2引数以降は,`要約統計量の名前 = 関数(変数名)`という形式で指定する。名前は出力される要約統計表データフレームの列名なので自由に指定すれば良い。関数の部分には,例として下の表のような関数が利用できる。変数名`x`には,第1引数として与えたデータフレーム内の変数名を指定すればよい (データフレーム名は必要ない)。
|関数|説明|
|-|-|
|`n()`|観測数|
|`mean(x)`|`x`の平均値|
|`var(x)`|`x`の分散|
|`sd(x)`|`x`の標準偏差|
|`max(x)`|`x`の最大値|
|`median(x)`|`x`の中央値|
|`min(x)`|`x`の最小値|
|`quantile(x, XX)`|`x`のXX×100パーセンタイル, e.g. `x`の25パーセンタイルであれば`quantile(x,0.25)`|
`summarize()`関数は,後で述べるようにグループ別の集計のときに役に立つ。
## stargazerパッケージを使う
レポートや論文に貼り付けるための要約統計表を作成するには,`stargazer`パッケージが便利。
```{r}
stargazer(
iris,
type = "text",
title = "要約統計表",
digits = 2,
summary.stat = c(
"mean",
"sd",
"min",
"p25",
"median",
"p75",
"max"
)
)
```
`stargazer()`関数は,要約統計表や回帰分析の結果などを,良い感じの見た目で出力してくれる。
`stargazer()`関数で要約統計表を作成する場合は,第1引数としてデータフレーム (この例では`iris`)を指定する。そのほかの引数は必要に応じて指定すれば良い。よく使うオプションだけ説明する。まず,`type`は表の出力形式で,"text"(プレーンテキスト),"html","latex"のいずれかを指定する。`title`は表のタイトル,`digits`は表の数値の小数点以下の桁数を指定する。`summary.stats`は表に含める要約統計量をベクトル形式で指定する。
|要約統計量|指定方法|
|-|-|
|平均|`mean`|
|標準偏差|`sd`|
|最小値|`min`|
|最大値|`max`|
|XXパーセンタイル(分位点)|`p90` (90パーセンタイル)|
要約統計表を作成することができるパッケージは`stargazer`のほかにも`gt`パッケージなどさまざまなものがある。用途や好みに応じて使い分けよう。`stargazer()`関数は,とくにLatex形式で出力する際に便利だ。
## 相関表
次に,変数間の相関を求めよう。相関表を求めるには`cor()`関数を使う。引数にはデータフレーム名を指定する。ただし,`iris`にファクター型の`Species`という変数が含まれているため,そのままではエラーになる。そこで,`iris`に含まれる5つの変数のうち数値型の4つを取り出して相関表を作成したいので,ファクター型の変数`Species`だけを除外した`iris2`を作成し,`cor()`関数の引数に,`iris2`を指定して相関行列を求める。
```{r}
iris2 <- select(iris, - Species)
cor(iris2)
```
同じことをパイプを使って書くと次のようになる。
```{r}
iris |>
select(- Species) |>
cor()
```
ここでは,パイプの理解のためにこのようにしたが,これくらいの作業であればパイプを使わずに以下のように書いても良い。
```{r eval=FALSE}
cor(select(iris, - Species))
```
## グループ分け
データをグループに分けて,グループごとに要約統計を求めたいということは,実際によくある。irisデータでは,アヤメはsetosa,versicolor,virginicaの3種類に分類されている。そこで,アヤメの種類ごとに萼片と花弁の長さ,幅の平均を求めてみよう。そのための方法はいくつか考えられる。
### group_by()を使う{#group_by}
たぶんこれが標準的な方法。
`group_by()`関数を使うと,(Rの内部で)グループに分類されたデータフレームを作成することができる。第1引数には分類したいデータフレーム名,第2引数以降は分類を行うためのファクター型変数を指定する。複数のファクター型変数を指定して,階層的な分類を行うことも可能。グループに分類されたデータフレームに`summarize()`関数を適用すると,グループごとの要約統計量が計算される。
```{r}
iris_grouped <- group_by(iris, Species)
summarize(
iris_grouped,
萼片長平均 = mean(Sepal.Length),
萼片長標準偏差 = sd(Sepal.Length),
花弁長平均 = mean(Petal.Length),
花弁長標準偏差 = sd(Petal.Length)
)
```
同じことを,パイプを使うと以下のように書ける。
```{r}
iris |>
group_by(Species) |>
summarize(
萼片長平均 = mean(Sepal.Length),
萼片長標準偏差 = sd(Sepal.Length),
花弁長平均 = mean(Petal.Length),
花弁長標準偏差 = sd(Petal.Length)
)
```
パイプのメリットの1つは,不要な中間オブジェクト (この場合は,`iris_grouped`)を作成せずに済むという点。もちろん,中間オブジェクトを作成せずに同じ結果を得るのは,以下のコードでも可能。
```{r evel=FALSE}
summarize(
group_by(iris, Species),
萼片長平均 = mean(Sepal.Length),
萼片長標準偏差 = sd(Sepal.Length),
花弁長平均 = mean(Petal.Length),
花弁長標準偏差 = sd(Petal.Length)
)
```
パイプを使わないと,関数の引数にまた関数を使うということになるので,コードが見づらくなる。パイプは,作業の流れがわかりやすいという点でも有用。
### xtabs()関数を使う
`xtabs()`関数を使うと,多次元分割表を柔軟に作成することができる。第1引数には形式を,第2引数にはデータフレーム名を指定する。形式は,`~ x1 + x2 + ...`か`y ~ x1 + x2 + ...`の形で指定する。たとえば,`~ x1 + x2`を指定すれば,`x1`, `x2`で表を分割し,各セルの観測数が得られる。`y ~ x1 + x2`を指定すれば,`x1`, `x2`で表を分割し,各セルごとの`y`の合計が得られる。
`iris`では分類に用いることができる変数は`Species`の1つしかないが,それでも`xtabs()`を適用できる。以下のコードで`Species`ごとのデータ数の表を作成できる。
```{r}
xtabs(~ Species, iris)
```
次に,以下のコードで`Species`ごとの萼片長の合計値の表を作成できる。
```{r}
xtabs(Sepal.Length ~ Species, iris)
```
平均値は合計値をデータ数で割ったものなので,`Species`ごとの萼片長の平均値を以下のように求められる。
```{r}
xtabs(Sepal.Length ~ Species, iris) / xtabs(~ Species, iris)
```
### フィルター
まず,データフレームからアヤメの種類ごとにデータを取り出して分割する方法。単純でわかりやすいが,分類が多くなると大変なので,要約統計量を求めるためだけであれば効率的な方法ではない。ただし,データフレームにフィルターをかけて特定の条件を満たす観測 (行)を取り出すことはよくあるので,やり方を覚えておこう。
データフレームから条件を満たす行を取り出すには,`filter()`関数を用いる。`filter()`の第1引数にはデータフレーム名,第2引数には抽出条件を指定する。
抽出条件は,`TRUE`か`FALSE`の論理値を返す式で指定する。`TRUE`のデータだけが抽出される。具体的な書き方は次の通り。
| 条件 | 意味 |
|------|------|
| `x == 10` | `x`が10と等しい |
| `x != 10` | `x`が10と等しくない `!(x==10)`とも書ける |
| `x > 10` | `x`が10より大きい |
| `x < 10` | `x`が10より小さい |
| `x >= 10` | `x`が10以上 |
| `x <= 10` | `x`が10以下 |
| `x %in% A` | `x`がベクトル`A`に含まれる |
このうち,とくにAとBが等しいという条件を `(A == B)`と書くことに注意。`=`が1つだと,条件ではなく代入を表すことになるため,エラーとなる。
```{r}
iris_setosa <- filter(iris, Species == "setosa")
iris_versicolor <- filter(iris, Species == "versicolor")
iris_virginica <- filter(iris, Species == "virginica")
```
これでアヤメの種類ごとのデータフレームができるので,それぞれのデータフレームで要約統計表を作成する。
```{r}
stargazer(
iris_setosa, type = "text", title = "setosa", digits = 2,
summary.stat = c("mean", "sd", "min", "p25", "median", "p75", "max")
)
stargazer(
iris_versicolor, type = "text", title = "versicolor", digits = 2,
summary.stat = c("mean", "sd", "min", "p25", "median", "p75", "max")
)
stargazer(
iris_virginica, type = "text", title = "virginica", digits = 2,
summary.stat = c("mean", "sd", "min", "p25", "median", "p75", "max")
)
```