本文目录导读:

我来详细讲解如何使用Pandas进行数据插补,包含多种场景和方法。
基础环境准备
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 创建包含缺失值的示例数据
np.random.seed(42)
df = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=100, freq='D'),
'temperature': [20 + np.random.randn() * 5 if np.random.random() > 0.2 else np.nan
for _ in range(100)],
'humidity': [60 + np.random.randn() * 10 if np.random.random() > 0.15 else np.nan
for _ in range(100)],
'category': np.random.choice(['A', 'B', 'C'], 100)
})
print("原始数据概览:")
print(df.info())
print(f"\n缺失值统计:\n{df.isnull().sum()}")
多种插补方法实战
1 简单统计插补
def simple_imputation(df):
"""演示各种简单插补方法"""
df_imputed = df.copy()
# 方法1:使用列均值插补
df_imputed['temperature_mean'] = df_imputed['temperature'].fillna(df_imputed['temperature'].mean())
# 方法2:使用中位数插补(适合有异常值的数据)
df_imputed['temperature_median'] = df_imputed['temperature'].fillna(df_imputed['temperature'].median())
# 方法3:使用众数插补(适合分类数据)
df_imputed['category_mode'] = df_imputed['category'].fillna(df_imputed['category'].mode()[0])
# 方法4:使用常数插补
df_imputed['temperature_constant'] = df_imputed['temperature'].fillna(25) # 假设默认温度25度
print("简单插补结果对比:")
print(df_imputed[['temperature', 'temperature_mean', 'temperature_median', 'temperature_constant']].head())
return df_imputed
df_simple = simple_imputation(df)
2 时间序列插补
def time_series_imputation(df):
"""时间序列数据插补方法"""
df_ts = df.copy()
df_ts.set_index('date', inplace=True)
# 方法1:前向填充
df_ts['temp_ffill'] = df_ts['temperature'].fillna(method='ffill')
# 方法2:后向填充
df_ts['temp_bfill'] = df_ts['temperature'].fillna(method='bfill')
# 方法3:线性插值
df_ts['temp_linear'] = df_ts['temperature'].interpolate(method='linear')
# 方法4:时间加权插值
df_ts['temp_time'] = df_ts['temperature'].interpolate(method='time')
# 查看某段缺失数据的插补效果
na_indices = df_ts['temperature'].isna()
print(f"缺失值位置:{na_indices.sum()}个")
print("\n插补效果示例:")
print(df_ts[na_indices].head())
return df_ts
df_ts = time_series_imputation(df)
3 高级插补方法
from sklearn.impute import KNNImputer, SimpleImputer
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
def advanced_imputation(df):
"""高级插补方法"""
# 准备数据(排除非数值列)
numeric_cols = ['temperature', 'humidity']
df_numeric = df[numeric_cols].copy()
# 方法1:KNN插补
knn_imputer = KNNImputer(n_neighbors=3)
df_knn = pd.DataFrame(
knn_imputer.fit_transform(df_numeric),
columns=numeric_cols
)
# 方法2:多重插补(MICE)
mice_imputer = IterativeImputer(
max_iter=10,
random_state=42,
imputation_order='random'
)
df_mice = pd.DataFrame(
mice_imputer.fit_transform(df_numeric),
columns=numeric_cols
)
# 方法3:分组均值插补
df_grouped = df.copy()
df_grouped['temp_group_mean'] = df_grouped.groupby('category')['temperature'].transform(
lambda x: x.fillna(x.mean())
)
print("KNN插补结果:")
print(df_knn.head())
print(f"\nMICE插补结果:")
print(df_mice.head())
print(f"\n分组均值插补结果:")
print(df_grouped[['category', 'temperature', 'temp_group_mean']].head())
return df_knn, df_mice, df_grouped
df_knn, df_mice, df_grouped = advanced_imputation(df)
4 综合插补策略
def comprehensive_imputation_strategy(df):
"""综合插补策略"""
def custom_imputer(series, method='mixed'):
"""
自定义插补函数
method: 'mixed' - 混合策略, 'auto' - 自动选择
"""
if series.isnull().sum() == 0:
return series
missing_pct = series.isnull().mean()
if method == 'mixed':
if missing_pct < 0.1:
# 缺失<10%:使用均值或中位数
return series.fillna(series.median())
elif missing_pct < 0.3:
# 缺失10%-30%:使用插值
return series.interpolate(method='linear')
else:
# 缺失>30%:使用多重插补
imputer = IterativeImputer(max_iter=5)
return pd.Series(
imputer.fit_transform(series.values.reshape(-1, 1)).flatten(),
index=series.index
)
return series
# 应用自定义插补策略
df_result = df.copy()
for col in ['temperature', 'humidity']:
df_result[f'{col}_imputed'] = custom_imputer(df_result[col])
print("综合插补策略结果:")
print(f"原始数据缺失率: {df['temperature'].isnull().mean():.2%}")
print(f"插补后缺失率: {df_result['temperature_imputed'].isnull().sum()}")
return df_result
df_comprehensive = comprehensive_imputation_strategy(df)
插补效果评估
def evaluate_imputation(original_df, imputed_df, true_values=None):
"""评估插补效果"""
# 模拟真实值(假设我们知道某些缺失值的真实值)
if true_values is None:
# 创建模拟真实值
true_values = {
'temperature': 22.5,
'humidity': 65.0
}
# 计算误差
print("插补效果评估:")
for col in ['temperature', 'humidity']:
imputed_col = f'{col}_imputed' if f'{col}_imputed' in imputed_df.columns else col
if imputed_col in imputed_df.columns:
# 获取插补后的值
imputed_values = imputed_df[imputed_col]
# 计算基本统计
print(f"\n{col}插补结果统计:")
print(f" 均值: {imputed_values.mean():.2f}")
print(f" 标准差: {imputed_values.std():.2f}")
print(f" 最小值: {imputed_values.min():.2f}")
print(f" 最大值: {imputed_values.max():.2f}")
# 可视化比较
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
for i, col in enumerate(['temperature', 'humidity']):
axes[i].hist(original_df[col].dropna(), alpha=0.5, label='原始数据', bins=20)
if f'{col}_imputed' in imputed_df.columns:
axes[i].hist(imputed_df[f'{col}_imputed'], alpha=0.5, label='插补后数据', bins=20)
axes[i].set_title(f'{col} 分布对比')
axes[i].legend()
plt.tight_layout()
plt.show()
return imputed_values
evaluate_imputation(df, df_comprehensive)
实战案例:销售数据插补
def sales_data_imputation_example():
"""销售数据插补实战案例"""
# 创建销售数据
np.random.seed(42)
sales_data = pd.DataFrame({
'date': pd.date_range('2024-01-01', '2024-03-31', freq='D'),
'sales': [
100 + 50 * np.sin(2 * np.pi * i / 7) + np.random.randn() * 20
for i in range(91)
],
'weekday': [pd.Timestamp('2024-01-01') + pd.Timedelta(days=i) for i in range(91)]
})
# 随机引入缺失值(特别是在周末)
np.random.seed(42)
days_of_week = sales_data['date'].dt.dayofweek
missing_mask = (days_of_week >= 5) & (np.random.random(91) < 0.4) # 周末40%缺失
missing_mask |= (np.random.random(91) < 0.1) # 其他时间10%缺失
sales_data.loc[missing_mask, 'sales'] = np.nan
sales_data['weekday_name'] = sales_data['date'].dt.day_name()
print("销售数据概况:")
print(f"数据量: {len(sales_data)}")
print(f"缺失值: {sales_data['sales'].isnull().sum()}")
print(f"缺失率: {sales_data['sales'].isnull().mean():.2%}")
# 多种插补方法对比
sales_data['sales_weekday_mean'] = sales_data.groupby('weekday_name')['sales'].transform(
lambda x: x.fillna(x.mean())
)
sales_data['sales_ffill'] = sales_data['sales'].fillna(method='ffill')
sales_data['sales_linear'] = sales_data['sales'].interpolate(method='linear')
# 使用季节性插补
sales_data['sales_seasonal'] = sales_data['sales'].interpolate(method='cubic')
print(f"\n插补后数据概况:")
print(sales_data[sales_data['sales'].isna()].head())
# 可视化
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
methods = ['weekday_mean', 'ffill', 'linear', 'seasonal']s = ['周平均插补', '前向填充', '线性插值', '三次样条插值']
for i, (method, title) in enumerate(zip(methods, titles)):
row, col = i // 2, i % 2
# 近30天数据对比
recent = sales_data.tail(30)
axes[row, col].plot(recent['date'], recent['sales'], 'o-', label='原始数据', alpha=0.6)
axes[row, col].plot(recent['date'], recent[f'sales_{method}'], 's--', label=f'{title}插补', alpha=0.8)
axes[row, col].set_title(f'{title}插补效果')
axes[row, col].legend()
axes[row, col].tick_params(axis='x', rotation=45)
plt.tight_layout()
plt.show()
return sales_data
sales_data = sales_data_imputation_example()
最佳实践建议
def imputation_best_practices():
"""数据插补最佳实践"""
print("数据插补最佳实践建议:")
print("="*50)
print("""
1. **缺失值分析**
- 了解缺失模式:随机缺失(MCAR/MAR)还是非随机缺失(MNAR)
- 评估缺失比例:<5%可忽略,5-20%需要插补,>20%需谨慎
2. **选择合适的插补方法**
- 连续变量:均值、中位数、线性插值
- 分类变量:众数、类别插补
- 时间序列:前向/后向填充、时间插值
- 多变量关系:KNN、MICE
3. **实用技巧**
- 先处理异常值,再进行插补
- 考虑业务逻辑,如销售额不能为负
- 对关键变量使用三种以上方法对比
4. **避免的陷阱**
- 不要盲目使用均值插补
- 不要忽略缺失值背后的业务原因
- 避免数据泄露(用训练集统计量插补)
5. **评估标准**
- 保持数据分布特征
- 维持变量间相关性
- 业务合理性检验
""")
imputation_best_practices()
- 基础方法:fillna(), interpolate() 是Pandas内置的常用函数
- 高级方法:Scikit-learn提供KNNImputer、IterativeImputer等
- 业务理解:插补策略应考虑数据特征和业务逻辑
- 效果评估:通过分布对比、统计指标验证插补质量
- 综合应用:根据缺失比例和数据类型选择合适策略
这些方法可以灵活组合使用,找到最适合你具体场景的插补方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播