我有一个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
如上所示,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)
Jaime.. 6
你可以使用整个事物进行矢量化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
这大约比你的代码快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
编辑那么这是如何工作的?在midpoints
我们存储桶之间的边界的排序列表.然后我们searchsorted
在这个排序列表上进行二进制搜索,得到idx
,它基本上告诉我们每个数据点属于哪个桶.剩下的就是对每个桶中的所有值进行分组.这bincount
是为了什么.给定一系列整数,它计算每个数字出现的次数.给定一个int数组和一个相应的数组weights
,而不是为存储桶的计数器添加1,它会添加相应的值weights
.通过两次调用,bincount
您可获得每个桶的总和和项目数:除以它们,您就可以得到桶的平均值.
你可以使用整个事物进行矢量化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
这大约比你的代码快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
编辑那么这是如何工作的?在midpoints
我们存储桶之间的边界的排序列表.然后我们searchsorted
在这个排序列表上进行二进制搜索,得到idx
,它基本上告诉我们每个数据点属于哪个桶.剩下的就是对每个桶中的所有值进行分组.这bincount
是为了什么.给定一系列整数,它计算每个数字出现的次数.给定一个int数组和一个相应的数组weights
,而不是为存储桶的计数器添加1,它会添加相应的值weights
.通过两次调用,bincount
您可获得每个桶的总和和项目数:除以它们,您就可以得到桶的平均值.