記述統計の基礎:データ要約術

統計

はじめに

記述統計は、大量のデータをシンプルな数値や図で要約し、全体像を素早く把握するための基礎技術です。ビジネスレポート、品質管理、アンケート分析などあらゆる場面で役立ちます。本記事では、(1)基本指標(2)可視化(3)実務での落とし穴(4)コピペで使えるPythonコードの順に解説します。

記述統計の基本と役割

  • 全体像の要約:平均・中央値・最頻値、分散・標準偏差、四分位数などで中心とばらつきを把握。
  • 分布の把握:ヒストグラム、箱ひげ図、散布図で偏り・外れ値・形状(裾の重さ)を可視化。
  • EDAの第一歩:前処理・仮説立案・次の分析手法(相関/回帰/検定など)の当たりをつける。

用語と記号(最小限)

  • 母集団/標本:全体(母)から一部(標本)を観測。標本の指標は不偏推定を意識(例:標本分散)。
  • 平均(μ or \bar{x}):中心的傾向。外れ値に敏感。
  • 中央値(median):外れ値に頑健。歪んだ分布で有効。
  • 分散・標準偏差:ばらつき。標本では ddof=1(不偏)を使うのが通例。
  • IQR(四分位範囲):Q3−Q1。中央50%の広がり。外れ値検出の基準に利用。
  • CV(変動係数):標準偏差÷平均。単位が違う指標間で相対的ばらつきを比較。
  • 歪度・尖度:分布の非対称性と裾の重さの指標。

基本指標とその計算例(サンプル統計量)

例:テスト得点データの要約。標準偏差は不偏推定ddof=1)で計算します。

import numpy as np

scores = np.array([72, 85, 90, 65, 88], dtype=float)

mean = np.mean(scores)
median = np.median(scores)
std_unbiased = np.std(scores, ddof=1)   # ★標本標準偏差はddof=1
q1, q3 = np.percentile(scores, [25, 75])
iqr = q3 - q1
cv = std_unbiased / mean

print(f"平均: {mean:.1f}")
print(f"中央値: {median:.1f}")
print(f"標本標準偏差: {std_unbiased:.1f}")
print(f"Q1: {q1:.1f}, Q3: {q3:.1f}, IQR: {iqr:.1f}")
print(f"変動係数(CV): {cv:.3f}")

# 出力例
# 平均: 80.0
# 中央値: 85.0
# 標本標準偏差: 10.6
# Q1: 72.0, Q3: 88.0, IQR: 16.0
# 変動係数(CV): 0.132
  • 平均:代表値だが外れ値に弱い。給与やアクセス数など歪な分布では中央値も併記。
  • 中央値:頑健な中心。極端値があっても安定。
  • 標本標準偏差:np.std(x, ddof=1)。分母にn-1を使う不偏推定。
  • IQR:外れ値の有無、箱ひげ図の箱の高さに対応。
  • CV:単位が違うKPI間の「相対的ばらつき」を比較するのに便利。

分布の可視化と外れ値検出

ヒストグラムや箱ひげ図で形状と外れ値をチェック。Tukeyの方法では、外れ値閾値を [Q1 − 1.5×IQR, Q3 + 1.5×IQR] と定義します。

import matplotlib.pyplot as plt
import numpy as np

x = scores  # 任意の1次元数値データ

# 外れ値検出(Tukey)
q1, q3 = np.percentile(x, [25, 75])
iqr = q3 - q1
lo, hi = q1 - 1.5*iqr, q3 + 1.5*iqr
outliers = x[(x < lo) | (x > hi)]

print(f"外れ値閾値: [{lo:.1f}, {hi:.1f}]")
print(f"外れ値: {outliers.tolist()}")

# ヒストグラム
plt.figure()
plt.hist(x, bins="auto", edgecolor="black")
plt.title("Histogram")

# 箱ひげ図
plt.figure()
plt.boxplot(x, vert=True, showmeans=True)
plt.title("Boxplot")
plt.show()

カテゴリデータの要約(頻度・割合・クロス集計)

import pandas as pd

df = pd.DataFrame({
    "性別": ["男","女","女","男","男","女"],
    "購入": ["はい","いいえ","はい","はい","いいえ","はい"]
})

# 単純集計
freq = df["購入"].value_counts()            # 件数
prop = df["購入"].value_counts(normalize=True)  # 比率

