🧹 缺失值处理(一)

📌 检测 · 删除 · 策略

✏️ 真实数据中缺失值无处不在。本节课掌握 缺失值检测(isnull、sum、可视化)与 缺失值删除(dropna 参数详解),为后续插补打下坚实基础。

🔍 一、缺失值检测

1.1 isnull() + sum() —— 快速定位

isnull() 返回布尔 DataFrame,sum() 按列统计缺失数量。配合 sort_values() 一目了然。

import pandas as pd
import numpy as np

# 示例数据
df = pd.DataFrame({
    '姓名': ['小智', '小霞', '小刚', '小茂', None],
    '年龄': [10, None, 12, 11, 13],
    '宝可梦': ['皮卡丘', '海星星', None, '妙蛙种子', '小火龙'],
    '徽章数': [3, 5, 2, None, 4]
})

# 缺失值检测
print(df.isnull().sum())
# 输出:
# 姓名      1
# 年龄      1
# 宝可梦    1
# 徽章数    1
# dtype: int64

# 缺失比例
print(df.isnull().mean().round(3) * 100)
列名缺失数量缺失率数据类型
姓名120%object
年龄120%float64
宝可梦120%object
徽章数120%float64

1.2 缺失值可视化(热力图 / 条形图)

使用 matplotlib + seaborn 或 missingno 库直观展示缺失模式。下方为 SVG 模拟热力图。

🧊 缺失值热力图 (模拟) 姓名 年龄 宝可梦 徽章数 道馆 有值 缺失

📊 黄色块表示缺失值,可快速发现缺失集中在哪些样本和特征。

🗑️ 二、缺失值删除 —— dropna() 策略与参数

dropna() 是处理缺失最直接的方法,但需谨慎使用。核心参数如下:

参数类型说明示例
axis0 / 10 删除行(默认),1 删除列df.dropna(axis=0)
how'any' / 'all''any' 存在缺失即删(默认),'all' 全为缺失才删df.dropna(how='all')
threshint保留至少 N 个非空值的行/列df.dropna(thresh=3)
subsetlist只在指定列中检查缺失df.dropna(subset=['年龄','徽章数'])
inplacebool是否原地修改 DataFramedf.dropna(inplace=True)

2.1 基础删除:行 / 列

# 删除任何包含缺失值的行 (默认)
df_clean = df.dropna()
print(df_clean.shape)  # (1, 4) 只剩一行无缺失

# 删除任何包含缺失值的列
df_col = df.dropna(axis=1)
print(df_col.columns)   # Index([], dtype='object') 因为每列都有缺失

2.2 how='all' 只删全空行/列

# 构造全空行
df.loc[5] = [None, None, None, None]
print(df.dropna(how='all').shape)  # 删除第5行,保留其他

2.3 thresh 阈值保留

# 保留至少3个非空值的行
df_thresh = df.dropna(thresh=3)
print(df_thresh)
# 小智、小霞、小刚、小茂 都保留 (缺失不超过1个)

2.4 subset 指定列检查

# 只在 '年龄','徽章数' 两列检查缺失,删除这两列有缺失的行
df_sub = df.dropna(subset=['年龄', '徽章数'])
print(df_sub)  # 小智、小刚、小茂 (小霞年龄缺失被删)
📦 原始数据
➡️
⚙️ axis=0/1
➡️
🔎 how='any'/'all'
➡️
📏 thresh=N
➡️
🎯 subset=[列]
➡️
🧹 干净数据

▲ dropna 参数决策流:按需组合,避免过度删除

🧠 三、删除策略建议

💡 小贴士:dropna() 返回新 DataFrame,除非设置 inplace=True。建议先使用 isnull().sum() 评估缺失情况,再决定删除策略。

📋 四、完整代码示例

import pandas as pd
import numpy as np

# 创建含缺失数据
df = pd.DataFrame({
    '姓名': ['小智', '小霞', '小刚', '小茂', None],
    '年龄': [10, None, 12, 11, 13],
    '宝可梦': ['皮卡丘', '海星星', None, '妙蛙种子', '小火龙'],
    '徽章数': [3, 5, 2, None, 4]
})

# 1. 缺失检测
print("缺失计数:\n", df.isnull().sum())
print("缺失比例:\n", df.isnull().mean())

# 2. 删除策略
# 2.1 默认删除含缺失行
df_drop_any = df.dropna()
print("删除任何缺失行:\n", df_drop_any)

# 2.2 全为空才删
df_drop_all = df.dropna(how='all')
print("全空删除:\n", df_drop_all)

# 2.3 阈值保留
df_thresh = df.dropna(thresh=3)
print("thresh=3:\n", df_thresh)

# 2.4 指定列
df_subset = df.dropna(subset=['年龄', '徽章数'])
print("subset 年龄&徽章:\n", df_subset)