LESSON

探索的データ分析(EDA)の進め方

「データ辞書ができた。次はEDAだ。データの声に耳を傾けよう。」

田中VPoEがJupyter Notebookを立ち上げる。

「EDAは芸術ではなく科学だ。体系的な手順に沿って、仮説を検証しながら進める。漫然とグラフを作るのではなく、目的を持って分析するんだ。」

EDAの体系的な手順

EDAの5ステップ:
1. データの全体像把握     → shape, info, describe
2. 目的変数の分布確認     → 不均衡度の把握
3. 単変量分析             → 各特徴量の分布
4. 二変量分析             → 特徴量と目的変数の関係
5. 多変量分析             → 特徴量間の相関・交互作用

Step 1: データの全体像

import pandas as pd
import numpy as np

df = pd.read_csv('WA_Fn-UseC_-Telco-Customer-Churn.csv')

# 基本情報
print(f"データサイズ: {df.shape}")
print(f"\nデータ型:\n{df.dtypes}")
print(f"\n基本統計量:\n{df.describe()}")
print(f"\n欠損値:\n{df.isnull().sum()[df.isnull().sum() > 0]}")

# TotalChargesの型変換
df['TotalCharges'] = pd.to_numeric(df['TotalCharges'], errors='coerce')
print(f"\nTotalCharges変換後の欠損: {df['TotalCharges'].isnull().sum()}")
# 11件の欠損が発生 → tenure=0の新規顧客

Step 2: 目的変数の分布

import matplotlib.pyplot as plt

churn_counts = df['Churn'].value_counts()
churn_rate = df['Churn'].value_counts(normalize=True)

print(f"離反分布:\n{churn_counts}")
print(f"\n離反率:\n{churn_rate}")

# 可視化
fig, ax = plt.subplots(figsize=(6, 4))
churn_counts.plot(kind='bar', ax=ax, color=['#2ecc71', '#e74c3c'])
ax.set_title('顧客離反の分布')
ax.set_ylabel('顧客数')
plt.tight_layout()
plt.savefig('churn_distribution.png')
クラス件数割合
No(非離反)5,17473.5%
Yes(離反)1,86926.5%

Step 3: 単変量分析

数値変数の分布

numeric_cols = ['tenure', 'MonthlyCharges', 'TotalCharges']

fig, axes = plt.subplots(1, 3, figsize=(15, 4))
for i, col in enumerate(numeric_cols):
    df[col].hist(bins=30, ax=axes[i], edgecolor='black')
    axes[i].set_title(f'{col}の分布')
    axes[i].set_xlabel(col)
    axes[i].set_ylabel('頻度')
plt.tight_layout()
plt.savefig('numeric_distributions.png')

# 統計サマリ
for col in numeric_cols:
    print(f"\n{col}:")
    print(f"  平均: {df[col].mean():.2f}")
    print(f"  中央値: {df[col].median():.2f}")
    print(f"  標準偏差: {df[col].std():.2f}")

カテゴリカル変数の分布

categorical_cols = ['gender', 'SeniorCitizen', 'Partner', 'Dependents',
                    'PhoneService', 'InternetService', 'Contract',
                    'PaperlessBilling', 'PaymentMethod']

for col in categorical_cols:
    print(f"\n{col}:")
    print(df[col].value_counts())

Step 4: 二変量分析(特徴量 vs 目的変数)

# カテゴリカル変数と離反率の関係
def plot_churn_rate_by_category(df, col):
    churn_rate = df.groupby(col)['Churn'].apply(
        lambda x: (x == 'Yes').mean()
    ).sort_values(ascending=False)

    print(f"\n{col}別の離反率:")
    print(churn_rate)
    return churn_rate

# 主要な仮説の検証
for col in ['Contract', 'InternetService', 'PaymentMethod', 'tenure']:
    if col == 'tenure':
        # tenureはビニングして分析
        df['tenure_group'] = pd.cut(df['tenure'],
                                      bins=[0, 12, 24, 48, 72],
                                      labels=['0-12', '13-24', '25-48', '49-72'])
        plot_churn_rate_by_category(df, 'tenure_group')
    else:
        plot_churn_rate_by_category(df, col)

主要な発見

二変量分析の主要発見:
- Contract: Month-to-month = 42.7%, One year = 11.3%, Two year = 2.8%
- InternetService: Fiber optic = 41.9%, DSL = 19.0%, No = 7.4%
- PaymentMethod: Electronic check = 45.3%, 他は15-18%
- tenure: 0-12ヶ月 = 47.7%, 49-72ヶ月 = 6.6%

Step 5: 多変量分析

# 数値変数の相関行列
numeric_df = df[['tenure', 'MonthlyCharges', 'TotalCharges']].copy()
numeric_df['Churn_numeric'] = (df['Churn'] == 'Yes').astype(int)

correlation = numeric_df.corr()
print("相関行列:")
print(correlation)

# ヒートマップ
import seaborn as sns
plt.figure(figsize=(8, 6))
sns.heatmap(correlation, annot=True, cmap='coolwarm', center=0)
plt.title('相関行列')
plt.tight_layout()
plt.savefig('correlation_heatmap.png')

EDAから得られるインサイト

仮説検証結果判定
H1: Month-to-month契約は離反率が高い42.7% vs 2.8%(Two year)支持
H4: Fiber optic顧客は離反率が高い41.9% vs 19.0%(DSL)支持
H7: 利用期間が短い顧客は離反しやすい0-12ヶ月: 47.7%支持
H10: Electronic check支払いは離反率が高い45.3% vs 15-18%支持

まとめ

項目ポイント
EDAの手順全体像→目的変数→単変量→二変量→多変量
不均衡度離反26.5%(極端ではないが考慮必要)
最強のシグナル契約形態(Month-to-month)が最も離反率に影響
数値変数tenureが離反と強い負の相関
仮説検証主要仮説はすべて支持された

チェックリスト

  • EDAの5ステップを実行できる
  • 単変量・二変量分析の手法を使える
  • 離反率が高い特徴量の組み合わせを特定できた
  • 仮説の検証結果をまとめられた

次のステップへ

EDAで全体像を把握できた。次は特徴量の可視化をさらに深め、離反者と非離反者の違いをより詳細に分析していこう。

推定読了時間: 30分