-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
summary_statistics.qmd
704 lines (542 loc) · 33.5 KB
/
summary_statistics.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
---
title: "データの特徴を捉える"
code-fold: false
---
```{r}
#| include: false
source("data-raw/zoo.R")
```
[データ分析の目的](intro.qmd#データ分析って何)の一つに「データを要約すること」があることを示しました。
それでは実際に、データの要約に取り組んでみましょう。
例として[**動物データ**](dataset.qmd#とくしま動物園で飼育される動物の体の大きさと体重)の体長を表示します。
```{r}
#| code-fold: false
df_zoo$body_length_cm
```
このデータの特徴として言えることは何でしょうか?
**動物データ**に含まれるわずか`r nrow(df_zoo)`件の数値でも、こうした数値の羅列からデータの特徴を説明することは困難です。
データ分析で扱うデータの件数は数千、数万となる場合もあり、一つ一つデータを見ていくことも
現実的ではありません。
そこでデータを要約するために**記述統計量(要約統計量)**の計算や**データの可視化**が行われます。
記述統計量はデータ全体を表現する代わりとしてデータを要約したものとして機能します。
記述統計量は大きく分けるとデータの位置を示す値を提供する代表値とデータのばらつきを説明する値の2つに考えられます。
記述統計量を組み合わせてデータの分布を考えることで、データのすべてを説明しなくても十分にデータの内容を伝えることが可能になります。
データの可視化はデータを値そのものとして表現するのではなく、グラフやチャートを用いて説明を行うものです。
記述統計量では失われてしまう情報も、グラフ上に投影することで効果的に示せる可能性があります。
この章では複数のRパッケージを利用します。
次のコマンドを実行し、利用できる状態にしておきましょう。
```{r}
#| message: false
library(dplyr)
library(ggplot2)
library(ragg)
library(palmerpenguins)
library(patchwork)
```
```{r}
# 作図のための関数
source("scripts/color_palette.R")
```
## データの位置を示す代表値: 平均値、中央値、最頻値
数値の傾向を捉えるには、その値が分布する位置を考えることが重要になります。
そこで手始めに複数の数値の性質や特徴をよく表す代表値を調べてみましょう。
**代表値によるデータの要約は、データに含まれる数値が位置するところについて大まかに傾向を把握する**ために用いられます。
代表値という名前の通り、数値によるデータの表現方法となります。
代表値によるデータの要約方法にはさまざまなものがあります。代表的なものは**平均値**の計算です。
平均値の他に中央値、最頻値が代表値としてしばしば使われます。
それぞれの特徴をみていきましょう。
### 平均値
まずは代表値の代表として平均値を紹介します。
平均値にも複数の種類が存在しますが、ここではより一般的な**算術平均**を平均値の例として扱います[^ch3-1]。
算術平均とは、2個以上のデータ(データの数を$N$とします)があるとき、そのすべての数値を足し合わせて$N$で割った値のことです。
[^ch3-1]: 平均として使われるものには、算術平均の他に幾何平均や加重平均などがあります。
```{r}
#| code-fold: false
# 1,3,5,7,10の平均を求めましょう
x <- c(1, 10, 5, 3, 7)
# まずは対象の数値を足し合わせます
sum(x)
# 次に数値の数(5)によって足し合わせた数値を割り算します
sum(x) / length(x)
# mean()関数を用いて平均値を計算することもできます。
mean(x)
```
平均値はその言葉の通り、データの真ん中あたりを示す代表値です。
しかし、「あたり」という点に注意してください。
**平均値は必ずしもデータの真ん中を示す値ではありません**。
平均値を扱うときは<ruby>外れ値<rt>はずれち</rt></ruby>の影響を受けやすい性質があるを理解しておきましょう。
外れ値とはデータの中の極端に大きい・小さい値のことです。
次に示す、**動物データ**の一部の動物の体重について平均値がどのくらいになるか考えてみましょう。
```{r}
#| df-print: kable
df_zoo_subset <-
df_zoo |>
arrange(weight_kg) |>
filter(name %in% c("ミーアキャット", "リスザル", "モルモット", "コツメカワウソ", "ホッキョクグマ")) |>
select(name, weight_kg)
df_zoo_subset
```
```{r}
#| code-fold: false
# 動物データの体重の平均はどのくらい?
df_zoo_subset$weight_kg
```
平均値は `r mean(df_zoo_subset$weight_kg)` です。
この平均よりも小さな動物は`r sum(df_zoo_subset$weight_kg <= mean(df_zoo_subset$weight_kg))`種もいたにも関わらずです。
この値をデータの真ん中と見なしても問題ないでしょうか。
データを見ると一番体重の大きなホッキョクグマが`r df_zoo_subset$weight_kg[5]`kgで、二番目に大きな動物とも`r df_zoo_subset$weight_kg[5] -df_zoo_subset$weight_kg[4]`kgも差があります。
**平均値が大きく釣り上げられてしまった原因は、ホッキョクグマの体重が他の動物に比べて極端に大きな値、外れ値であったため**です。
ホッキョクグマを除いたときの平均値は`r mean(df_zoo_subset$weight_kg[-5])`となります。
このように平均値はデータの中の外れ値によって大きく左右される特徴があり、注意してください(@fig-average_outlier)。
![平均値は外れ値の影響を受けやすい](images/average_outlier.png){#fig-average_outlier}
### 中央値
中央値は、すべてのデータを大きさの順番に並べたとき、大きい方と小さい方のちょうど真ん中にくる値を指します。
例えば得られている数値が`r x`の場合には数値の数は`r length(x)`個なので、その真ん中の順位は3番目の値になります。
この真ん中の順位にくる数値を中央値とします。
```{r}
# xの数値は大きさの順番になっていないので並び替える
sort(x)
sort(x)[3]
median(x)
```
中央値はデータの値に関わらず、順番だけを気にするために外れ値が含まれている場合でも影響を受けません。
先ほどの**動物データ**の一部に対しても中央値を求めましょう。
```{r}
median(df_zoo_subset$weight_kg)
```
一方、数値の個数が偶数のときには真ん中の数を決めるのに悩んでしまいます。
例えば4つの数値からなるデータの中央値を求めようとすると、真ん中は2.5番目となってしまいます。データの中には2.5番目の値は含まれません。
このときは2番目と3番目の値の平均を中央値として利用します。
```{r}
# データの個数が偶数の場合の中央値の求め方
x <- c(1, 2, 4, 6)
mean(c(x[2], x[3]))
# median()関数で中央値を求められる
median(x)
```
### 四分位点
中央値の考え方を拡張したものとして四分位点があります。
これはデータを小さい方から並び替えたとき、**データ全体を均等な数からなる4つのグループに分ける3つの点(値)**のことを指します。
各グループ区切りの値となる点をそれぞれ第1四分位点(25パーセンタイル)、第2四分位点(50パーセンタイル)、第3四分位点(75パーセンタイル)と呼びます。
第2四分位点はデータの値を並び替えたときの真ん中となる値、つまり中央値です(@fig-quantile_explain)。
また、パーセンタイルというのは値を小さい方から並び替えたときの最後の値の位置を100としたときの四分位点の位置を示す値です。
つまり最小値は0パーセンタイル、最大値は100パーセンタイルとなります。
```{r}
#| include: false
#| eval: false
library(ggbeeswarm)
ggplot(penguins, aes(x = "", y = flipper_length_mm)) +
geom_beeswarm(size = 0.8) +
geom_hline(yintercept = unname(quantile(penguins$flipper_length_mm, na.rm = TRUE)[c(2:4)])) +
coord_flip()
ggsave("images/quantile_explain_bee.png", width = 9, height = 7)
```
![四分位点のイメージ](images/quantile_explain.png){#fig-quantile_explain}
データの半分が含まれる第1四分位点から第3四分位点までの範囲のことを四分位範囲と呼びます。
四分位範囲は第3四分位点から第1四分位点の値を引くことで求められます。
[**ペンギンデータ**](dataset.qmd#南極大陸に生育するペンギンの大きさについての観測データ)の翼の長さ (`flipper_length_mm`)について四分位点を確認しましょう。
まずはおさらいとして中央値を求めます。
```{r}
penguins$flipper_length_mm
median(penguins$flipper_length_mm, na.rm = TRUE)
```
Rでは`quantile()`関数を使い四分位点を求めます。
また、`summary()`関数で出力される値からも四分位点を確認できます。
```{r}
quantile(penguins$flipper_length_mm, na.rm = TRUE)
```
`quantile()`関数の出力の25%、50%、75%の表示がそれぞれ第1四分位点、第2四分位点、第3四分位点です。
50%が中央値と同じ値になっている点を確認できました。
<!-- 文部科学省の中学校学習指導要領での解説との差を説明するべきか
ref) https://www.mext.go.jp/component/a_menu/education/micro_detail/__icsFiles/afieldfile/2019/03/18/1387018_004.pdf
pp. 120-121
-->
続いて`summary()`関数の出力結果を見てみます。
こちらは`1st Qu.`、`Median`、`3rd Qu.`が該当する項目です。
`Qu.`は四分位点を意味する英語のQuantileに由来する表記です。
```{r}
summary(penguins$flipper_length_mm)
```
平均値や中央値ではデータの位置を示す値として一つの値しかわからなかったのに対して、四分位点を用いることで、より多くの情報を得ることができるようになりました。
この四分位点を利用したデータの視覚的な表現方法として[箱ヒゲ図](#箱ヒゲ図)があります。
箱ヒゲ図についてはこの章で後ほど登場します。
### 最頻値
最頻値はデータの中で最も頻繁に出現する値のことを言います。
クラスのテストの点数で、96点の人が3人と最も多かったとき、最頻値は96です。ただし92点の人が同様に3人いたときには96、92が最頻値となります。
```{r}
x <-
c(73, 58, 96, 61, 87, 54, 92, 92, 63, 80,
92, 59, 77, 96, 62, 64, 64, 59, 76, 96)
# 各点数の人数を求めます
table(x)
# 最頻値を求めます
names(which(table(x) == max(table(x))))
```
上記の例は変数が離散変数の場合の最頻値の求め方でした。
連続変数の場合も手順は変わりませんが、数値を適当な間隔でまとめた階級を設定することで判断することがあります。
これについては後ほど、[度数分布表](#度数分布表)を紹介するときに説明します。
データの位置を示す代表値3種類を説明しました。
それではデータの特徴を捉えるのに、平均値、中央値、最頻値のどれを使うのが適切でしょうか。
よく使われるのは平均値ですが、だからと言って平均値がどのような時にも優れているわけではありません。
扱うデータの内容、注目する事柄によって重要な代表値は変わってきます。
[前の章](intro.qmd)で、テストの平均点よりも低かった場合の位置について考えましたが、
そのとき中央値を計算していれば、平均よりも低い点であってもクラスの上位に含まれる可能性があることがわかったはずです。
::: {.callout-tip .tokupon_none}
#### 動物データの代表値を計算しよう
**動物データ**に対して平均値や中央値、最頻値を求めてみよう。
Rにはここで紹介した`mean()`や`median()`以外にも
代表値の算出を行う関数が用意されているよ。
それらについて調べて実行してみよう。
コードの例と解説は[練習問題](exercise.qmd)をみてね。
:::
## データのばらつき
代表値によって、データが分布する大まかな位置を知ることができるようになりました。
一方で外れ値を含む平均値や単純な頻度で求める最頻値のように、分布の形を推定することはできません。
外れ値によって中心がずれているかもしれませんし、最頻値が中心であるという保証はないのです。
そこで今度はデータのもつばらつきを考えてみます。
データは代表値から離れて分布しているのか、代表値の周辺に集中しているのか。
データの大まかな中心としての代表値とそのばらつきを知ることで、データの分布についておおよその傾向が掴めるようになります。
ばらつき具合を数値で表現する方法として代表的なものに、範囲、分散、標準<ruby>偏差<rt>へんさ</rt></ruby>があります。
ここでも**動物データ**を例にして算出方法をみていきましょう。
### 範囲
範囲はもっとも単純で、データの最小値と最大値から求めます。
Rでは最小値、最大値を求める関数としてそれぞれ`min()`関数、`max()`関数が用意されています。
また、最小値・最大値を同時に出力する`range()`関数も利用できます。
これらの関数はいずれも対象の変数を与えることで計算が行われます。
```{r}
#| echo: true
#| code-fold: false
# 動物データの体長について最小値・最大値を求める
# bl ... body_lengthの略称として使います
min_bl <-
min(df_zoo$body_length_cm, na.rm = TRUE)
min_bl
max_bl <-
max(df_zoo$body_length_cm, na.rm = TRUE)
max_bl
range(df_zoo$body_length_cm, na.rm = TRUE)
```
最小値と最大値がわかれば、次のその差を求めます。この値がデータのとりうる範囲となります。
**範囲により区間という意味でのデータのばらつきの程度がわかる**ようになります。
```{r}
#| echo: true
#| code-fold: false
# 動物データの体長の範囲
max_bl - min_bl
# このやり方でもOK
diff(range(df_zoo$body_length_cm, na.rm = TRUE))
```
範囲を求める際に使う数値はデータの最小値と最大値でした。
そのためいくつかの問題が発生します。
まず、最小値と最大値だけを見ているので、他の値については無視することになっています。
そのため分布がどうなっているかを具体的に知ることはできません。
加えて、最小値・最大値が外れ値となっているある場合に、範囲が過大評価となってしまう恐れがあります。
そこで次に、データのすべての値がもつ情報を利用する分散と、分散を利用した標準偏差を求めることにします。
### 分散と標準偏差
分散とは、それぞれのデータが**平均値を中心としてどのように散らばっているかを示す**ものです。
分散を求めることで、例えばペンギンの各個体の体長は全般的に均一な値をしているのか、特定の個体が平均値よりも特段高い(あるいは低い)のか、はたまた体長が高い個体と低いがバラバラにいるのかがわかるようになります。
分散は次のように求めます。
1. 変数の値の平均値を出す
2. 変数の各値と平均値の差を求める(<ruby>偏差<rt>へんさ</rt></ruby>と呼びます)
3. 2で求めた差を2乗する
4. すべての値に対して1~3を繰り返し、合計する
5. 4をデータの数で割る
**各値と平均値の差を求めたあと、その合計を計算すると、どんなデータであっても合計は0になります**。
平均値より小さい・大きい値との差を求めてその合計を出しているので、差を相殺することになっています。
これではばらつきを評価できません。
そこで分散を求める際には、その差を2乗し、値を足し合わせます。
ここまでの内容を整理すると次のように表現できます。
$$
分散 = \frac{変数の値と平均値の差の2乗の合計}{変数に含まれるデータ数} = \frac{1}{n}\sum_{i=i}^{n}{(x_i - \bar{x})^2}
$$
上記の式は標本分散を求める式となっています。
Rにおける分散の算出は`var()`関数で行われますが、ここでの分散は不偏分散と呼ばれるもので
データの数から1引いた値で割る点で異なります。
ここまでの内容をおさらいしてみましょう。
```{r}
df <-
penguins |>
filter(species == "Adelie") |>
select(body_mass_g) |>
filter(!is.na(body_mass_g)) |>
slice_head(n = 5)
df <-
df |>
# 各値について偏差 deviation(平均よりもいくら大きいか小さいか)を求める
mutate(deviation = body_mass_g - mean(df$body_mass_g, na.rm = TRUE))
df
```
```{r}
# 偏差の合計は0になる
sum(df$deviation)
```
```{r}
# 偏差の値はプラスとマイナスが混ざる
df$deviation
# 偏差は2乗することでプラスの値のみになる
df$deviation^2
```
```{r}
# 分散
sum(df$deviation^2) / nrow(df)
# var()関数に対象の変数を直接与えて求めても良い
var(df$body_mass_g) * (nrow(df)-1) / nrow(df)
```
```{r}
# Rでは不偏分散
var(df$body_mass_g)
# sum(df$deviation^2) / (nrow(df) - 1)
```
合計が0になる差に対して2乗するのではなく、絶対値をとり、その合計を求めたものを平均偏差と呼びます。
また、**分散について平方根を求めたものが標準偏差**となります。
標準偏差は散らばりの具合を見るための指標となります。
```{r}
# 標準偏差
sqrt(sum(df$deviation^2) / (nrow(df) - 1))
sqrt(var(df$body_mass_g))
```
**標準偏差を求める際に平方根を利用する理由は、分散を求めたときに2乗したものを元に戻すため**です。
具体的には2乗した場合に単位が変わってしまうものを元に戻す必要があるためです。
例えば、長さの単位としてセンチメートルで測ったものならば平方センチメートルとなり、面積の単位になってしまうのを防ぐ効果があります。
![標準偏差を導くまでの過程](images/variance_table.png)
## 分布の姿を捉える
これまで見てきたように、代表値やデータのばらつきを調べることでデータがどのような値を持っているのか、その分布の傾向を掴むことができるようになりました。
一方でまだ分布の姿そのものについては明らかではありません。
次の度数分布表やヒストグラム、箱ヒゲ図を作成することで、分布の姿を捉えることができるようになります。
### 度数分布表
実験や観測により値が得られたら、まずは**度数分布表**を作ることから始めると全体の分布の状況を理解しやすい傾向があります。
ある値がデータに含まれる数を<ruby>度数<rt>どすう</rt></ruby>または<ruby>頻度<rt>ひんど</rt></ruby>といいます。
度数分布表とはその名の通り、度数の分布を表形式にまとめたものを指します。
データに対する度数がどのように分布するかを示すかを表したものが度数分布表です。
度数によってすべてのデータに対して大まかな位置を集計することになるため、データの分布が明らかになります。
動物のデータセットの分類群を例にすると、`df_zoo$taxon`で分類群の値(霊長類や鳥類)を確認し、各値をカウントして度数を求め、それを分類群ごとに集約するという手順をとります。
![分類群ごとに何種類の動物がいるか数えてみよう](images/animal_species_count.png)
```{r}
df_zoo$taxon
```
結果は次のようになります。
```{r}
#| echo: true
#| df-print: kable
# 度数、頻度を英語で frequency といいます
# 度数が大きな分類群の順で表示するように sort = TRUE を指定しています
count(df_zoo, taxon, sort = TRUE, name = "frequency")
```
対象が質的変数の場合は頻度を簡単に求めることができます。
それでは量的変数の度数を求めるにはどうすれば良いでしょうか。
量的変数のうち、離散変数でサイコロの目のようにとりうる値が限られる際には質的変数と同じように考えることもできます。
一方で連続変数では質的変数や離散変数のように同じ値をとることが少ないです。
そのため連続変数や離散変数の度数を求めるときは、**変数がとり得る値をいくつかの区間に分割した階級(class)を考えます**。
このときの区間の幅を階級幅と呼びます。
**ペンギンデータ**に含まれる体重を例として、まずは階級分けのために、まずは変数の最小値と最大値を調べましょう。
Rでは最小値・最大値を調べるのに`range()`関数が利用できることを思い出しましょう。
```{r}
range(penguins$body_mass_g, na.rm = TRUE)
```
```{r}
#| code-fold: true
# range()関数を使わないでmin()関数やmax()関数を使っても良い
min(penguins$body_mass_g, na.rm = TRUE)
max(penguins$body_mass_g, na.rm = TRUE)
```
最小値と最大値がわかったところで、次は階級と階級幅を設定します。
階級はデータ中のすべての値が含まれるようにします。
**ペンギンデータ**の体重の最小値は`r min(penguins$body_mass_g, na.rm = TRUE)`、最大値は`r max(penguins$body_mass_g, na.rm = TRUE)`ですので、
2000から7000までの階級を設定しておきましょう。
この場合、階級幅を区切りが良い1000とすると階級数は5つあることになります。
つづいて、階級ごとに含まれる値の件数を数えます。
```{r}
weight_freq <-
table(cut(penguins$body_mass_g,
breaks = seq(2000,
7000,
by = 1000),
dig.lab = 4))
```
```{r}
#| label: tbl-penguins_weight_freq
#| tbl-cap: ペンギンデータの体重の度数分布表
tibble::tibble(
class = names(weight_freq),
frequency = weight_freq)
```
以上の手順が量的変数に対する度数分布表の求め方です。
**ペンギンデータ**の体重についての度数分布表を作成することができました(@tbl-penguins_weight_freq)。
3000から4000の区間に含まれる値が最も多く、その次に4000から5000の区間の値、そのほかの区間の値はわずかということがわかります。
```{r}
#| eval: false
#| echo: false
hist(df_zoo$weight_kg, breaks = 10)$breaks
hist(df_zoo$weight_kg, breaks = 10)$counts
hist(df_zoo$weight_kg, breaks = 10)$density
hist(df_zoo$weight_kg, breaks = 10)$mids
```
### ヒストグラム
ここまではデータを要約する方法として、数値の要約や集計といった処理を行ってきました。
次に登場する**ヒストグラムはこれまでの例とは異なり、データをグラフで表現する手法**になります。
データをグラフ上に可視化することで、データの分布を確認しつづ、データの特徴を素早く捉えることができるようになります。
こうしたグラフ表現はデータに対する説得力を増すためにも使われます。
それでは早速ヒストグラムの作り方を見ていきましょう。
ヒストグラムの元になるのは先ほど求めた度数分布表です。
**ヒストグラムでは、グラフの横軸に興味のある変数の階級、縦軸に階級内に含まれる度数を示します**。
階級ごとに柱を設け、柱の高さで度数を表現します。
このときに階級の間、つまり柱と柱の間隔を空けないようにします。
ペンギンの体重の度数分布表 (@tbl-penguins_weight_freq) からヒストグラムを作成すると次のようになります(@fig-histogram_for_body_mass_g)。
```{r}
#| label: fig-histogram_for_body_mass_g
#| fig-cap: ペンギンの体重のヒストグラム
#| warning: false
#| dev: ragg_png
p <-
penguins |>
ggplot(aes(body_mass_g)) +
# ヒストグラムでは柱の階級をビン bin と呼びます
geom_histogram(bins = 5) +
ylab("Frequency") +
xlab("Body mass (g)") +
labs(title = "ペンギンの体重のヒストグラム")
p
```
ヒストグラムによって一眼で3000から4000の区間の個体が多いことが読み取れます。
全体のデータの散らばりの程度についても大まかに把握することができます。
次に、これまで見てきた代表値やばらつきを表す数値とヒストグラムの関係を見てみましょう。
データ全体の傾向を示すヒストグラムと、代表的な値の関係を見ることで、データに対する理解が深まります。
```{r}
#| label: fig-histogram_for_body_mass_g_annotate
#| fig-cap: ペンギンの体重のヒストグラムと代表値の関係
#| warning: false
#| dev: ragg_png
#| code-fold: true
p +
geom_vline(xintercept = mean(penguins$body_mass_g, na.rm = TRUE),
color = course_colors[3]) +
geom_vline(xintercept = median(penguins$body_mass_g, na.rm = TRUE),
color = course_colors[2]) +
geom_vline(xintercept = as.numeric(names(which.max(table(penguins$body_mass_g)))),
color = course_colors[1]) +
geom_label(aes(4400, 20),
label = "平均値",
color = course_colors[3],
show.legend = FALSE) +
geom_label(aes(4050, 50),
label = "中央値",
color = course_colors[2],
show.legend = FALSE) +
geom_label(aes(3600, 80),
label = "最頻値",
color = course_colors[1],
show.legend = FALSE)
```
@fig-histogram_for_body_mass_g_annotate を見てわかることは、**代表値の並びが小さい方から最頻値、中央値、平均値の順に並んでいる**ことです。
ヒストグラムの形が左に長く伸びている(この様子を「裾を引いている」と言います)場合、代表値はこの順番に並ぶことが多くなります。
ヒストグラムを作成するときは、階級数がいくら設けられているかに注目します。
例えば同じデータであっても階級数が異なる場合、ヒストグラムの見た目は大きく異なります。
@fig-histogram_bins では、ペンギンの体重について階級数が2のときと30のときのヒストグラムをそれぞれ作成した図を表示しています。
階級数が少ないとデータの分布を把握するのが難しく、逆に階級数が多すぎるときもデータを要約し辛い図になってしまっています。
```{r}
#| label: fig-histogram_bins
#| fig-cap: 階級数によってヒストグラムの見た目は変わる
#| warning: false
#| dev: ragg_png
#| fig-width: 10
p1 <-
penguins |>
ggplot(aes(body_mass_g)) +
geom_histogram(bins = 2, fill = course_colors[1]) +
ylab("Frequency") +
xlab("Body mass (g)") +
labs(title = "ペンギンの体重のヒストグラム。階級数2")
p2 <-
penguins |>
ggplot(aes(body_mass_g)) +
geom_histogram(bins = 30, fill = course_colors[2]) +
ylab("Frequency") +
xlab("Body mass (g)") +
labs(title = "ペンギンの体重のヒストグラム。階級数30")
p1 + p2 + plot_layout(ncol = 2)
```
::: {.callout-warning}
#### 階級幅の異なるヒストグラム
階級の幅が一定でないヒストグラムが存在するよ。
:::
::: {.callout-note .tokupon}
#### 適切な階級数はどうやって決めるの?
階級数を決める方法としては、最小値と最大値、データの範囲やデータ数などが参考になるよ。
でも階級数によってヒストグラムの見た目が変わると
適切かはわからないよね
スタージェスの法則を用いる
:::
<!-- 誤差 -->
### 箱ヒゲ図
[ヒストグラム](#ヒストグラム)の他に、グラフを用いたデータの散らばりを表現する方法として箱ヒゲ図 (@fig-how_to_make_boxplot) があります。
四角い箱の上下に<ruby>髭<rt>ひげ</rt></ruby>が伸びているような図であることから箱ヒゲ図と呼ばれます。
「箱」と「ヒゲ」を使った簡単な図ですが、データの分布だけでなく、データを小さい方から並び替えてグループ分けを行ったときの代表的な3つの位置を表現する[四分位点](#四分位点)も合わせて表示できる図となっています。
箱ヒゲ図の作成手順は次の通りです。
箱ヒゲ図を作成するときは、データの区間と四分位点を求めることが必要になります。
1. まず最小値・最大値から、グラフの縦軸にデータの値が収まるような値を設定します。
2. 第1四分位点と第3四分位点の区間(四分位範囲)を「箱」としてグラフ上に描画します。
3. 中央値は第1四分位点と第3四分位点の間の値となりますので、箱の中に中央値を太い線で描きます。
4. 箱から箱の長さ(四分位範囲)の1.5倍を超す値を外れ値として点で描きます。
5. 箱の上端・下端から、外れ値でないものの最大値と最小値を線で結び「ヒゲ」を作ります。
![箱ヒゲ図の見方と作り方](images/how_to_make_boxplot.png){#fig-how_to_make_boxplot}
**動物データ**の体重について箱ヒゲ図を作成してみます (@fig-zoo_body_length_boxplot)。
箱とヒゲについての意味を理解しておく必要がありますが、ヒストグラムのようにデータの分布を確認することができる図となっています。
また箱ヒゲ図の作成方法は上記のものの他に最大値と最小値をヒゲとして利用するものがあります。
```{r}
#| label: fig-zoo_body_length_boxplot
#| fig-cap: 動物データの体重の箱ヒゲ図
#| warning: false
#| dev: ragg_png
df_zoo |>
ggplot(aes(y = body_length_cm)) +
geom_boxplot() +
labs(title = "動物データの体重の箱ヒゲ図")
```
箱ヒゲ図は複数データのばらつきを比較する際にも役立ちます。
ヒストグラムでは複数のデータを比較することが困難ですが、箱ヒゲ図では箱ヒゲを90度回転させて横に描画することで複数データの比較が容易になります。
@fig-zoo_body_length_boxplot_by_taxon は**動物データ**の分類群ごとに体長の箱ヒゲ図を作成したものです。
箱ヒゲ図ではデータの散らばりが小さい場合には小さくなり、逆に散らばりが大きい時には大きくなります。
このことから、**動物データ**に含まれる動物のうち、食肉類の体長は種の違いが大きく、霊長類は種のばらつきが小さいことが読み取れます。
```{r}
#| label: fig-zoo_body_length_boxplot_by_taxon
#| fig-cap: 動物データの分類群ごとの体長の箱ヒゲ図。箱ヒゲ図を並べて描画することで複数のデータを比較しやすくなります。
#| warning: false
#| dev: ragg_png
# 分類群ごとの箱ヒゲ図を描画
# あらかじめ中央値を計算し、グラフ上では中央値の並びで分類群が表示されるように
# 調整しています。
df_zoo |>
filter(!is.na(body_length_cm)) |>
group_by(taxon) |>
mutate(body_length_median = median(body_length_cm)) |>
ungroup() |>
mutate(taxon = forcats::fct_reorder(taxon, body_length_median)) |>
ggplot(aes(taxon, body_length_cm, color = taxon)) +
geom_boxplot() +
coord_flip() +
scale_colour_tokupon() +
guides(color = "none") +
labs(title = "動物データの分類群ごとの体長の箱ヒゲ図")
```
### さまざまな分布の形
ヒストグラムや箱ヒゲ図で見てきたように、分布の形ががどのような形になっているかを意識することは、データ分析を進めていく際に重要です。
それは分布の形によってデータの特徴が異なるためです。
分布の形はその形に応じて次のような種類があります。
- 中央に一つ峰がある山型の分布
- 特に左右対称に近い形をした釣鐘型
- ロングテール型(右に尻尾が長く伸びているような形)
- 峰が2つ以上ある分布
<!--
べき分布
-->
## まとめと課題
- データを要約する方法の一つに記述統計量がある。記述統計量は大きく次の2種類に分けられる
- データ分析の目的の一つであるデータの要約を行う際に、平均値や中央値などの代表値が利用できる
- データにはばらつきが存在し、そのばらつきを表現するための分散や標準偏差を計算できる
- ヒストグラムを作って、いろいろな分布の形があることを確認しよう
## 参考文献・URL
- @isbn9784130420655
- @isbn9784623084784
- @isbn9784873119267
- @isbn9784489023323
- @isbn9784780609363