# クロス集計(行割合)
ct = pd.crosstab(df["性別"], df["購入"], margins=True)
row_pct = pd.crosstab(df["性別"], df["購入"], normalize="index").round(3)

print(freq)
print(prop)
print(ct)
print(row_pct)
  • 最頻値(mode):カテゴリの代表値。多峰性がある場合は複数存在。
  • 割合の併記:件数と%をセットで示すと伝わりやすい。
  • 積み上げ棒グラフ:カテゴリ間の構成比を一目で比較。

正規性・相関に関する注意

  • 正規性検定:分布が正規かを形式的に確認するにはシャピロ・ウィルク検定Kolmogorov–SmirnovAnderson–Darlingなどを用います。
  • 相関の種別:連続×連続ならピアソン(線形)、順位相関ならスピアマン。スピアマンは正規性検定ではありません(よくある誤解)。
  • 多変量の可視化:散布図行列や相関行列ヒートマップで全体を俯瞰。

実務でハマりやすい落とし穴(チェックリスト)

  • ddofの未指定:標本標準偏差は ddof=1。デフォルト(0)は母集団向け。
  • 単位とスケール:異なる単位の指標を平均化しない。比率は%で揃える。
  • 欠損値処理:平均値埋めは分布を歪める。欠損の仕組み(MCAR/MAR/MNAR)を確認。
  • 集計粒度:日・週・月の混在で誤解が生じやすい。粒度と集計関数を明示。
  • 外れ値の乱暴な除去:原因特定が先。入力ミス・仕様変更・実イベントかを区別。
  • シンプソンの逆説:全体集計と群別集計で傾向が逆転することに注意。

コピペで使える要約レシピ(1ファイル完結)

# 記述統計ダッシュ(最小セット)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# ===== データ例 =====
np.random.seed(42)
n = 200
df = pd.DataFrame({
    "score": np.clip(np.random.normal(70, 12, n), 0, 100),
    "gender": np.random.choice(["男","女"], size=n, p=[0.5,0.5]),
    "passed": np.where(np.random.rand(n) < 0.6, "はい", "いいえ")
})

# ===== 基本要約 =====
s = df["score"].dropna().values
mean = np.mean(s)
median = np.median(s)
std1 = np.std(s, ddof=1)
q1, q3 = np.percentile(s, [25, 75])
iqr = q3 - q1
cv = std1 / mean
skew = pd.Series(s).skew()       # 歪度
kurt = pd.Series(s).kurtosis()   # 尖度(フィッシャー型)

print(f"平均: {mean:.2f}, 中央値: {median:.2f}, 標本SD: {std1:.2f}")
print(f"Q1: {q1:.2f}, Q3: {q3:.2f}, IQR: {iqr:.2f}, CV: {cv:.3f}")
print(f"歪度: {skew:.3f}, 尖度: {kurt:.3f}")

# ===== 外れ値(Tukey) =====
lo, hi = q1 - 1.5*iqr, q3 + 1.5*iqr
out_idx = (s < lo) | (s > hi)
print(f"外れ値件数: {out_idx.sum()} / {len(s)}")

# ===== 可視化 =====
plt.figure()
plt.hist(s, bins="auto", edgecolor="black"); plt.title("Histogram of score")

plt.figure()
plt.boxplot(s, vert=True, showmeans=True); plt.title("Boxplot of score")

# カテゴリ × カテゴリ
ct = pd.crosstab(df["gender"], df["passed"], margins=True)
print("\n--- クロス集計 ---\n", ct)

plt.show()

より深い分析へ進むときの道しるべ

  • 分布に応じたモデル選択:カウント→ポアソン/NB、比率→二項、連続の歪度が大→ロバスト統計や変換(対数・Box–Cox)。
  • 相関から因果へ:相関は因果を意味しない。層別・実験・IV・傾向スコアなどへ展開。
  • 可観測以外のばらつき:階層構造(部門/店舗/担当者)を意識して分解。

まとめ

記述統計は「まず全体像を正しく掴む」ための最短ルートです。代表値+散布+分布形状をセットで示し、必要に応じて頑健な指標(中央値・IQR・CV)も併記しましょう。粒度・単位・欠損・外れ値の扱いを明示できれば、レポートの信頼性が大きく向上します。