You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Pandas按月分组后序列排序错误及需新增近12个月数据求和功能的问题

Pandas按月分组后序列排序错误及需新增近12个月数据求和功能的问题

看起来你碰到了两个实际的小问题:分组后的月份顺序是按字母排的不是时间顺序,还有需要计算近12个月的数据总和。我来一步步帮你搞定~

一、修复月份排序错误的问题

你当前用dt.strftime("%b-%Y")得到的是类似Aug-2022的字符串,Pandas对字符串分组排序是按字母顺序来的(比如Aug因为首字母A在J前面,就排在Jul前面了),所以要让排序遵循实际的时间逻辑,有两种简单的解决方法:

方法1:用月份周期(Period)分组(推荐)

这种方法直接基于时间类型分组,天然按时间顺序排列,之后再格式化索引成你要的样式:

import pandas as pd
import pyodbc

# 先获取原始数据(你的原查询不变)
monthSQL = pd.read_sql_query('SELECT SDATETIME,max(FE014BPV) as flow,max(FE011BPV) as steam  FROM [SCADA].[dbo].[TOTALIZER] GROUP BY SDATETIME ORDER BY SDATETIME ASC', conn)

# 按月份周期分组,自动按时间排序
monthdata = monthSQL.groupby(monthSQL['SDATETIME'].dt.to_period('M'), sort=True).sum()
# 将索引格式化为"月-年"的字符串样式
monthdata.index = monthdata.index.strftime("%b-%Y")
# 重置索引,让SDATETIME成为普通列,匹配你想要的输出格式
monthdata = monthdata.reset_index().rename(columns={'index': 'SDATETIME'})

print(monthdata)

运行后就能得到按May-2022 → Jun-2022 → Jul-2022 → Aug-2022 → Sep-2022顺序排列的结果。

方法2:字符串分组后转为时间类型再排序

如果你更习惯用字符串分组,可以先按字符串分组,再把索引转成时间类型排序,最后转回原格式:

monthSQL = pd.read_sql_query('SELECT SDATETIME,max(FE014BPV) as flow,max(FE011BPV) as steam  FROM [SCADA].[dbo].[TOTALIZER] GROUP BY SDATETIME ORDER BY SDATETIME ASC', conn)

# 先按字符串分组,关闭自动排序
monthdata = monthSQL.groupby(monthSQL['SDATETIME'].dt.strftime("%b-%Y"), sort=False).sum()
# 将索引转为datetime对象,按时间排序
monthdata.index = pd.to_datetime(monthdata.index, format="%b-%Y")
monthdata = monthdata.sort_index()
# 转回"月-年"字符串格式,重置索引
monthdata.index = monthdata.index.strftime("%b-%Y")
monthdata = monthdata.reset_index().rename(columns={'index': 'SDATETIME'})

print(monthdata)

二、新增近12个月数据求和的功能

这里分两种常见场景,你可以根据需求选择:

场景1:对分组后最近12个月份的汇总数据求和

如果你的数据已经按月分组完成,直接取最后12个月的汇总结果求和即可:

# 确保monthdata已经按时间顺序排列好(上面的代码已经处理)
# 取最后12行数据(如果数据不足12个月则取全部)
last_12_months = monthdata.tail(12)
# 计算flow和steam的总和
total_last_12 = last_12_months[['flow', 'steam']].sum()
# 整理成和原有数据一致的格式
total_df = pd.DataFrame({'SDATETIME': ['Last 12 Months Total'],
                         'flow': [round(total_last_12['flow'], 6)],  # 保留6位小数和原数据一致
                         'steam': [round(total_last_12['steam'], 6)]})
# 把总和行追加到原有数据后面
final_data = pd.concat([monthdata, total_df], ignore_index=True)

print(final_data)

场景2:基于原始数据中最新日期往前推12个月的所有数据求和

如果需要的是从最新记录日期倒推12个月内的所有原始数据总和,可以这样处理:

monthSQL = pd.read_sql_query('SELECT SDATETIME,max(FE014BPV) as flow,max(FE011BPV) as steam  FROM [SCADA].[dbo].[TOTALIZER] GROUP BY SDATETIME ORDER BY SDATETIME ASC', conn)

# 找到原始数据中的最新日期
latest_date = monthSQL['SDATETIME'].max()
# 计算12个月前的日期
twelve_months_ago = latest_date - pd.DateOffset(months=12)
# 筛选出这个时间范围内的数据
filtered_data = monthSQL[monthSQL['SDATETIME'] >= twelve_months_ago]
# 计算总和
total_last_12 = filtered_data[['flow', 'steam']].sum()
# 整理成输出格式
total_df = pd.DataFrame({'SDATETIME': ['Last 12 Months Total'],
                         'flow': [round(total_last_12['flow'], 6)],
                         'steam': [round(total_last_12['steam'], 6)]})
# 先处理好月份排序的主数据,再追加总和行
monthdata = monthSQL.groupby(monthSQL['SDATETIME'].dt.to_period('M'), sort=True).sum()
monthdata.index = monthdata.index.strftime("%b-%Y")
monthdata = monthdata.reset_index().rename(columns={'index': 'SDATETIME'})
final_data = pd.concat([monthdata, total_df], ignore_index=True)

print(final_data)

备注:内容来源于stack exchange,提问作者Rushabh Bhosale

火山引擎 最新活动