如何按列值上限聚合行?pd.DataFrame的10天等桶聚合求助
解决DataFrame按10天等长桶聚合并拆分跨桶行的问题
我明白你的需求了——要把包含days和values的DataFrame按10天的等长桶聚合,还要处理单条记录天数超过10天的情况,拆分后按规则计算桶内的平均值。pd.Grouper确实不太适合这种场景,因为它没法自动拆分跨桶的行,得手动处理拆分逻辑。下面是具体的实现方案:
步骤说明
- 先计算累计天数,明确每一行数据对应的时间区间;
- 生成所有10天桶的区间边界;
- 遍历每一行数据,拆分它跨越的所有桶,计算每个拆分片段的加权值(
value * 重叠天数 / 原始天数); - 按桶分组,根据需求计算最终的聚合值(比如你示例中的平均值)。
完整代码实现
import pandas as pd # 读取你的CSV数据(替换为实际文件路径) # df = pd.read_csv('your_data.csv') # 模拟示例数据(对应你描述的场景) df = pd.DataFrame({'days': [15, 5, 8, 12], 'values': [15, 20, 10, 30]}) # 计算累计天数,方便确定每一行的时间区间 df['cum_days'] = df['days'].cumsum() # 在开头添加初始累计天数0,方便处理第一行的起始点 df = pd.concat([pd.DataFrame({'days': [0], 'values': [0], 'cum_days': [0]}), df], ignore_index=True) # 生成所有10天桶的起始和结束点 total_days = df['cum_days'].iloc[-1] buckets = list(range(0, int(total_days) + 10, 10)) bucket_intervals = list(zip(buckets[:-1], buckets[1:])) # 存储拆分后的片段数据 split_segments = [] # 遍历每一行原始数据,拆分跨桶的片段 for i in range(1, len(df)): row_start = df['cum_days'].iloc[i-1] row_end = df['cum_days'].iloc[i] row_value = df['values'].iloc[i] row_total_days = df['days'].iloc[i] # 检查当前行是否与每个桶区间重叠 for bucket_start, bucket_end in bucket_intervals: overlap_start = max(row_start, bucket_start) overlap_end = min(row_end, bucket_end) # 如果有重叠,计算重叠天数和对应的加权值 if overlap_start < overlap_end: overlap_days = overlap_end - overlap_start weighted_value = row_value * (overlap_days / row_total_days) split_segments.append({ 'bucket_id': bucket_start // 10, # 桶编号,从0开始 'overlap_days': overlap_days, 'weighted_value': weighted_value }) # 转换为DataFrame方便后续聚合 split_df = pd.DataFrame(split_segments) # 按桶聚合:这里按你示例中的规则,取桶内所有加权值的平均值 result = split_df.groupby('bucket_id')['weighted_value'].mean().reset_index(name='values') # 如果需要按重叠天数加权平均(更通用的场景),可以用下面的代码: # result = split_df.groupby('bucket_id').apply( # lambda x: (x['weighted_value'] * x['overlap_days']).sum() / x['overlap_days'].sum() # ).reset_index(name='values') print("最终聚合结果:") print(result)
代码验证(对应你的示例)
对于你提到的前两行数据:
- 第一行
days=15, values=15:拆分为10天的片段(加权值15*(10/15)=10)和5天的片段(加权值15*(5/15)=5); - 第二行
days=5, values=20:正好填充剩下的5天,加权值就是20; - 第二个桶的平均值为
(5+20)/2=12.5,完全符合你的预期。
为什么pd.Grouper不适用?
pd.Grouper主要用于基于时间戳的固定频率分组(比如按天/月聚合日期数据),但你的场景是基于累计天数的区间拆分,且需要将单条记录拆分到多个桶中,Grouper无法自动处理这种拆分逻辑,所以必须手动实现片段拆分后再聚合。
内容的提问来源于stack exchange,提问作者s3bw
相关产品推荐
相关产品推荐

