聊天視窗

數據洞察:從原始資料到策略決策的全流程分析 - 第 3 章

第 3 章 資料探索與前處理技巧

發布於 2026-02-24 17:02

# 第 3 章 資料探索與前處理技巧 資料探索(Exploratory Data Analysis, EDA)與前處理是數據科學流程中的「前哨」與「鋪路」。透過可視化、統計描述、缺失值與異常值處理,以及特徵工程,我們能把原始資料轉化為可被機器學習模型「理解」的結構化訊息。 --- ## 3.1 數據可視化 | 目的 | 常用圖表 | 使用情境 | |------|----------|----------| | 探索分布 | Histogram、Kernel Density Estimation (KDE) | 檢查是否為正態分布、重複值 | | 比較分組 | Boxplot、Violin plot | 分析各類別之差異 | | 時序趨勢 | Line plot、Seasonal decomposition | 觀察季節性、長期趨勢 | | 相關性 | Heatmap、Scatter plot matrix | 評估特徵間線性或非線性關聯 | python import pandas as pd import seaborn as sns import matplotlib.pyplot as plt df = pd.read_csv('data.csv') # Histogram sns.histplot(df['age'], kde=True) plt.title('年齡分布') plt.show() # Boxplot for categorical variable sns.boxplot(x='gender', y='income', data=df) plt.title('收入對比:男女') plt.show() # Correlation heatmap corr = df.corr() sns.heatmap(corr, annot=True, cmap='coolwarm') plt.title('特徵相關矩陣') plt.show() > **實務提醒**:交互式可視化(如 Plotly、Bokeh)適用於大型資料集或多維分析,可提升探索速度。 --- ## 3.2 統計描述 | 量度 | 公式/說明 | 何時使用 | |------|-----------|----------| | 均值、媒值、眾數 | `mean`, `median`, `mode` | 中心趨勢 | | 標準差、變異數 | `std`, `var` | 散布幅度 | | 四分位數、IQR | `quantile` | 判斷離群 | | Skewness、Kurtosis | `skew`, `kurtosis` | 檢測分布形狀 | python summary = df.describe().T summary['skew'] = df.skew() summary['kurtosis'] = df.kurtosis() print(summary) > **小技巧**:對非連續型變數可直接用 `value_counts()` 觀察頻率分布。 --- ## 3.3 缺失值處理 ### 3.3.1 缺失機制 | 機制 | 例子 | |------|------| | MCAR (Missing Completely At Random) | 隨機抽樣漏填 | 可直接刪除 | | MAR (Missing At Random) | 受觀測變數影響 | 需使用多變量補值 | | MNAR (Missing Not At Random) | 與未觀測變數相關 | 需要專業判斷 | ### 3.3.2 補值方法 | 方法 | 主要工具 | 何時選擇 | |------|----------|----------| | 均值/媒值/眾數 | `SimpleImputer` | 連續/類別、缺失比例低 | | 前向/後向填充 | `ffill`, `bfill` | 時序資料、缺失連續段 | | KNN 補值 | `KNNImputer` | 高維度、非線性關聯 | | 多重插補 (MICE) | `IterativeImputer` | 多變量、缺失比例中等 | | 生成式模型 | `BayesianRidge`, `DNN` | 需求高精度補值 | python from sklearn.impute import SimpleImputer, KNNImputer # 均值補值 imp_mean = SimpleImputer(strategy='mean') df['salary'] = imp_mean.fit_transform(df[['salary']]) # KNN 補值 imp_knn = KNNImputer(n_neighbors=5) X_imp = imp_knn.fit_transform(df[['age', 'salary', 'experience']]) > **注意**:補值前請先視覺化缺失模式,避免盲目補值導致偏差。 --- ## 3.4 異常值檢測 | 方法 | 計算方式 | 典型用途 | |------|----------|----------| | IQR | 1.5*IQR | 連續型離群 | | Z-Score | (x-μ)/σ | 連續型、正態分布 | | DBSCAN | 密度聚類 | 高維、非線性離群 | python from scipy import stats z_scores = stats.zscore(df['income']) abs_z = np.abs(z_scores) outliers = df[abs_z > 3] print('離群數量:', outliers.shape[0]) > **實務**:異常值有時是真實業務事件(如欺詐),不可盲目剔除;先分析其來源再決策。 --- ## 3.5 特徵工程 ### 3.5.1 轉換與標準化 | 目的 | 方法 | 實例 | |------|------|------| | 消除偏態 | `np.log1p`, `np.sqrt`, `boxcox` | `log_income = np.log1p(df['income'])` | | 量綱統一 | `StandardScaler`, `MinMaxScaler` | `X_scaled = scaler.fit_transform(X)` | ### 3.5.2 派生特徵 | 類型 | 技巧 | 典型例子 | |------|------|----------| | 多項式 | `PolynomialFeatures` | `age^2`, `age*experience` | | 時間特徵 | `pd.to_datetime` | `hour`, `day_of_week`, `month` | | 交叉特徵 | `Interaction` | `price*quantity` | | 組合類別 | `Category Encoders` | `gender_age_group` | python from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures(degree=2, include_bias=False) X_poly = poly.fit_transform(df[['age', 'experience']]) ### 3.5.3 編碼類別變數 | 編碼方式 | 何時適用 | 示例 | |-----------|----------|------| | One-Hot | 低基數 | `pd.get_dummies(df['city'])` | | Label | 有序 | `LabelEncoder().fit_transform(df['grade'])` | | Target | `target_encoder` | 根據目標變數的平均值編碼 | | 嵌入 | `Embedding` (NN) | `user_id_embed = EmbeddingLayer(...)` | > **最佳實踐**:將編碼放入 `ColumnTransformer`,確保同一套轉換可在測試集上重複。 --- ## 3.6 資料分割 python from sklearn.model_selection import train_test_split, StratifiedShuffleSplit # 常規分割 X_train, X_temp, y_train, y_temp = train_test_split( X, y, test_size=0.3, random_state=42, stratify=y) # 最終測試集 X_valid, X_test, y_valid, y_test = train_test_split( X_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp) > **時序數據**:使用 `TimeSeriesSplit` 或手動 `df.iloc[:int(len(df)*0.7)]` 等方法,保持時間順序。 --- ## 3.6 資料管道(Pipeline) python from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline from sklearn.preprocessing import OneHotEncoder, StandardScaler numeric_features = ['age', 'income'] numeric_transformer = Pipeline(steps=[ ('imputer', SimpleImputer(strategy='median')), ('scaler', StandardScaler()), ]) categorical_features = ['city', 'gender'] categorical_transformer = Pipeline(steps=[ ('imputer', SimpleImputer(strategy='most_frequent')), ('onehot', OneHotEncoder(handle_unknown='ignore')), ]) preprocessor = ColumnTransformer( transformers=[ ('num', numeric_transformer, numeric_features), ('cat', categorical_transformer, categorical_features), ]) model_pipe = Pipeline(steps=[ ('preprocessor', preprocessor), ('classifier', LogisticRegression()) ]) model_pipe.fit(X_train, y_train) > **好處**:Pipeline 保證 **所有** 步驟在訓練與測試期間一致,減少資料泄漏風險。 --- ## 3.7 小結 | 步驟 | 目的 | 取捨要點 | |------|------|----------| | EDA | 初步判斷資料品質 | 先可視化,再做數值摘要 | | 缺失/異常 | 消除噪音 | 補值前先探查模式 | | 特徵工程 | 產生高維度訊息 | 依業務意義與模型需求平衡 | | Pipeline | 一致性、可重複 | 讓開發流程可被版本控制 | 透過上述技巧,我們能把「雜亂」的原始資料,轉變為 **乾淨、可量化、可解釋** 的特徵集合,為後續的模型訓練與評估奠定堅實基礎。