首先创建一个包含多种缺失值情况的 DataFrame:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'姓名': ['张三', '李四', '王五', '赵六', '陈七'],
'年龄': [28, np.nan, 42, 29, np.nan],
'工资': [8000, 12000, np.nan, 9500, 11000],
'部门': ['技术', '销售', np.nan, '管理', '销售'],
'入职日期': pd.date_range('2020-01-01', periods=5).insert(2, pd.NaT).delete(3) # 制造缺失日期
})
print("原始数据:")
print(df)
在进行任何处理之前,首先需要了解缺失值的分布情况。
isna() / isnull()返回布尔型 DataFrame,缺失值位置为 True,否则为 False。
df.isna()
df['年龄'].isna()
notna() / notnull()与 isna() 相反,非缺失值为 True。
df.notna()
# 统计每列缺失数量
print(df.isna().sum())
# 统计每行缺失数量
print(df.isna().sum(axis=1))
# 查看有缺失值的行
print(df[df.isna().any(axis=1)])
# 查看全部没有缺失值的行
print(df[df.notna().all(axis=1)])
dropna()直接删除包含缺失值的行或列,适用于缺失数据占比很小或随机缺失的情况。
df.dropna() # 默认删除任何包含NaN的行
df.dropna(how='any') # 同上(默认)
df.dropna(how='all') # 仅删除全为NaN的行
df.dropna(thresh=3) # 保留至少有3个非空值的行
df.dropna(axis=1) # 删除任何包含NaN的列
df.dropna(axis=1, how='all') # 仅删除全为NaN的列
# 删除年龄缺失的行
df.dropna(subset=['年龄'])
# 原地修改
df.dropna(inplace=True)
fillna()用指定值、统计量或前/后值填充缺失值,是更常用的策略,可以保留数据样本量。
df.fillna(0) # 所有NaN替换为0
df['年龄'].fillna(df['年龄'].mean()) # 用均值填充年龄
df.fillna(method='ffill') # 用上一行值填充
df.fillna(method='bfill') # 用下一行值填充
df.fillna(method='ffill', limit=1) # 最多连续填充1个缺失
# 对不同列使用不同填充值
df.fillna({'年龄': df['年龄'].median(), '部门': '未知'})
# 用每列的均值填充
df.fillna(df.mean(numeric_only=True))
# 对分类列用众数填充
df['部门'].fillna(df['部门'].mode()[0], inplace=True)
# 对时间序列使用插值
df['入职日期'].fillna(method='ffill', inplace=True) # 或使用 interpolate()
interpolate()对于有序数据(如时间序列),插值方法可以更合理地估计缺失值。
# 线性插值(默认)
df['年龄'].interpolate()
# 时间插值(适用于日期索引)
df.set_index('入职日期', inplace=True)
df['年龄'].interpolate(method='time')
df.reset_index(inplace=True) # 恢复索引
# 多项式插值
df['年龄'].interpolate(method='polynomial', order=2)
有时数据中用特殊值(如 -999, 'NULL', '?')表示缺失,需要先转换为 NaN。
# 读取时指定
df = pd.read_csv('data.csv', na_values=['NULL', '?', '-999'])
# 读取后替换
df.replace(['NULL', '?', -999], np.nan, inplace=True)
axis 0=行,1=列
how 'any'或'all'
thresh 非空值阈值
subset 指定列
inplace 原地修改
method 'ffill'/'bfill'等
limit 填充次数限制
import pandas as pd
import numpy as np
# 创建示例数据
df = pd.DataFrame({
'日期': pd.date_range('2024-01-01', periods=10),
'销量': [100, np.nan, 150, np.nan, 200, 180, np.nan, 210, 190, 220],
'类别': ['A', 'B', np.nan, 'A', 'B', 'A', 'B', 'A', np.nan, 'B']
})
print("原始数据:")
print(df)
print("\n缺失统计:")
print(df.isna().sum())
# 处理策略
# 1. 删除类别缺失的行(因为类别是离散的,无法填充)
df_cleaned = df.dropna(subset=['类别'])
print("\n删除类别缺失后:")
print(df_cleaned)
# 2. 对销量列用前向填充(假设时间序列趋势)
df_cleaned['销量'] = df_cleaned['销量'].fillna(method='ffill')
print("\n销量前向填充后:")
print(df_cleaned)
# 3. 剩余的缺失可能已不存在
print("\n最终缺失统计:")
print(df_cleaned.isna().sum())
method='ffill' 时需确保数据已排序,否则会从错误的上一条记录填充。
isna(),不能用 == np.nan。
df.info() 和 df.isna().sum() 了解缺失情况。