带DatetimeIndex的pandas重采样如何不使用apply取组内最大值对应行
问题背景
有带DatetimeIndex的pandas.DataFrame,数据采样间隔为30分钟(也支持其他间隔),需要按小时对数据进行重采样,对每个时间分组提取指定列取值最高的对应行。
示例输入数据
WindDir WindSpeed Temperature CloudHgt Date 2020-01-01 00:20:00 150.0 3.6 5.0 213.0 2020-01-01 00:50:00 150.0 3.1 5.0 213.0 2020-01-01 01:20:00 130.0 4.1 5.0 183.0 2020-01-01 01:50:00 130.0 3.6 5.0 183.0 2020-01-01 02:20:00 130.0 3.1 4.0 244.0 2020-01-01 02:50:00 140.0 3.6 4.0 366.0 2020-01-01 03:20:00 130.0 2.6 3.0 99999.0 2020-01-01 03:50:00 160.0 2.6 3.0 91.0 2020-01-01 04:20:00 170.0 2.6 3.0 61.0 2020-01-01 04:50:00 180.0 2.6 3.0 30.0 2020-01-01 05:20:00 150.0 1.5 3.0 183.0 2020-01-01 05:50:00 190.0 2.1 3.0 30.0 2020-01-01 06:20:00 190.0 2.1 3.0 122.0 2020-01-01 06:50:00 220.0 1.5 3.0 152.0 2020-01-01 07:20:00 230.0 2.1 3.0 213.0 2020-01-01 07:50:00 230.0 1.5 3.0 244.0 2020-01-01 08:20:00 999.0 1.0 3.0 335.0 2020-01-01 08:50:00 999.0 0.5 3.0 335.0 2020-01-01 09:20:00 120.0 2.1 3.0 335.0
期望输出结果
WindDir WindSpeed Temperature CloudHgt Date 2020-01-01 00:00:00 150.0 3.6 5.0 213.0 2020-01-01 01:00:00 130.0 4.1 5.0 183.0 2020-01-01 02:00:00 130.0 3.6 5.0 183.0 2020-01-01 03:00:00 140.0 3.6 4.0 366.0 2020-01-01 04:00:00 160.0 2.6 3.0 91.0 2020-01-01 05:00:00 180.0 2.6 3.0 30.0 2020-01-01 06:00:00 190.0 2.1 3.0 30.0 2020-01-01 07:00:00 230.0 2.1 3.0 213.0 2020-01-01 08:00:00 230.0 1.5 3.0 244.0 2020-01-01 09:00:00 120.0 2.1 3.0 335.0
现有方案的问题
目前可运行的方案使用apply(lambda group: group.nlargest(1, columns=column)),但大数据量下运行速度极慢,原代码如下:
# define grouper grouper = pd.Grouper(freq='1H', offset='30min') # aggregate data (except wind dir) resampled = (data .groupby(grouper) .apply(lambda group: group.nlargest(1, columns=column)) .reset_index(level=-1, drop=True) ).shift(30,'min')
需要不使用apply函数的更优方案,提升大数据量下的运行效率。
优化解决方案
推荐使用矢量化操作的idxmax方法,全程无自定义函数循环开销,运行效率远高于apply方案,百万行级数据下性能可提升数十倍:
import pandas as pd # 生成分组键 grouper = pd.Grouper(freq='1H', offset='30min') # 获取每个分组指定列最大值对应的原始索引 max_row_idx = data.groupby(grouper)[column].idxmax() # 按索引取出对应行,调整时间标签为整点 resampled = data.loc[max_row_idx].set_index(max_row_idx.index).shift(30, 'min')
如果存在同一分组多个行的指定列值相同的场景,需要控制优先级,可使用排序去重法:
resampled = (data # 按目标列降序排序,可加其他列作为辅助排序条件 .sort_values(column, ascending=False) .groupby(pd.Grouper(freq='1H', offset='30min')) # 取每个分组第一条数据 .head(1) # 恢复时间顺序 .sort_index() .shift(30, 'min') )
内容的提问来源于stack exchange,提问作者Luca
相关产品推荐
相关产品推荐

