聊天視窗

資料驅動決策:從數據探索到模型部署 - 第 1 章

第一章:資料探索與清理

發布於 2026-02-27 15:01

# 第一章:資料探索與清理 在資料科學的工作流程中,**資料探索與清理**是最基礎、最關鍵的環節。資料的品質直接決定了後續模型的效能與可解釋性。以下將詳細說明從資料採集、缺失值處理、重複資料剔除到資料型態轉換的完整流程,並配合實際 Python 範例(pandas)提供可執行的程式碼。 --- ## 1.1 資料採集:從來源到檔案 | 來源 | 典型格式 | 優勢 | 局限 | 典型工具 | |------|----------|------|------|----------| | SQL 資料庫 | .csv、.json | 結構化、完整性約束 | 需授權、資料庫連線設定 | `sqlalchemy`, `pymysql` | | Web API | JSON | 近即時、易於整合 | 速率限制、網路不穩 | `requests`, `httpx` | | 文字檔 | .txt, .log | 低成本、靈活 | 需自行解析 | `open`, `re` | | Excel | .xlsx | 易於手動編輯 | 大檔案效能差 | `openpyxl`, `xlrd` | | 雲端儲存 | Google Drive, S3 | 分散式、擴展性 | 需要 API 金鑰 | `gcsfs`, `boto3` | | > **實務提示**: > - **版本控制**:將資料採集腳本放入版本控制,確保資料採集流程可重現。 > - **日誌記錄**:採集過程中要產生 `log`,方便排查錯誤。 python # 範例:從 SQL 讀取資料並存成 CSV import pandas as pd from sqlalchemy import create_engine engine = create_engine('mysql+pymysql://user:pwd@host:3306/dbname') query = "SELECT * FROM sales WHERE date >= '2023-01-01'" df = pd.read_sql(query, engine) # 儲存 df.to_csv('data/sales_2023.csv', index=False) --- ## 1.2 資料結構與型態檢查 ### 1.2.1 `df.dtypes` 之重要性 > 資料型態決定了 pandas 對每個欄位進行運算的方式。若型態錯誤,計算可能出現預期之外的結果或耗時。 python # 檢查型態 print(df.dtypes) ### 1.2.2 常見型態轉換 | 原始型態 | 目標型態 | 適用情境 | |----------|----------|----------| | `object` | `int64` | 數值欄位被誤讀為字串 | | `object` | `float64`| 小數欄位被誤讀 | | `object` | `datetime64[ns]` | 日期時間欄位 | | `category` | `object` | 節省記憶體但不需要類別性 | | > **範例**:將 `order_date` 欄位轉為 datetime,並設定缺失值為 `NaT`。 python # 轉型 datetime df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce') # 將字串 'N/A' 轉為 NaN df['amount'] = df['amount'].replace('N/A', pd.NA).astype(float) --- ## 1.3 缺失值處理 缺失值(Missing Value)是資料清理中最常見且最棘手的問題。不同的處理方法對模型有不同影響,需視業務與資料特性選擇。 ### 1.3.1 常見缺失值表示 | 表示 | 典型情境 | |------|----------| | `NaN` | IEEE 浮點 NaN | | `None` | Python 空值 | | `''` | 空字串 | | `-999` | 佔位符 | | ### 1.3.2 缺失值檢查 python # 逐欄缺失值統計 missing = df.isna().sum() print(missing) ### 1.3.3 處理策略 | 方式 | 適用條件 | 典型方法 | |------|----------|----------| | 刪除 | 缺失比例 < 5% 且資料量足 | `dropna()` | | 補值 | 欄位屬性較為一致 | `fillna()`(常數、均值、中位數、前後值) | | 模型補值 | 變數間高度相關 | 回歸、KNN 等 | | 分類特徵 | 類別不重要 | 佔位符 `'Unknown'` | | > **實務案例**: > - `amount` 欄位若缺失,使用同類商品的平均金額補值。 > - 日期欄位若缺失,可使用前一天的值(`ffill`)或最常見日期(mode)。 python # 刪除缺失比例 > 20% 的欄位 threshold = 0.2 cols_to_drop = missing[missing > df.shape[0]*threshold].index df.drop(columns=cols_to_drop, inplace=True) # 補值範例:均值補值 mean_amount = df['amount'].mean() df['amount'].fillna(mean_amount, inplace=True) --- ## 1.4 重複資料剔除 重複資料會導致統計指標失真、模型學習偏差。pandas 提供 `duplicated()` 與 `drop_duplicates()` 兩個關鍵函式。 python # 標示重複行(全部欄位相同) duplicated_rows = df.duplicated(keep=False) print(df[duplicated_rows]) # 刪除重複行(保留第一筆) df_clean = df.drop_duplicates(keep='first') > **細節說明**: > - `keep='first'`:保留第一筆、刪除其後。 > - `keep='last'`:保留最後一筆。 > - `keep=False`:標示所有重複行。 > - 若只關注關鍵欄位(如 `order_id`),可使用 `subset=['order_id']`。 --- ## 1.5 資料型態轉換:數值與類別 ### 1.5.1 數值型態(Numeric) - `int64`:離散整數。 - `float64`:連續數值。 > **注意**:若有過大數字(> 2^63-1)或小數精度需求,請使用 `decimal.Decimal` 或 `numpy.float128`(Linux)。 ### 1.5.2 類別型態(Categorical) > 使用 `category` 能節省記憶體並提升某些模型(如 LightGBM、CatBoost)的運算速度。 python # 將產品類別轉為 category df['product_category'] = df['product_category'].astype('category') ### 1.5.3 日期時間型態(Datetime) > 轉為 `datetime64[ns]` 後,可利用 pandas 的時間系列功能(`.dt.year`, `.dt.month` 等)。 python # 解析日期 df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce') # 提取年月日 df['order_year'] = df['order_date'].dt.year df['order_month'] = df['order_date'].dt.month --- ## 1.6 範例:完整清理流程 以下提供一個結合前述步驟的完整範例,方便快速驗證。 python import pandas as pd # 1. 讀取 raw = pd.read_csv('data/raw_sales.csv') # 2. 型態檢查 print(raw.dtypes) # 3. 清理 # 3.1 日期轉換 raw['order_date'] = pd.to_datetime(raw['order_date'], errors='coerce') # 3.2 金額轉 float raw['amount'] = raw['amount'].replace('N/A', pd.NA).astype(float) # 3.3 刪除重複 raw.drop_duplicates(subset=['order_id'], keep='first', inplace=True) # 3.4 缺失值處理 # 刪除缺失比例 > 20% 的欄位 missing = raw.isna().sum() cols_to_drop = missing[missing > raw.shape[0]*0.2].index raw.drop(columns=cols_to_drop, inplace=True) # 補值(均值) for col in raw.columns: if raw[col].dtype in ['float64', 'int64']: raw[col].fillna(raw[col].mean(), inplace=True) else: raw[col].fillna('Unknown', inplace=True) # 3.5 類別轉型 raw['product_category'] = raw['product_category'].astype('category') # 4. 儲存 raw.to_csv('data/clean_sales.csv', index=False) print('清理完成,檔案已儲存於 data/clean_sales.csv') --- ## 1.7 常見陷阱與最佳實踐 | 陷阱 | 影響 | 解決方案 | |------|------|----------| | 讀取時自動轉型錯誤 | 文字欄位被轉為數值或日期 | 使用 `dtype` 指定型態或 `low_memory=False` | | 缺失值標記混用 | `NaN`、`None`、`''` 混雜 | 先統一標記為 `pd.NA`,再轉為 `float`/`int` | | 重複行過濾不全 | 只檢查部分欄位 | `subset` 參數明確指定關鍵欄位 | | 大型資料切片 | 記憶體不足 | 逐塊讀取 (`chunksize`) 或使用 Dask | | > **最佳實踐**: > 1. 每一步都寫入日誌,並保存處理後的中間檔。 > 2. 使用版本控制管理資料檔(如 DVC、git-lfs)。 > 3. 與業務人員確認欄位意義,避免自動化過度解讀。 > 4. 定期重跑清理腳本,確保資料持續一致。 --- ## 1.8 小結 - 資料清理是資料科學流程中不可或缺的一環,直接影響後續分析與模型效能。 - 掌握 **資料採集、型態轉換、缺失值處理、重複資料剔除** 的基本技巧,能在實務中快速解決常見問題。 - 使用 pandas 進行清理時,建議編寫 **模組化、可重現** 的程式碼,並結合日誌與版本控制,確保資料品質可追蹤。 > **下一章**:將學習如何以圖形化方式探索資料,進一步發掘隱藏的關係與趨勢。