返回目錄
A
資料驅動決策:從數據探索到模型部署 - 第 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 進行清理時,建議編寫 **模組化、可重現** 的程式碼,並結合日誌與版本控制,確保資料品質可追蹤。
> **下一章**:將學習如何以圖形化方式探索資料,進一步發掘隱藏的關係與趨勢。