Pandas按国家自定义时段条件分组求最小值的优化方案咨询
基于国家自定义时段的GroupBy最小值计算优化方案
需求:根据不同国家的自定义时段,对数据按scenario、country和对应时段分组,计算每组内value的最小值,并将结果映射回原数据的每一行。现有代码可正常运行,但需要更高效简洁的实现方案。
原始数据集
datetime country scenario value 2023-01-01 00:00:00 FR 1 1 2023-01-01 01:00:00 FR 1 2 2023-01-01 02:00:00 FR 1 3 2023-01-01 03:00:00 FR 1 4 2023-01-01 01:00:00 DE 1 1 2023-01-01 02:00:00 DE 1 2 2023-01-01 03:00:00 DE 1 3 2023-01-01 04:00:00 DE 1 4
自定义时段字典
countries = {'DE':2,'FR':4}
当前实现代码
df3l=[] for sc in scenarios: # iterate over countries df2l = [] for c in countries: # iterate over scenarios df2 = df[ (df['scenario']==sc) & (df['country']==c)] # select country and scenario # compute min over period per country df2['min over period']= pd.DataFrame(df.groupby(['scenario','country',pd.Grouper(key='datetime', freq=str(countries[c])+'H')]).transform('min')) df2l.append(df2) df2 = pd.concat(df2l,axis=0) df3l.append(df2) df = pd.concat(df3l,axis=0)
优化方案
方案1:向量化操作+分组Transform(最简洁高效)
核心思路:先为每行生成对应国家的时段分组标识,再通过一次分组+Transform完成最小值计算,彻底消除嵌套循环和重复数据拼接。
代码实现:
# 确保datetime列为datetime类型 df['datetime'] = pd.to_datetime(df['datetime']) # 生成时段分组键:根据国家对应的时段,将时间向下取整到时段起始点 df['period'] = df.apply(lambda row: row['datetime'].floor(f"{countries[row['country']]}H"), axis=1) # 计算时段内最小值并映射回原数据 df['min over period'] = df.groupby(['scenario', 'country', 'period'])['value'].transform('min') # 可选:删除临时的period列 df = df.drop('period', axis=1)
方案2:批量分组处理,提升大数据量性能
若数据集规模较大,逐行apply可能存在性能瓶颈,可改为按country分组批量生成时段标识:
df['datetime'] = pd.to_datetime(df['datetime']) # 按country分组,批量生成时段键 def get_period(group): freq = f"{countries[group.name]}H" return group['datetime'].floor(freq) df['period'] = df.groupby('country')['datetime'].transform(get_period) # 计算时段最小值 df['min over period'] = df.groupby(['scenario', 'country', 'period'])['value'].transform('min') df = df.drop('period', axis=1)
方案3:针对性修复原代码的冗余问题
原代码存在重复分组全量数据、多次筛选拼接的问题,可先完成分组计算再合并回原数据:
df['datetime'] = pd.to_datetime(df['datetime']) # 按scenario+country分组后,分别计算对应时段的最小值 result = df.groupby(['scenario', 'country']).apply( lambda g: g.groupby(pd.Grouper(key='datetime', freq=f"{countries[g.name[1]]}H"))['value'].min() ).reset_index(name='min over period') # 将结果合并回原数据 df = df.merge(result, on=['scenario', 'country', 'datetime'], how='left')
优化效果说明
- 消除嵌套循环和多次
concat,代码量减少60%以上 - 避免重复分组全量数据,计算效率随数据量增大提升更明显
- 逻辑更清晰,可读性和可维护性更强
内容的提问来源于stack exchange,提问作者Peslier53
相关产品推荐
相关产品推荐

