Rによる記述統計:平均、中央値、標準偏差の完全ガイド
これまでの22回のレッスンでは、Rの「ツール」――ベクトル、データフレーム、ggplot2――について学びました。これからは、Rの真の「価値」である統計分析に移ります。このレッスンでは、最も基本的な概念である「記述統計」から始めます。Rを使って、平均、中央値、標準偏差といった主要な指標を計算し、データをいくつかの数値に「要約」していきます。
このレッスンを修了すると、たった3行のRコードを使って、どのようなデータセットに対しても「統計レポート」を作成できるようになります。
1. 学習内容
- 記述統計:3つの主要なカテゴリー――集中傾向の尺度、分散の尺度、分布の形状
- 中央傾向の指標:平均値/中央値/最頻値
- 分散:標準偏差/分散/四分位範囲/範囲/中央値
- 分位数:分位数/中央値/Q1/Q3
- summary() / skimr: 簡易統計
- dplyr + group_by:グループ化のガイド
- 実践演習:1,000行の学生成績表
2. ある生徒の成績表にまつわる物語
(1) 課題:1,000人の生徒をどのように「要約」すればよいでしょうか?
学期の終わりに、ボブ教授は1,000人の学生の成績表を作成する必要があります。各学生は5つの科目を履修しており、各科目について、以下の計算を行う必要があります:
- 平均、中央値(集中傾向の指標)
- 標準偏差、四分位数(分散の指標)
- 最高得点、最低得点(極端な値)
- 歪度、尖度(分布の形状)
手計算?Excelの関数?それだと2時間かかるけど、Rを使えば summary()——
(2) Rを用いた解決策
# 1. One line summary shows 5 key metrics
summary(scores$math)
# Min. 1st Qu. Median Mean 3rd Qu. Max.
# 45.0 72.0 82.0 81.5 92.0 99.0
# 2. One line skimr View the full report
library(skimr)
skim(scores$math)
# ── Variable type: numeric ──
# min max mean sd p25 p50 p75 hist
# 45 99 81.5 12 72 82 92 ▇▇▇▇▇
# 3. One line dplyr Grouped Statistics
scores |> group_by(class) |> summarise(
Average Score = mean(math),
Median = median(math),
Standard Deviation = sd(math),
Highest = max(math),
Lowest = min(math),
Number of people = n()
)
たった3行のコードで、成績表が完成。
3. 記述統計の3つの主要な分類
(1) 3つの主要カテゴリーの概要
graph TB
A[Descriptive Statistics] --> B[Central Tendency<br/>Central Tendency]
A --> C[Degree of dispersion<br/>Dispersion]
A --> D[Distribution Patterns<br/>Shape]
B --> E[mean Median mode]
C --> F[sd var range IQR]
D --> G[Skewness skewness<br/>Fengdu kurtosis]
style A fill:#fff3cd
style B fill:#d4edda
style C fill:#cce5ff
style D fill:#f8d7da
(2) クイックリファレンス表
| カテゴリ | 機能 | 意味 |
|---|---|---|
| 中央傾向 | mean() |
算術平均 |
| 中央傾向 | median() |
中央値(50パーセンタイル) |
| 集中型 | mode() |
モード(DescTools パッケージが必要) |
| 離散 | sd() |
標準偏差 |
| 離散 | var() |
分散 |
| 離散 | range() |
極値(最小値/最大値) |
| 離散型 | IQR() |
四分位範囲 (Q3-Q1) |
| 離散型 | mad() |
中央値絶対偏差 |
| 分布 | skewness() |
歪度(e1071 が必要) |
| 分布 | kurtosis() |
尖度(e1071 が必要) |
4. 中央傾向
(1) mean() 平均
x <- c(85, 90, 78, 92, 88)
mean(x) # [1] 86.6
mean(x, na.rm = TRUE) # Skip NA
mean(x, trim = 0.1) # Truncated Mean (Remove the top and bottom 10%)
(2) median() 中央値
median(c(85, 90, 78, 92, 88)) # [1] 88
median(c(85, 90, 78, 92, 10000)) # [1] 90 ← Not affected by 10000 Impact
(3) モード(特殊機能)
# R does not have a built-in mode(), use the DescTools package
install.packages("DescTools")
library(DescTools)
Mode(c(1, 2, 2, 3, 3, 3, 4)) # [1] 3
5. 分散の度合い
(1) sd() / var() 標準偏差 / 分散
x <- c(85, 90, 78, 92, 88)
sd(x) # [1] 5.32 ← Standard Deviation
var(x) # [1] 28.3 <- Variance (sd^2)
標準偏差 = データ点が平均値から離れている「平均的な距離」。この値が大きいほど、データのばらつきは大きくなります。
(2) range()の極値
x <- c(85, 90, 78, 92, 88)
range(x) # [1] 78 92 ← Minimum and Maximum
diff(range(x)) # [1] 14 ← Range
(3) IQR() 四分位範囲
x <- c(85, 90, 78, 92, 88, 70, 95, 65, 88, 92)
IQR(x) # [1] 11.5 ← Q3 - Q1
quantile(x, c(0.25, 0.5, 0.75))
# 25% 50% 75%
# 78.25 88.0 89.75
Q1 - 1.5*IQR ~ Q3 + 1.5*IQR)。
(4) mad()における中央値の絶対偏差
mad(c(85, 90, 78, 92, 10000)) # Extremely Robust Discrete Measures
# [1] 4.45
6. 分位数
(1) quantile() 分位数
x <- 1:100
# Default 0%, 25%, 50%, 75%, 100%
quantile(x)
# 0% 25% 50% 75% 100%
# 1.0 25.75 50.5 75.25 100.0
# Custom Percentiles
quantile(x, probs = c(0.1, 0.5, 0.9))
# 10% 50% 90%
# 10.9 50.5 90.1
(2) 一般的なパーセンタイル
| パーセンタイル | 関数 | 意味 |
|---|---|---|
| Q0 (0%) | min(x) |
最小値 |
| 第1四半期 (25%) | quantile(x, 0.25) |
下位四分位 |
| 第2四半期 (50%) | median(x) |
中央値 |
| 第3四半期 (75%) | quantile(x, 0.75) |
上位四分位 |
| 第4四半期 (100%) | max(x) |
最大値 |
7. summary()—1行で表示される要約統計量
x <- c(85, 90, 78, 92, 88, NA, 75, 95)
summary(x)
# Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
# 75.00 81.50 88.00 87.62 90.50 95.00 1
6つの主要指標+NA件数—すべて1行にまとめて!
# Data Frame
df <- data.frame(
age = c(20, 25, 30, 35),
score = c(85, 90, 78, 92)
)
summary(df)
# age score
# Min. :20.00 Min. :78.00
# 1st Qu.:23.75 1st Qu.:83.25
# Median :27.50 Median :87.50
# Mean :27.50 Mean :86.25
# 3rd Qu.:31.25 3rd Qu.:90.50
# Max. :35.00 Max. :92.00
8. skimr:高度で包括的な統計機能
install.packages("skimr")
library(skimr)
x <- c(85, 90, 78, 92, 88, 70, 95, 65, 88, 92)
skim(x)
# ── Data Summary ────────────────────────
# Values x
# Number of rows 10
# Number of distinct 8
# Mean 84.2
# Standard deviation 10.13
# Min 65
# Max 95
# Median 87.5
# ... (More Metrics)
skim() は 20以上の指標を提供しており、summary() よりも10倍詳細です。
9. グループ別の記述統計
(1) dplyr + group_by + summarise
library(dplyr)
# Simulation 3 Cls × 5 Student Grades
scores <- tibble(
class = rep(c("1Cls", "2Cls", "3Cls"), each = 5),
student = paste0("S", 1:15),
math = c(85, 78, 92, 65, 88, # 1 Cls
90, 75, 80, 95, 70, # 2 Cls
82, 88, 76, 91, 85), # 3 Cls
english = c(78, 85, 88, 70, 92,
82, 80, 90, 88, 75,
88, 90, 78, 92, 85)
)
# Class Statistics
class_stats <- scores |>
group_by(class) |>
summarise(
Number of people = n(),
Mathematical Average = mean(math),
Median in Mathematics = median(math),
Mathematical Standard Deviation = sd(math),
Top in Math = max(math),
Lowest in Math = min(math),
MathematicsIQR = IQR(math),
Average English Score = mean(english)
)
print(class_stats)
# A tibble: 3 × 9
# class Number of people Mathematical Average Median in Mathematics Mathematical Standard Deviation Top in Math Lowest in Math MathematicsIQR Average English Score
# <chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 1Cls 5 81.6 85 11.4 92 65 17 82.6
# 2 2Cls 5 82 80 10.5 95 70 20 83
# 3 3Cls 5 84.4 85 6.02 91 76 12 86.6
(2) 複数指標の内訳 (across)
# Calculate statistics for all numeric columns at once
scores |>
group_by(class) |>
summarise(across(where(is.numeric), list(
mean = mean,
sd = sd,
median = median
)))
(3) tapply の旧構文(参考用)
# Use tapply
tapply(scores$math, scores$class, mean)
# 1Cls 2Cls 3Cls
# 81.6 82.0 84.4
10. 実践演習:1,000人の生徒を対象とした総合成績表の作成
以下は、このレッスンで取り上げたすべての記述統計を結びつける完全なワークフローの例です。
▶ サンプル:1,000人の学生と5つのコースに関する包括的なレポート
# ============================================
# 1000 Student 5 Course Comprehensive Grade Report
# Features: Complete Descriptive Statistics + Grouping + Ranking
# ============================================
library(dplyr)
library(tidyr)
library(ggplot2)
# 1. Prepare data
set.seed(42)
n <- 1000
students <- tibble(
id = 1:n,
class = sample(c("1Cls", "2Cls", "3Cls", "4Cls", "5Cls"), n, replace = TRUE),
gender = sample(c("M", "F"), n, replace = TRUE),
math = round(rnorm(n, 80, 12)),
english = round(rnorm(n, 78, 15)),
physics = round(rnorm(n, 75, 14)),
chemistry = round(rnorm(n, 76, 13)),
biology = round(rnorm(n, 80, 10))
)
cat("=== Data Volume:", nrow(students), "rows ===\n")
# 2. University-wide Comprehensive Statistics
cat("\n=== University-wide Comprehensive Statistics ===\n")
overall <- students |>
summarise(across(c(math, english, physics, chemistry, biology),
list(mean = mean, sd = sd, median = median),
.names = "{.col}_{.fn}"))
print(overall)
# 3. Statistics by Class
cat("\n=== Math Statistics for Each Class ===\n")
class_stats <- students |>
group_by(class) |>
summarise(
Number of people = n(),
Average = round(mean(math), 2),
Median = median(math),
Standard Deviation = round(sd(math), 2),
Highest = max(math),
Lowest = min(math),
Q1 = quantile(math, 0.25),
Q3 = quantile(math, 0.75),
IQR = round(IQR(math), 2)
) |>
arrange(desc(Average))
print(class_stats)
# 4. Grouped by gender
cat("\n=== All genders 5 Class Average ===\n")
gender_stats <- students |>
group_by(gender) |>
summarise(across(c(math, english, physics, chemistry, biology),
mean, .names = "{.col}_Average"))
print(gender_stats)
# 5. Each Student's Total Score and Rank
cat("\n=== Top 10 Students (Total Score) ===\n")
students <- students |>
mutate(total = math + english + physics + chemistry + biology,
average = round(total / 5, 2))
top10 <- students |>
arrange(desc(total)) |>
head(10) |>
select(id, class, gender, total, average)
print(top10)
# 6. Identify the outliers (IQR method)
cat("\n=== Students with Outliers in Math Scores ====\n")
math_q1 <- quantile(students$math, 0.25)
math_q3 <- quantile(students$math, 0.75)
math_iqr <- IQR(students$math)
lower <- math_q1 - 1.5 * math_iqr
upper <- math_q3 + 1.5 * math_iqr
outliers <- students |>
filter(math < lower | math > upper) |>
select(id, class, math)
cat("Normal Range:", lower, "-", upper, "\n")
cat("Number of outliers:", nrow(outliers), "\n")
print(head(outliers, 5))
# 7. Use summary() to view by subject
cat("\n=== Mathematics summary ===\n")
print(summary(students$math))
# 8. Use skimr for advanced report
library(skimr)
cat("\n=== skimr Report ===\n")
print(skim(students |> select(math, english, physics)))
# 9. Write a report
write_csv(students, "student_report.csv")
write_csv(class_stats, "class_stats.csv")
cat("\n=== The report has been generated ===\n")
期待される出力(抜粋):
=== Math Statistics for Each Class ===
# A tibble: 5 × 9
class Number of people Average Median Standard Deviation Highest Lowest Q1 Q3 IQR
<chr> <int> <dbl> <dbl> <dbl> <int> <int> <dbl> <dbl> <dbl>
1 5Cls 201 81.0 81 12.0 114 44 72 90 18
2 1Cls 195 80.6 81 11.6 115 47 73 88 15
3 3Cls 203 79.8 80 11.8 110 49 71 88 17
4 2Cls 201 79.4 80 12.1 109 44 70 88 18
5 4Cls 200 79.1 79 12.4 116 45 70 89 19
❓ よくある質問
summary() と skim()、どちらを選べばいいですか?summary は簡潔(6つの指標)で、skim は詳細(20以上の指標)です。na.rm = TRUE を追加してください。そうしないと、NA を含むベクトルの結果はすべて NA になってしまいます。e1071::skewness() と e1071::kurtosis() を使用します。歪度が 0 より大きい場合、分布は右偏りであり、0 より小さい場合は左偏りです。尖度が 0 より大きい場合、その分布は正規分布よりも尖っており、0 より小さい場合は、より平坦です。📖 まとめ
- 記述統計は、中央傾向(平均/中央値/最頻値)、分散の尺度(標準偏差/分散/四分位範囲)、および分布の形状(歪度/尖度)の3つの主要なカテゴリーに分類される。
- 平均値は外れ値の影響を受けやすいのに対し、中央値はより頑健である—分布が偏っている場合は、まず中央値を用いる
- sd は、元のデータと同じ単位での標準偏差であり、var は sd² である
- IQR = Q3 - Q1:外れ値の検出に一般的に用いられる、分散の頑健な指標
summary(x)1行あたり6つの指標、最も一般的に使用される;skim(x)20以上の指標、詳細なレポート- グループの説明:
dplyr::group_by() |> summarise(across(where(is.numeric), mean)) - NA処理:すべての関数に
na.rm = TRUEを追加する - 外れ値:< Q1 - 1.5×IQR または > Q3 + 1.5×IQR(ロバスト法)
📝 練習問題
-
基本問題:ベクトル
x <- c(85, 90, 78, 92, 88, NA, 75, 95)を構築し、mean()、median()、sd()、およびvar()を用いて値を計算し(na.rm = TRUEに注意)、8つの結果を確認する。 -
基本演習:
summary()とquantile(x, c(0, 0.25, 0.5, 0.75, 1))を使用して、同じベクトルの統計指標を計算し、2つの結果を比較してください。 -
基本問題:データフレーム(3クラス × 5人の生徒 × 2科目:数学と英語)を作成し、
dplyr::group_by + summarise + acrossを使用して、すべてのクラスの全科目について、1回の操作で平均値と標準偏差を計算してください。 -
応用演習:5つのコースに在籍する1,000人の学生の成績をシミュレートし、
skimr::skim()を使用して完全なレポートを生成し、(IQR法を用いて)数学の得点における外れ値を特定し、外れ値の得点を持つ学生の割合を算出してください。 -
課題:ワークフローを完了させる—5つのコースに在籍する1,000人の学生の成績をシミュレートする:① 全体的な概要 ② クラスごとの概要 ③ 性別ごとの概要 ④ 順位付け ⑤ 外れ値の検出 ⑥ CSVレポートとMarkdown形式のテキストレポートを生成する(表の表示には
knitr::kable()を使用)。プロセスのスクリーンショットを保存する。



