加快熊猫过滤

mar*_*ion 3 python optimization performance numpy pandas

我有一个37456153行x 3列Pandas数据帧由以下列组成:[Timestamp, Span, Elevation].每个Timestamp值都有大约62000行SpanElevation数据,看起来像(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数据不是等间距,我实际上需要它.所以我想出了以下代码将其转换为等间距格式.我知道我想分析的地点startend位置.然后我将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)

Jai*_*ime 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  
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您可获得每个桶的总和和项目数:除以它们,您就可以得到桶的平均值.