You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按列值上限聚合行?pd.DataFrame的10天等桶聚合求助

解决DataFrame按10天等长桶聚合并拆分跨桶行的问题

我明白你的需求了——要把包含days和values的DataFrame按10天的等长桶聚合,还要处理单条记录天数超过10天的情况,拆分后按规则计算桶内的平均值。pd.Grouper确实不太适合这种场景,因为它没法自动拆分跨桶的行,得手动处理拆分逻辑。下面是具体的实现方案:

步骤说明

  1. 先计算累计天数,明确每一行数据对应的时间区间;
  2. 生成所有10天桶的区间边界;
  3. 遍历每一行数据,拆分它跨越的所有桶,计算每个拆分片段的加权值(value * 重叠天数 / 原始天数);
  4. 按桶分组,根据需求计算最终的聚合值(比如你示例中的平均值)。

完整代码实现

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:09:49