mar*_*ion 3 python optimization performance numpy pandas
我有一个37456153行x 3列Pandas数据帧由以下列组成:[Timestamp, Span, Elevation]
.每个Timestamp
值都有大约62000行Span
和Elevation
数据,看起来像(Timestamp = 17210
作为示例过滤时):
Timestamp Span Elevation
94614 17210 -0.019766 36.571
94615 17210 -0.019656 36.453
94616 17210 -0.019447 36.506
94617 17210 -0.018810 36.507
94618 17210 -0.017883 36.502
... ... ... ...
157188 17210 91.004000 33.493
157189 17210 91.005000 33.501
157190 17210 91.010000 33.497
157191 17210 91.012000 33.500
157192 17210 91.013000 33.503
Run Code Online (Sandbox Code Playgroud)
如上所示,Span
数据不是等间距,我实际上需要它.所以我想出了以下代码将其转换为等间距格式.我知道我想分析的地点start
和end
位置.然后我将delta
参数定义为我的增量.我创建了一个名为numpy的数组mesh
,它保存了Span
我希望最终得到的等间距数据.最后,我决定对给定TimeStamp
的代码(代码中的17300)进行数据帧迭代,以测试它的工作速度.代码中的for循环计算每个增量Elevation
的+/- 0.5delta
范围的平均值.
我的问题是:它需要603毫秒,通过数据帧过滤和计算平均Elevation
在一个单一的迭代.对于给定的参数,我必须经历9101次迭代,从而导致该循环结束的大约1.5小时的计算时间.此外,这是一个单一的Timestamp
价值,我有600个(900小时做所有?!).
有什么方法可以加快这个循环吗?非常感谢任何输入!
# MESH GENERATION
start = 0
end = 91
delta = 0.01
mesh = np.linspace(start,end, num=(end/delta + 1))
elevation_list =[]
#Loop below will take forever to run, any idea about how to optimize it?!
for current_loc in mesh:
average_elevation = np.average(df[(df.Timestamp == 17300) &
(df.Span > current_loc - delta/2) &
(df.Span < current_loc + delta/2)].Span)
elevation_list.append(average_elevation)
Run Code Online (Sandbox Code Playgroud)
你可以使用整个事物进行矢量化np.searchsorted
.我不是一个大熊猫用户,但这样的东西应该工作,并在我的系统上运行得相当快.使用chrisb的虚拟数据:
In [8]: %%timeit
...: mesh = np.linspace(start, end, num=(end/delta + 1))
...: midpoints = (mesh[:-1] + mesh[1:]) / 2
...: idx = np.searchsorted(midpoints, df.Span)
...: averages = np.bincount(idx, weights=df.Elevation, minlength=len(mesh))
...: averages /= np.bincount(idx, minlength=len(mesh))
...:
100 loops, best of 3: 5.62 ms per loop
Run Code Online (Sandbox Code Playgroud)
这大约比你的代码快3500倍:
In [12]: %%timeit
...: mesh = np.linspace(start, end, num=(end/delta + 1))
...: elevation_list =[]
...: for current_loc in mesh:
...: average_elevation = np.average(df[(df.Span > current_loc - delta/2) &
...: (df.Span < current_loc + delta/2)].Span)
...: elevation_list.append(average_elevation)
...:
1 loops, best of 3: 19.1 s per loop
Run Code Online (Sandbox Code Playgroud)
编辑那么这是如何工作的?在midpoints
我们存储桶之间的边界的排序列表.然后我们searchsorted
在这个排序列表上进行二进制搜索,得到idx
,它基本上告诉我们每个数据点属于哪个桶.剩下的就是对每个桶中的所有值进行分组.这bincount
是为了什么.给定一系列整数,它计算每个数字出现的次数.给定一个int数组和一个相应的数组weights
,而不是为存储桶的计数器添加1,它会添加相应的值weights
.通过两次调用,bincount
您可获得每个桶的总和和项目数:除以它们,您就可以得到桶的平均值.