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,讓函數自動處理

注意事項

  1. Pandas 的統計方法預設會忽略 NaN

    s = pd.Series([1, 2, None, 4])
    print(s.mean())  # 2.333...(自動忽略 None)
    
  2. NaN 的比較

    np.nan == np.nan  # False
    pd.isna(np.nan)   # True(正確方式)
    
  3. 原地修改

    # 不建議使用 inplace
    df.fillna(0, inplace=True)
    
    # 建議用賦值
    df = df.fillna(0)