如何高效计算DataFrame列内超大数组的逐值差分优化运行效率
问题描述
当前使用的DataFrame结构如下:
index Rod_1 label 0 [[1.94559799] [1.94498416] [1.94618273] ... [1.8941952 ] [1.89461277] [1.89435902]] F0 1 [[1.94129488] [1.94268905] [1.94327065] ... [1.93593512] [1.93689935] [1.93802091]] F0 2 [[1.94034818] [1.93996006] [1.93940095] ... [1.92700882] [1.92514855] [1.92449449]] F0 3 [[1.95784532] [1.96333782] [1.96036528] ... [1.94958261] [1.95199495] [1.95308231]] F2
Rod_1列每个单元格存储长度为1200万的数组,需求是计算数组内相邻值的差值,实现数据去季节性处理,提升后续模型效果。
当前采用双层Python循环的实现代码如下:
interval = 1 for j in range(0, len(df_all['Rod_1'])): for i in range(1, len(df_all['Rod_1'][0])): df_all['Rod_1'][j][i - interval] = df_all['Rod_1'][j][i] - df_all['Rod_1'][j][i - interval]
数据集共45行,该代码在笔记本上运行需要20分钟才能完成,需要更高效的实现方案。
性能瓶颈说明
当前代码速度慢的核心原因是使用纯Python双层循环逐元素运算:Python解释器本身的循环调度、索引寻址开销极高,完全没有用到数值计算库的底层优化,处理总计5.4亿个元素(45行*1200万元素/行)自然耗时极长。
优化实现方案
直接使用numpy内置的np.diff函数做向量化计算,底层为C实现的优化逻辑,比纯Python循环快几十到上百倍,普通笔记本处理全量数据通常仅需十几秒到几十秒。
基础优化版本(适配pandas常规操作逻辑)
首先确认Rod_1列的存储格式,如果是Python原生列表先统一转为numpy数组,再通过apply批量计算差分:import numpy as np # 原生列表转numpy数组,仅需运行一次,已经是numpy数组可跳过 df_all['Rod_1'] = df_all['Rod_1'].apply(np.array) interval = 1 # 原始数组是(12000000,1)形状的二维数组,需要指定axis=0按序列方向计算差分 # 如果需要直接覆盖原列,把赋值列名改为'Rod_1'即可 df_all['Rod_1_diff'] = df_all['Rod_1'].apply(lambda x: np.diff(x, n=interval, axis=0))差分后的数组长度会比原数组少
interval个值,属于正常情况,因为序列首位没有前序元素可以做差。极致提速版本(内存充足时使用)
可以把所有数组合并为二维numpy矩阵一次性计算,跳过pandas的行级遍历开销,速度还能提升30%左右:import numpy as np # 合并所有行的数组统一做差分 all_arr = np.concatenate(df_all['Rod_1'].values, axis=1).T all_diff = np.diff(all_arr, n=1, axis=1) # 计算结果拆分后赋值回DataFrame df_all['Rod_1'] = list(np.expand_dims(all_diff, axis=2))额外小优化
如果后续模型不需要保留二维数组结构,可以提前把形状为(长度,1)的数组squeeze为一维数组,进一步降低计算和内存开销:df_all['Rod_1_diff'] = df_all['Rod_1'].apply(lambda x: np.diff(x.squeeze(), n=interval))
内容的提问来源于stack exchange,提问作者Ashkan Lotfipoor
相关产品推荐
相关产品推荐

