什麼是缺失值?¶
在數據分析中,缺失值(Missing Value)指的是數據集中某些行或列沒有有效值。比如一份學生成績表中,某學生的數學成績沒填,或者某公司某季度的銷售額數據丟失了。在 pandas 中,缺失值通常用 NaN(Not a Number)表示,有時也會遇到 None,但 NaN 是更標準的數值型缺失值表示。
如何檢查缺失值?¶
在處理缺失值前,第一步是找到數據中哪裏有缺失值。pandas 提供了兩個簡單實用的方法:
1. isnull():標記缺失值¶
df.isnull() 會返回一個布爾型 DataFrame,True 表示該位置是缺失值,False 表示有效數據。
import pandas as pd
import numpy as np
# 創建一個帶缺失值的示例 DataFrame
data = {
'姓名': ['小明', '小紅', '小剛', '小麗', '小強'],
'年齡': [20, np.nan, 22, 21, np.nan],
'成績': [85, 92, np.nan, 78, 88]
}
df = pd.DataFrame(data)
# 檢查所有位置是否缺失
print(df.isnull())
輸出結果:
姓名 年齡 成績
0 False False False
1 False True False
2 False False True
3 False False False
4 False True False
2. isnull().sum():統計缺失值數量¶
df.isnull().sum() 可以快速統計每列的缺失值總數,方便定位問題。
# 統計每列缺失值數量
print(df.isnull().sum())
輸出結果:
姓名 0
年齡 2
成績 1
dtype: int64
3. info():查看數據整體缺失情況¶
df.info() 可以查看每列的數據類型和非空值數量,直觀判斷缺失值分佈。
df.info()
輸出結果:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 姓名 5 non-null object
1 年齡 3 non-null float64
2 成績 4 non-null float64
dtypes: float64(2), object(1)
memory usage: 240.0+ bytes
缺失值處理方法¶
處理缺失值的核心思路是:要麼刪除缺失值,要麼用合理的值填充缺失值。
方法一:刪除缺失值(dropna)¶
當缺失值很少且不影響整體數據時,可以直接刪除包含缺失值的行或列。
1. 刪除有缺失值的行(默認)¶
df.dropna(axis=0, how='any')
- axis=0:刪除行(默認);axis=1:刪除列。
- how='any':只要行/列中有一個缺失值就刪除;how='all':僅當所有值都是缺失值時才刪除。
# 刪除所有有缺失值的行
df_drop_rows = df.dropna(axis=0)
print(df_drop_rows)
輸出結果(僅保留無缺失值的行):
姓名 年齡 成績
0 小明 20.0 85.0
3 小麗 21.0 78.0
2. 刪除有缺失值的列¶
# 刪除所有有缺失值的列
df_drop_cols = df.dropna(axis=1)
print(df_drop_cols)
輸出結果(僅保留無缺失值的列):
姓名
0 小明
1 小紅
2 小剛
3 小麗
4 小強
方法二:填充缺失值(fillna)¶
當缺失值較多或刪除會丟失關鍵信息時,填充缺失值更常用。pandas 的 fillna() 支持多種填充方式。
1. 用固定值填充¶
直接用某個固定值(如 0、-1)填充所有缺失值。
# 用 0 填充所有缺失值
df_fill_0 = df.fillna(0)
print(df_fill_0)
輸出結果:
姓名 年齡 成績
0 小明 20.0 85.0
1 小紅 0.0 92.0
2 小剛 22.0 0.0
3 小麗 21.0 78.0
4 小強 0.0 88.0
2. 用統計量填充(均值/中位數/衆數)¶
數值型數據適合用統計量填充,比如:
- 均值:適合對稱分佈數據(如正態分佈)。
- 中位數:適合偏態分佈數據(抗極端值能力強)。
- 衆數:適合分類數據(出現次數最多的值)。
# 用年齡列的均值填充年齡缺失值
df['年齡'] = df['年齡'].fillna(df['年齡'].mean())
print(df['年齡'])
輸出結果(年齡列均值爲 (20+22+21)/3=21):
0 20.0
1 21.0
2 22.0
3 21.0
4 21.0
Name: 年齡, dtype: float64
3. 向前/向後填充(ffill/bfill)¶
適用於時間序列數據或有順序的數據(如按時間排列的銷售額)。
- ffill():用前一個非缺失值填充後面的缺失值。
- bfill():用後一個非缺失值填充前面的缺失值。
# 模擬時間序列數據
df_time = pd.DataFrame({'value': [1, np.nan, 3, np.nan, 5]})
# 向前填充
df_forward = df_time.fillna(method='ffill')
print("向前填充結果:")
print(df_forward)
# 向後填充
df_backward = df_time.fillna(method='bfill')
print("\n向後填充結果:")
print(df_backward)
輸出結果:
向前填充結果:
value
0 1.0
1 1.0
2 3.0
3 3.0
4 5.0
向後填充結果:
value
0 1.0
1 3.0
2 3.0
3 5.0
4 5.0
綜合實踐案例¶
假設我們有一份電商訂單數據,需要處理缺失值。
數據準備¶
# 訂單數據
orders = {
'訂單ID': [101, 102, 103, 104, 105],
'客戶姓名': ['A', 'B', 'C', 'D', 'E'],
'金額': [150, np.nan, 200, np.nan, 80],
'支付方式': ['微信', '支付寶', np.nan, '微信', '支付寶']
}
df_orders = pd.DataFrame(orders)
步驟1:檢查缺失值¶
print(df_orders.isnull().sum())
輸出:
訂單ID 0
客戶姓名 0
金額 2
支付方式 1
dtype: int64
步驟2:處理缺失值¶
- 金額列:數值型,用均值填充。
- 支付方式列:分類型,用衆數(出現次數最多的值)填充。
# 填充金額列的缺失值(均值)
df_orders['金額'] = df_orders['金額'].fillna(df_orders['金額'].mean())
# 填充支付方式列的缺失值(衆數)
df_orders['支付方式'] = df_orders['支付方式'].fillna(df_orders['支付方式'].mode()[0])
print(df_orders)
輸出結果:
訂單ID 客戶姓名 金額 支付方式
0 101 A 150.0 微信
1 102 B 143.333333 支付寶 # 均值=(150+200+80)/3≈143.33
2 103 C 200.0 支付寶 # 衆數是支付寶(出現2次)
3 104 D 143.333333 微信
4 105 E 80.0 支付寶
總結¶
缺失值處理的核心步驟:
1. 檢查缺失值:用 isnull() 和 isnull().sum() 定位問題。
2. 選擇處理策略:
- 缺失值極少(<5%)且不重要 → 刪除(dropna())。
- 缺失值較多或關鍵數據 → 填充(fillna()),優先用統計量(均值/中位數)或固定值。
3. 驗證結果:處理後再次檢查數據,確保缺失值已合理處理。
處理缺失值沒有“萬能方法”,需結合數據特點和業務需求靈活選擇,避免因處理不當導致數據偏差。