聊天視窗

數據洞見:從原始數據到商業決策的機器學習實戰 - 第 4 章

第4章 探索性資料分析 (EDA)

發布於 2026-02-28 07:42

# 第4章 探索性資料分析 (EDA) 在前章,我們已經把資料打磨成乾淨且可重現的狀態,接下來的關鍵步驟是 **洞悉資料本身的結構與特性**。EDA(Exploratory Data Analysis)不僅是統計學中的一套工具,更是機器學習流程中「決策的先聲」——它能告訴我們哪些特徵值得進一步處理、哪些分佈不符合模型假設、哪些關聯值得深入挖掘。下面,我們將以一個實務案例(客戶流失預測)為例,逐步展示如何透過統計圖表、分布檢定與相關矩陣,為後續特徵拆解與縮減奠定理論與實務基礎。 ## 4.1 為什麼要做 EDA 1. **驗證資料完整性**:檢查缺失值、重複記錄、資料型別錯誤。 2. **揭露分佈特徵**:確定數值型特徵是否偏態、是否存在極端值。 3. **檢測關聯結構**:探索特徵間的線性/非線性關係,為特徵選擇提供依據。 4. **設計特徵工程策略**:決定是否需要對數、平方根、標準化或類別編碼。 5. **評估模型假設**:如迴歸假設的正態性、獨立性、同方差性等。 ## 4.2 工具與環境 python import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from scipy import stats - **pandas**:資料處理與描述統計。 - **seaborn**:可視化,特別是分佈圖與熱力圖。 - **scipy.stats**:統計檢定(Shapiro-Wilk、Kolmogorov‑Smirnov 等)。 - **plotnine**(可選):如果想用 ggplot 風格,也可以。 ## 4.3 步驟概覽 | 步驟 | 目的 | 主要工具 | 典型輸出 | |------|------|----------|----------| | 4.3.1 | 資料描述統計 | `df.describe()` | 數值型欄位的 5‑90‑95‑99% 範圍 | | 4.3.2 | 缺失值分析 | `df.isnull().sum()` | 缺失率表格 | | 4.3.3 | 分佈檢定 | `stats.shapiro()`, `stats.kstest()` | p‑value 與檢定統計量 | | 4.3.4 | 可視化 | Seaborn hist/box/violin | 直方圖、箱形圖、貝努利圖 | | 4.3.5 | 相關性 | `df.corr()` | 相關係數矩陣 | | 4.3.6 | 熱力圖 | `sns.heatmap()` | 相關性熱力圖 | | 4.3.7 | 外脫值檢測 | IQR 或 Z‑score | 確認外脫值清單 | | 4.3.8 | 分類特徵分析 | `df['cat'].value_counts()` | 頻數表、比例圖 | | 4.3.9 | 時間序列拆分 | `pd.Grouper()` | 月度/季度匯總 | | ## 4.4 以客戶流失數據為例 以下載 `customer_churn.csv` 為例,檔案包含 12 個欄位,主要有數值型 (`age`, `monthly_charge`) 與類別型 (`gender`, `contract_type`) 特徵。 python df = pd.read_csv('customer_churn.csv') print(df.head()) ### 4.4.1 描述統計 python numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns print(df[numeric_cols].describe(percentiles=[0.05,0.25,0.5,0.75,0.95])) - **觀察**:`monthly_charge` 的 95% 分位數已超過 $100,表明存在高付費客戶群。 - **下一步**:對這類高付費客戶進行聚類或分層分析。 ### 4.4.2 缺失值 python missing = df.isnull().sum() / len(df) * 100 print(missing.sort_values(ascending=False).head(10)) - **發現**:`tenure` 欄位有 2.3% 缺失,需決定補值策略(如均值或多重插補)。 ### 4.4.3 分佈檢定 python # Shapiro-Wilk 只對樣本量 < 5000 適用,若超過可改用 Kolmogorov‑Smirnov w, p = stats.shapiro(df['monthly_charge'].dropna()) print('Shapiro W:', w, 'p‑value:', p) - **結果**:p‑value < 0.01,顯示 `monthly_charge` 並非正態分佈,需做對數轉換。 ### 4.4.4 可視化 python plt.figure(figsize=(15,5)) sns.histplot(df['monthly_charge'], bins=50, kde=True) plt.title('Monthly Charge Distribution') plt.show() - **觀察**:右偏斜,尾部長。 - **對策**:log‑transform 或 box‑cox。 ### 4.4.5 相關性 python corr = df[numeric_cols].corr(method='pearson') print(corr) - **關鍵洞察**:`tenure` 與 `monthly_charge` 的相關係數為 0.42,說明長期客戶往往付費較高。 - **後續**:可將 `tenure` 與 `contract_type` 交叉作為新特徵。 ### 4.4.6 熱力圖 python plt.figure(figsize=(10,8)) sns.heatmap(corr, annot=True, fmt='.2f', cmap='coolwarm') plt.title('Correlation Heatmap') plt.show() - **視覺**:輕度呈現線性關係;高負相關的僅有 `age` 與 `tenure`。 ### 4.4.7 外脫值 python Q1 = df['monthly_charge'].quantile(0.25) Q3 = df['monthly_charge'].quantile(0.75) IQR = Q3 - Q1 lower = Q1 - 1.5 * IQR upper = Q3 + 1.5 * IQR outliers = df[(df['monthly_charge'] < lower) | (df['monthly_charge'] > upper)] print('外脫值數量:', len(outliers)) - **處理**:可選擇將外脫值標記為另一類別或進行 Winsorizing。 ### 4.4.8 類別特徵 python cat_cols = df.select_dtypes(include=['object', 'category']).columns for col in cat_cols: print(f"{col} 類別分布:\n{df[col].value_counts(normalize=True).round(3)}\n") - **發現**:`contract_type` 中 `Month-to-Month` 占比 57%,是高流失率群組。 - **策略**:可考慮將 `contract_type` 轉為 one‑hot 或 target encoding。 ### 4.4.9 時間序列 若資料中包含 `signup_date`,可進行季度聚合以觀察季節性波動。 python df['signup_date'] = pd.to_datetime(df['signup_date']) quarterly = df.groupby(pd.Grouper(key='signup_date', freq='Q')).size() quarterly.plot(kind='bar') plt.title('客戶簽約季度分布') plt.show() - **洞察**:某些季節簽約量激增,後續模型可加入季節指標。 ## 4.5 EDA 常見陷阱 | 陷阱 | 影響 | 解決方案 | |------|------|----------| | **過度依賴箱形圖** | 可能忽略多峰或右/左偏斜 | 搭配直方圖與 KDE | | **忽略缺失值分佈** | 造成偏差估計 | 繪製缺失熱力圖 | | **混合型別資料未分開處理** | 造成計算錯誤 | 使用 `select_dtypes()` 分類處理 | | **多重檢定忽略校正** | 假陽性風險 | 采用 Benjamini‑Hochberg | | **過度解讀相關係數** | 可能誤判因果 | 使用 Granger‑Causality 或因子分析 | ## 4.6 從洞察到決策 - **特徵選擇**:根據相關性熱力圖與分佈特徵,挑選 `age`, `tenure`, `monthly_charge`,並對 `monthly_charge` 做 log‑transform。 - **特徵工程**:將 `contract_type` 轉為 one‑hot;為 `tenure` 創建分段特徵(如 0‑12, 13‑24…)。 - **模型驗證**:在特徵工程完成後,進行交叉驗證,確保改動帶來的提升可被統計檢定。 ## 4.7 小結 > EDA 不是一個「一次性」任務,而是資料科學流程中 **動態迭代** 的基石。透過統計檢定與可視化,我們能快速捕捉資料中的不一致、偏差與關聯,為特徵工程與模型建構提供堅實依據。 > > 本章以客戶流失案例為藍本,示範了從描述統計、缺失值、分佈檢定到相關性矩陣、外脫值、類別特徵分析的完整流程。隨著資料量與複雜度的增加,建議將上述步驟封裝成 **自動化 EDA pipeline**,並結合監控(如 Evidently)即時偵測資料漂移。 > 下一章將進一步探討 **特徵拆解與縮減**,把 EDA 所得到的洞察轉化為可直接投入模型的特徵,並深入講解主成份分析(PCA)與特徵選擇演算法。