Python案例如何用Pandas做数据分组填充

wen python案例 1

本文目录导读:

Python案例如何用Pandas做数据分组填充

  1. 基础准备
  2. 按组填充缺失值
  3. 向前/向后填充(时间序列)
  4. 复杂填充场景
  5. 实际应用案例
  6. 高级技巧
  7. 性能优化建议
  8. 完整示例代码

我来详细讲解如何使用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()

这些方法覆盖了大部分分组填充的场景,你可以根据实际需求选择合适的方法,建议在处理真实数据时,先了解数据的特点和缺失值的分布,再选择合适的填充策略。

抱歉,评论功能暂时关闭!