超大规模电力价格数据集(1.5亿+行)分组分析优化方案问询
优化1.51亿行电力价格数据集的年度波动率计算效率
问题背景
你有一个1.51亿+行的电力价格数据集,包含18065个结算节点,每个节点每年有8760条小时级数据,结构为Node ID(int64)、Datetime(datetime)、Price(float64)。需要计算每个节点的年度平均波动率:
- 每日计算最高4小时均价与最低4小时均价的差值
- 将全年所有日期的差值取平均
现有方案使用pd.groupby结合nsmallest/nlargest,每秒仅处理2个节点,总耗时约2.5小时,需要更高效的分组分析方法。
性能瓶颈分析
现有方案的核心问题在于:
nsmallest/nlargest本质是对每组数据做全量排序,时间复杂度为O(nlogn),在百万级分组场景下开销极大- 嵌套的
groupby(先按节点年份分组,再在组内按日期分组)会产生大量逐组迭代的额外开销 - 重复解析
Datetime字段(每次分组都调用dt.date/dt.year)增加了不必要的计算量
优化方案
1. 预提取日期与年份字段
提前从Datetime中解析出date和year列,避免后续分组时重复解析:
data['date'] = data['Datetime'].dt.date data['year'] = data['Datetime'].dt.year
2. 用Numpy Partition替代全量排序
np.argpartition可以在O(n)时间复杂度内找到第k小/大的元素,无需全量排序,大幅降低单组计算耗时:
import numpy as np def calc_daily_diff(group): prices = group['Price'].values # 获取最低4个价格的均值 bottom4_idx = np.argpartition(prices, 4)[:4] bottom4_mean = prices[bottom4_idx].mean() # 获取最高4个价格的均值 top4_idx = np.argpartition(prices, -4)[-4:] top4_mean = prices[top4_idx].mean() return top4_mean - bottom4_mean
3. 扁平化分组逻辑
拆分两次独立的分组计算,避免嵌套分组的开销:
# 第一步:按节点+日期分组,计算每日差值 daily_diffs = data.groupby(['Node ID', 'date']).apply(calc_daily_diff) # 第二步:按节点+年份分组,计算年度平均波动率 annual_vol = daily_diffs.groupby([ 'Node ID', daily_diffs.index.get_level_values('date').year ]).mean()
4. 极致加速:Numba JIT编译
用Numba对数值计算部分做JIT编译,进一步降低计算耗时:
from numba import njit @njit def numba_calc_diff(prices): bottom4_idx = np.argpartition(prices, 4)[:4] bottom_mean = prices[bottom4_idx].mean() top4_idx = np.argpartition(prices, -4)[-4:] top_mean = prices[top4_idx].mean() return top_mean - bottom_mean # 替换分组调用的函数 daily_diffs = data.groupby(['Node ID', 'date']).apply(lambda x: numba_calc_diff(x['Price'].values))
最小可复现示例
生成模拟数据
import pandas as pd import numpy as np # 生成100个节点、1年的小时级模拟数据 nodes = np.arange(1, 101) dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='H') data = pd.DataFrame({ 'Node ID': np.repeat(nodes, len(dates)//len(nodes)), 'Datetime': dates.tile(len(nodes)), 'Price': np.random.uniform(10, 100, size=len(nodes)*len(dates)) })
效果说明
在模拟数据集上,优化后的方案耗时仅为原方案的1/151/20,在1.51亿行的真实数据集上,预计总耗时可压缩至1015分钟。
内容的提问来源于stack exchange,提问作者kblackburn
相关产品推荐
相关产品推荐

