Pandas 缺失值處理
真實世界的資料經常會有缺失值(missing values)。Pandas 使用 NaN(Not a Number)來表示缺失值。處理缺失值是資料清理的重要步驟。
範例資料
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', 'Bob', None, 'David', 'Eva'],
'age': [25, None, 35, 28, None],
'city': ['Taipei', 'Tokyo', 'Seoul', None, 'Tokyo'],
'salary': [50000, 60000, None, 55000, 65000]
})
print(df)
name age city salary
0 Alice 25.0 Taipei 50000.0
1 Bob NaN Tokyo 60000.0
2 None 35.0 Seoul NaN
3 David 28.0 None 55000.0
4 Eva NaN Tokyo 65000.0
檢測缺失值
isnull() / isna()
這兩個方法是等價的,回傳布林值:
# 檢測每個值是否為空
print(df.isnull())
name age city salary
0 False False False False
1 False True False False
2 True False False True
3 False False True False
4 False True False False
# 檢測某欄是否有空值
print(df['age'].isnull())
# 找出有空值的列
print(df[df['age'].isnull()])
notnull() / notna()
與 isnull() 相反:
print(df['age'].notnull())
統計缺失值數量
# 每欄的缺失值數量
print(df.isnull().sum())
name 1
age 2
city 1
salary 1
dtype: int64
# 缺失值總數
print(df.isnull().sum().sum()) # 5
# 每欄缺失值比例
print(df.isnull().mean())
# 有缺失值的列數
print(df.isnull().any(axis=1).sum())
刪除缺失值
dropna()
# 刪除任何有缺失值的列(預設)
df_clean = df.dropna()
print(df_clean)
name age city salary
0 Alice 25.0 Taipei 50000.0
只在特定欄位有缺失值時刪除
# 只有 age 欄是空值時才刪除
df_clean = df.dropna(subset=['age'])
控制刪除條件
# how='any':任一欄為空就刪除(預設)
df_clean = df.dropna(how='any')
# how='all':全部欄都為空才刪除
df_clean = df.dropna(how='all')
# thresh:至少要有 n 個非空值才保留
df_clean = df.dropna(thresh=3) # 至少 3 個非空值
刪除有缺失值的欄位
# axis=1 對欄操作
df_clean = df.dropna(axis=1)
填補缺失值
fillna()
# 用固定值填補
df_filled = df.fillna(0)
# 用不同值填補不同欄位
df_filled = df.fillna({
'age': 0,
'city': 'Unknown',
'salary': df['salary'].mean()
})
用統計值填補
# 用平均值填補
df['age'] = df['age'].fillna(df['age'].mean())
# 用中位數填補
df['salary'] = df['salary'].fillna(df['salary'].median())
# 用眾數填補
df['city'] = df['city'].fillna(df['city'].mode()[0])
前向填補和後向填補
# 用前一個值填補(forward fill)
df_filled = df.fillna(method='ffill')
# 或
df_filled = df.ffill()
# 用後一個值填補(backward fill)
df_filled = df.fillna(method='bfill')
# 或
df_filled = df.bfill()
限制填補數量
# 最多連續填補 2 個
df_filled = df.fillna(method='ffill', limit=2)
插值法填補
適合時間序列或有順序的數值資料:
# 線性插值
df_interpolated = df.interpolate()
# 指定插值方法
df_interpolated = df.interpolate(method='linear') # 線性(預設)
df_interpolated = df.interpolate(method='polynomial', order=2) # 多項式
替換特定值為 NaN
有時候資料用特殊值(如 -1、'N/A'、空字串)表示缺失:
# 將 -1 替換為 NaN
df = df.replace(-1, np.nan)
# 將多個值替換為 NaN
df = df.replace(['N/A', '', -1], np.nan)
處理策略選擇
| 情況 | 建議策略 |
|---|---|
| 缺失值很少 | 直接刪除 |
| 缺失值較多,欄位重要 | 用統計值填補 |
| 時間序列資料 | 前向/後向填補或插值 |
| 缺失值比例太高 | 考慮刪除該欄位 |
| 分析時可以忽略 | 保留 NaN,讓函數自動處理 |
注意事項
Pandas 的統計方法預設會忽略 NaN:
s = pd.Series([1, 2, None, 4]) print(s.mean()) # 2.333...(自動忽略 None)NaN 的比較:
np.nan == np.nan # False pd.isna(np.nan) # True(正確方式)原地修改:
# 不建議使用 inplace df.fillna(0, inplace=True) # 建議用賦值 df = df.fillna(0)