本文目录导读:

我来详细讲解如何使用Pandas进行数据分组填充,包含多种常见场景的案例:
基础准备
import pandas as pd
import numpy as np
# 创建示例数据
df = pd.DataFrame({
'group': ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C'],
'value': [1, np.nan, 3, np.nan, 5, np.nan, np.nan, 8],
'date': ['2024-01-01', '2024-01-02', '2024-01-03',
'2024-01-01', '2024-01-02', '2024-01-03',
'2024-01-01', '2024-01-02']
})
print("原始数据:")
print(df)
按组填充缺失值
1 用组内均值填充
# 用每组的平均值填充
df['value_fill_mean'] = df.groupby('group')['value'].transform(lambda x: x.fillna(x.mean()))
print("用组内均值填充:")
print(df[['group', 'value', 'value_fill_mean']])
2 用组内中位数填充
# 用每组的中位数填充
df['value_fill_median'] = df.groupby('group')['value'].transform(lambda x: x.fillna(x.median()))
print("用组内中位数填充:")
print(df[['group', 'value', 'value_fill_median']])
3 用组内众数填充
# 用每组的众数填充
def fill_with_mode(x):
mode_val = x.mode()
if len(mode_val) > 0:
return x.fillna(mode_val[0])
return x
df['value_fill_mode'] = df.groupby('group')['value'].transform(fill_with_mode)
向前/向后填充(时间序列)
# 按组进行前向填充
df['value_ffill'] = df.groupby('group')['value'].transform(lambda x: x.fillna(method='ffill'))
# 按组进行后向填充
df['value_bfill'] = df.groupby('group')['value'].transform(lambda x: x.fillna(method='bfill'))
print("前后填充结果:")
print(df[['group', 'value', 'value_ffill', 'value_bfill']])
复杂填充场景
1 按组填充特定值
# 不同组使用不同填充值
fill_values = {'A': 0, 'B': 100, 'C': -1}
df['value_custom'] = df.groupby('group')['value'].transform(
lambda x: x.fillna(fill_values[x.name])
)
print("自定义填充:")
print(df[['group', 'value', 'value_custom']])
2 组合填充策略
def smart_fill(series):
"""智能填充:先用ffill,再用后向填充,最后用均值"""
# 首先前向填充
result = series.fillna(method='ffill')
# 然后后向填充
result = result.fillna(method='bfill')
# 最后用均值填充
result = result.fillna(series.mean())
return result
df['value_smart'] = df.groupby('group')['value'].transform(smart_fill)
实际应用案例
1 销售数据分组填充
# 创建销售数据
sales_data = pd.DataFrame({
'store': ['Store_A', 'Store_A', 'Store_A', 'Store_B', 'Store_B', 'Store_B'],
'month': ['Jan', 'Feb', 'Mar', 'Jan', 'Feb', 'Mar'],
'sales': [1000, np.nan, 1200, np.nan, 800, np.nan],
'target': [1100, 1200, 1300, 900, 1000, 1100]
})
print("原始销售数据:")
print(sales_data)
# 按门店填充:用相邻月份的平均值填充
def fill_sales(group):
# 先用线性插值
group['sales_interpolated'] = group['sales'].interpolate(method='linear')
# 如果还有缺失,用目标的80%填充
group['sales_final'] = group['sales_interpolated'].fillna(group['target'] * 0.8)
return group
sales_data = sales_data.groupby('store').apply(fill_sales)
print("\n填充后的销售数据:")
print(sales_data)
2 学生成绩分组填充
# 创建学生成绩数据
grades_data = pd.DataFrame({
'class': ['Class_A']*4 + ['Class_B']*4,
'student': ['Tom', 'Jerry', 'Alice', 'Bob', 'Emma', 'Jack', 'Lily', 'Mike'],
'score': [85, np.nan, 92, 78, np.nan, 88, np.nan, 95]
})
print("原始成绩数据:")
print(grades_data)
# 按班级填充策略
def fill_grades(group):
# 计算班级统计信息
class_stats = {
'mean': group['score'].mean(),
'median': group['score'].median(),
'std': group['score'].std()
}
# 对不同成绩段设置不同填充策略
for idx in group[group['score'].isna()].index:
# 可以基于其他特征设置填充值
# 这里简单用中位数填充
group.loc[idx, 'score_filled'] = class_stats['median']
group['score_filled'] = group['score'].fillna(group['score_filled'])
return group
grades_data = grades_data.groupby('class').apply(fill_grades)
print("\n填充后的成绩数据:")
print(grades_data)
高级技巧
1 条件分组填充
# 根据条件选择填充方式
def conditional_fill(group):
if group['value'].isna().sum() > len(group) * 0.5: # 缺失超过50%
# 用中位数填充
return group.fillna(group.median())
else:
# 用插值法填充
return group.interpolate()
df['value_conditional'] = df.groupby('group')['value'].transform(conditional_fill)
2 滚动窗口填充
# 使用滚动窗口均值填充
def rolling_fill(series, window=2):
# 计算滚动均值
rolling_mean = series.rolling(window=window, min_periods=1).mean()
# 填充缺失值
return series.fillna(rolling_mean)
df['value_rolling'] = df.groupby('group')['value'].transform(lambda x: rolling_fill(x))
性能优化建议
# 大数据集优化
def fast_group_fill(df, group_col, value_col, method='mean'):
"""高效的组内填充函数"""
if method == 'mean':
fill_values = df.groupby(group_col)[value_col].transform('mean')
elif method == 'median':
fill_values = df.groupby(group_col)[value_col].transform('median')
elif method == 'ffill':
fill_values = df.groupby(group_col)[value_col].transform(lambda x: x.ffill())
return df[value_col].fillna(fill_values)
# 使用示例
df['value_fast'] = fast_group_fill(df, 'group', 'value', 'mean')
完整示例代码
import pandas as pd
import numpy as np
# 完整的填充示例
def complete_group_fill_example():
# 创建测试数据
df = pd.DataFrame({
'group': np.repeat(['A', 'B', 'C'], 5),
'time': np.tile(range(5), 3),
'value': [1, np.nan, 3, np.nan, 5,
np.nan, 7, np.nan, 9, 10,
11, 12, np.nan, np.nan, 15]
})
print("原始数据:")
print(df)
# 1. 简单填充
df['fill_mean'] = df.groupby('group')['value'].transform(lambda x: x.fillna(x.mean()))
df['fill_median'] = df.groupby('group')['value'].transform(lambda x: x.fillna(x.median()))
# 2. 插值填充(考虑时间顺序)
df['fill_interpolate'] = df.groupby('group')['value'].transform(
lambda x: x.interpolate(method='linear')
)
# 3. 前向填充
df['fill_ffill'] = df.groupby('group')['value'].transform(lambda x: x.ffill())
# 4. 链式填充(多重策略)
def chain_fill(series):
# 先向前填充,再向后填充,最后用均值
return series.fillna(method='ffill').fillna(method='bfill').fillna(series.mean())
df['fill_chain'] = df.groupby('group')['value'].transform(chain_fill)
print("\n所有填充结果:")
print(df[['group', 'time', 'value', 'fill_mean', 'fill_median',
'fill_interpolate', 'fill_ffill', 'fill_chain']])
return df
# 运行示例
result_df = complete_group_fill_example()
这些方法覆盖了大部分分组填充的场景,你可以根据实际需求选择合适的方法,建议在处理真实数据时,先了解数据的特点和缺失值的分布,再选择合适的填充策略。