聊天視窗

數據科學全能指南:從數據到洞察 - 第 4 章

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

發布於 2026-02-22 23:00

# 第四章:探索性資料分析(EDA) > 探索性資料分析(Exploratory Data Analysis, EDA)是資料科學流程中**首要**且**持續**的步驟。它不僅能幫你快速了解資料的結構、分布與潛在問題,更能為後續特徵工程、模型選擇與假設檢定提供指引。 ## 目錄 1. [為何需要 EDA?](#為何需要-eda) 2. [EDA 的工作流程](#eda-的工作流程) 3. [統計摘要與描述性統計](#統計摘要與描述性統計) 4. [資料視覺化技巧](#資料視覺化技巧) 5. [相關性與共變分析](#相關性與共變分析) 6. [離群值與分佈偏差](#離群值與分佈偏差) 7. [假設檢定與統計檢驗](#假設檢定與統計檢驗) 8. [高維資料的降維與視覺化](#高維資料的降維與視覺化) 9. [實務工作流程範例:Titanic 乘客資料](#實務工作流程範例titanic-乘客資料) 10. [最佳實踐與常見陷阱](#最佳實踐與常見陷阱) 11. [常用工具與函式庫](#常用工具與函式庫) --- ## 為何需要 EDA? | 目的 | 為什麼重要 | 典型工具 | |------|------------|----------| | **確認資料完整度** | 缺失值、重複行、資料型別錯誤都會影響模型 | `pandas.isnull()`, `DataFrame.duplicated()` | | **洞悉分佈** | 了解變數是否偏態或多峰,決定是否需要轉換 | 直方圖、核密度估計 (KDE) | | **偵測離群值** | 離群值可能扭曲統計量或導致模型過擬合 | IQR、Z‑score、箱型圖 | | **發現相關性** | 變數間的相互關係可啟發特徵工程 | 相關係數矩陣、熱力圖 | | **生成假設** | 為後續假設檢定與建模提供基礎 | t‑test、ANOVA、Chi‑square | > **結論**:EDA 不是「可有可無」的步驟,而是每一次資料科學專案中不可或缺的前置檢查,確保後續工作基於可靠且理解透徹的資料。 ## EDA 的工作流程 1. **資料載入**:使用 `pandas.read_csv()` / `read_sql()` 等方式。 2. **基本統計摘要**:`DataFrame.describe()`、`DataFrame.info()`。 3. **缺失值處理**:視情況填補或刪除。 4. **型別轉換**:確保數值型、類別型、時間序列型正確。 5. **視覺化**:直方圖、箱型圖、散佈圖、熱力圖等。 6. **相關性分析**:計算相關係數、進行假設檢定。 7. **離群值偵測**:使用 IQR、Z‑score 或更進階的聚類方法。 8. **統計檢定**:t‑test、ANOVA、非參數檢定等。 9. **文件化結果**:將所有發現記錄於 Jupyter Notebook / 文檔。 10. **重複迭代**:隨著資料更新與問題調整,回到相應步驟。 ## 統計摘要與描述性統計 python import pandas as pd df = pd.read_csv('data/raw/titanic.csv') # 基本資料資訊 print(df.info()) # 描述性統計(數值型) print(df.describe(include='all')) > **提示**:`include='all'` 可同時顯示類別型資料的頻數。若資料量極大,考慮只取前 1000 行進行摘要。 ### 典型統計量 - **平均值**(Mean) - **中位數**(Median) - **眾數**(Mode) - **範圍**(Range) - **標準差**(Standard Deviation) - **變異係數**(Coefficient of Variation) - **四分位數**(Quartiles) ## 資料視覺化技巧 | 視覺化 | 目的 | 典型工具 | |------|------|----------| | 直方圖 | 變數分佈 | `sns.histplot`, `plt.hist` | | KDE | 平滑分佈 | `sns.kdeplot` | | 箱型圖 | 檢測離群值 | `sns.boxplot` | | 散佈圖 | 兩變數關係 | `sns.scatterplot` | | 熱力圖 | 相關性 | `sns.heatmap` | | Pairplot | 多變數關係 | `sns.pairplot` | python import seaborn as sns import matplotlib.pyplot as plt # 直方圖 + KDE sns.histplot(df['Age'].dropna(), kde=True, bins=30) plt.title('Age Distribution') plt.show() # 箱型圖 sns.boxplot(x='Sex', y='Fare', data=df) plt.title('Fare by Sex') plt.show() ### 重要注意 - **時間序列資料**:使用 `plot_date` 或 `tsplot`,並考慮季節性。 - **高維資料**:使用 `pairplot` 或 `scatter_matrix`,但避免在 > 10 個變數時過度渲染。 ## 相關性與共變分析 ### 皮爾遜相關係數 python corr_matrix = df.corr(method='pearson') plt.figure(figsize=(10,8)) sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f') plt.title('Pearson Correlation Heatmap') plt.show() ### 斯皮爾曼等級相關係數(對非線性關係友善) python corr_spearman = df.corr(method='spearman') > **小技巧**:若資料中含有類別型欄位,可先使用 `pd.get_dummies()` 轉換,再進行相關性分析。 ## 離群值與分佈偏差 ### IQR 方法 python Q1 = df['Fare'].quantile(0.25) Q3 = df['Fare'].quantile(0.75) IQR = Q3 - Q1 lower = Q1 - 1.5 * IQR upper = Q3 + 1.5 * IQR outliers = df[(df['Fare'] < lower) | (df['Fare'] > upper)] print(outliers) ### Z‑score 方法 python from scipy import stats df['Fare_z'] = stats.zscore(df['Fare'].dropna()) print(df[df['Fare_z'].abs() > 3]) ### 可視化 - **箱型圖**:直觀顯示離群值。 - **點圖**:將離群值標記為紅點,便於快速定位。 ## 假設檢定與統計檢驗 | 檢定 | 適用場景 | 典型工具 | |------|----------|----------| | t‑test(獨立樣本) | 比較兩組平均值 | `scipy.stats.ttest_ind` | | ANOVA | 多組平均值差異 | `scipy.stats.f_oneway` | | Chi‑square | 類別資料的獨立性 | `scipy.stats.chi2_contingency` | | Mann‑Whitney U | 非參數兩組比較 | `scipy.stats.mannwhitneyu` | python # t‑test: Age 之間的差異是否顯著? from scipy.stats import ttest_ind male_age = df[df['Sex']=='male']['Age'].dropna() female_age = df[df['Sex']=='female']['Age'].dropna() print(ttest_ind(male_age, female_age)) > **注意**:在進行假設檢定前,確認變數符合檢定的假設(如正態分佈、等方差)。若不符,可採用非參數檢定。 ## 高維資料的降維與視覺化 ### 主成分分析(PCA) python from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler numeric_cols = df.select_dtypes(include=['float64','int64']).columns X = df[numeric_cols].dropna() X_std = StandardScaler().fit_transform(X) pca = PCA(n_components=2) principal_components = pca.fit_transform(X_std) pc_df = pd.DataFrame(data=principal_components, columns=['PC1', 'PC2']) ### t‑SNE(保留局部結構) python from sklearn.manifold import TSNE tsne = TSNE(n_components=2, random_state=42) X_tsne = tsne.fit_transform(X_std) plt.scatter(X_tsne[:,0], X_tsne[:,1], alpha=0.5) plt.title('t‑SNE of Titanic Features') plt.show() > **備註**:PCA 主要用於**數值型**資料,t‑SNE 則更適合 **非線性** 高維結構。 ## 實務工作流程範例:Titanic 乘客資料 > 我們將使用 Titanic 乘客資料示範完整的 EDA 步驟,並將結果儲存於 Notebook。 ### 1. 資料載入 python import pandas as pd df = pd.read_csv('data/raw/titanic.csv') ### 2. 基本統計摘要 python print(df.info()) print(df.describe(include='all')) ### 3. 缺失值視覺化 python import seaborn as sns import matplotlib.pyplot as plt sns.heatmap(df.isnull(), cbar=False, yticklabels=False, cmap='viridis') plt.title('Missing Values Heatmap') plt.show() ### 4. 分佈與離群值 python # Age KDE sns.histplot(df['Age'].dropna(), kde=True, bins=30) plt.title('Age Distribution') plt.show() # Fare 箱型圖 sns.boxplot(y='Fare', data=df) plt.title('Fare Boxplot') plt.show() ### 5. 相關性分析 python corr = df.corr(method='pearson') plt.figure(figsize=(10,8)) sns.heatmap(corr, annot=True, cmap='Blues', fmt='.2f') plt.title('Correlation Matrix') plt.show() ### 6. 離群值偵測 python Q1 = df['Fare'].quantile(0.25) Q3 = df['Fare'].quantile(0.75) IQR = Q3 - Q1 lower = Q1 - 1.5 * IQR upper = Q3 + 1.5 * IQR outliers = df[(df['Fare'] < lower) | (df['Fare'] > upper)] print('Fare 離群值數量:', outliers.shape[0]) ### 7. 假設檢定 python from scipy.stats import ttest_ind male_fare = df[df['Sex']=='male']['Fare'].dropna() female_fare = df[df['Sex']=='female']['Fare'].dropna() print(ttest_ind(male_fare, female_fare)) ### 8. 文件化 > 在 Jupyter Notebook 中,將所有 **圖表** 與 **統計量** 插入 Markdown 儲存,並撰寫 **摘要段落**,以供團隊分享與決策。 ## 最佳實踐與常見陷阱 | 實踐 | 說明 | |------|------| | **版本控制** | 使用 Git 追蹤 Notebook、CSV 與腳本 | `git add`, `git commit` | | **隨機種子** | 確保圖表與統計結果可重現 | `np.random.seed(42)` | | **資料分割** | 先對完整資料做 EDA,再進行資料切分 | `train_test_split()` 前不做隨機選樣 | | **記錄發現** | 用 Markdown 標註關鍵發現與假設 | `# EDA: Age 低於 0 的觀測值` | | **避免資訊洩漏** | 在 EDA 期間不使用測試集資訊 | `df.sample()` 只用訓練集 | | **關注類別不平衡** | 可透過 `value_counts()` 與 `barplot` | | | **處理缺失值策略** | 根據變數類型決定填補方式 | `df['Age'].fillna(df['Age'].median())` | > **常見陷阱**: > - **過度依賴自動生成圖表**:雖然 `sns.pairplot` 方便,但對大規模資料會耗時且視覺化過於擁擠。 > - **忽略時間序列型資料的季節性**:直接對時間欄位做描述性統計可能產生誤導。 > - **不恰當的離群值處理**:在某些場景下,離群值代表重要資訊,簡單刪除可能喪失關鍵特徵。 ## 常用工具與函式庫 | 函式庫 | 主要功能 | 典型版本 | |--------|----------|----------| | **pandas** | 資料載入、清理、摘要 | 1.5+ | | **seaborn** | 高階統計視覺化 | 0.11+ | | **matplotlib** | 基礎繪圖與自訂 | 3.3+ | | **statsmodels** | 迴歸、假設檢定 | 0.12+ | | **scipy** | 統計檢定、離群值 | 1.7+ | | **scikit‑learn** | 標準化、降維、模型評估 | 1.1+ | | **plotly** | 互動式圖表 | 5+ | --- > **延伸閱讀**: > - *“Exploratory Data Analysis”* by John Tukey (1977) > - *“Practical Statistics for Data Scientists”* by Peter Bruce & Andrew Bruce > - Kaggle 資料科學筆記本(大量實戰案例) > **結語**:透過 EDA,我們不僅能快速檢測資料問題,更能構築對資料的直覺。下一章將把這些洞察轉化為 **特徵工程** 的具體操作,為模型訓練奠定堅實基礎。