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

使用Pandas将多年时间序列转换为单年平均序列的技术问询

解决方案:用Groupby更合适,同时解决数据点缺失、列名和排序问题

首先直接给结论:groupby是更合适的选择——你的需求是按「月-日-小时」维度分组计算均值,groupby语法更直接高效;而pivot_table更适合需要将分组维度转成列(比如把小时作为列、月份作为行)的透视场景,这里完全用不上。

接下来一步步解决你遇到的三个核心问题:

1. 修复列名问题

你的代码里groupby(...).mean()转成DataFrame后列名还是Energy,可以直接在聚合阶段重命名列,或者用更直观的agg方法指定列名:

# 方式1:聚合后重命名列并转成DataFrame
p50_8760 = df.groupby(['Month', 'Day', 'Hour'])['Energy'].mean().rename('Energy_Mean').to_frame()

# 方式2:用agg直接指定列名,同时保留分组列为普通列(而非索引)
p50_8760 = df.groupby(['Month', 'Day', 'Hour'], as_index=False).agg(Energy_Mean=('Energy', 'mean'))

第二种方式更清晰,直接得到带目标列名的DataFrame,不需要额外处理索引。

2. 确保输出是8760个数据点

数据点不足的原因是原始数据中存在缺失的「月-日-小时」组合(比如包含闰年2月29日的数据,或部分日期的小时数据缺失)。解决方法是先生成平年完整的8760个时间组合基准表,再和分组结果左连接补全:

import pandas as pd

# 1. 定义月份的自然顺序(后续排序的关键)
month_order = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 
               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

# 2. 生成平年完整的小时级时间序列(用2019年这种平年做基准)
full_time_range = pd.date_range(start='2019-01-01 00:00', end='2019-12-31 23:00', freq='H')
full_df = pd.DataFrame({
    'Month': full_time_range.strftime('%b'),  # 转成Jan/Feb格式的月份缩写
    'Day': full_time_range.day,
    'Hour': full_time_range.hour + 1  # 匹配你数据里1-24的小时格式
})
# 将Month转为有序分类,保证后续排序是自然月份顺序
full_df['Month'] = pd.Categorical(full_df['Month'], categories=month_order, ordered=True)

# 3. 对原始数据分组求均值(同步处理月份排序)
df['Month'] = pd.Categorical(df['Month'], categories=month_order, ordered=True)
grouped_mean = df.groupby(['Month', 'Day', 'Hour'], as_index=False).agg(Energy_Mean=('Energy', 'mean'))

# 4. 左连接补全所有时间组合,缺失的均值可按需填充(比如填0或保留NaN)
final_df = pd.merge(full_df, grouped_mean, on=['Month', 'Day', 'Hour'], how='left')
# 若需填充缺失值:
# final_df['Energy_Mean'] = final_df['Energy_Mean'].fillna(0)

这样final_df就会严格包含8760行数据,每个「月-日-小时」组合都存在。

3. 保证月份按自然顺序排列

核心是把Month列转为有序分类(Categorical),指定从Jan到Dec的顺序,这样不管是分组还是排序,都会遵循自然月份顺序,彻底解决默认字母序(比如Apr排在Jan前面)的问题。上面的代码已经包含了这一步骤。

补充:Groupby vs Pivot_table的区别

再明确下为什么不用pivot_table:如果用pivot_table,你可能需要写这样的代码:

# 这不是你要的格式,仅作对比举例
pivot_result = df.pivot_table(index=['Month', 'Day', 'Hour'], values='Energy', aggfunc='mean')

它的结果和groupby类似,但pivot_table更适合「交叉透视」场景——比如你想把Hour作为列、Month作为行,每个单元格显示对应均值,这时候用pivot_table更方便。而你的需求是生成一维的8760行序列,groupby是更简洁的选择。

内容的提问来源于stack exchange,提问作者Aakash

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 08:27:54