加速数据帧 .loc()

Posted

技术标签:

【中文标题】加速数据帧 .loc()【英文标题】:Speed up dataframe .loc() 【发布时间】:2017-02-16 12:39:48 【问题描述】:

我有一个大约 400k IP 的列表(存储在 pandas DataFrame df_IP 中),可以使用 maxming geoIP 数据库进行地理定位。我使用 City 版本,并检索城市、纬度、经度和县代码(法国的部门),因为有些城市的名称相同,但在不同的地方。

这是我的工作代码:

import geoip2.database
import pandas as pd

reader = geoip2.database.Reader('path/to/GeoLite2-City.mmdb')
results = pd.DataFrame(columns=('IP',
                                'city',
                                'latitude',
                                'longitude',
                                'dept_code'))

for i, IP in enumerate(df_IP["IP"]):
    try :
        response = reader.city(IP)
        results.loc[i] = [IP,response.city.name,response.location.latitude,response.location.longitude,response.subdivisions.most_specific.iso_code]
    except Exception as e:
        print ("error with line , IP : ").format(i,df_IP["IP"][i],e )

它运行良好,但在每个循环中它变得越来越慢。如果我在 1000 第一个 IP 上计时,我需要 4.7s,所以整个 400k 应该需要大约 30 分钟,但它运行了将近 4 小时。

IMO 唯一会随着时间的推移而变慢的是填充数据框 results:我有什么不使用 .loc 并且可以更快的替代方案?最后我仍然需要相同的数据框。

我也有兴趣解释为什么 loc 在大型数据帧上如此缓慢。

【问题讨论】:

您是否考虑过使用 pandas 的迭代器之一(例如 iterrows())来遍历您的行并使用 apply 和您的阅读器函数来创建一个新列,其中包含您所有的字符串地理数据?然后,您可以拆分字符串以为所有地理数据创建单独的列。不确定这是否会更快,但在迭代数据帧时,通常最好使用iterrows() 之类的东西。 我过去也遇到过类似的问题,在 for 循环中使用 loc 非常慢。我发现我可以通过将新列的数据生成为单独的列表来规避这个问题,然后以这种形式重新分配它。这需要更多的代码行并且有点丑陋,但比loc 的性能要好得多。如果您可以应用它,可能值得考虑。 @oliversm 你能详细说明一下吗?我真的不明白你的伎俩。 @Khris,不,我从未使用过 iterrows,我会尝试 IP 是唯一的吗? 【参考方案1】:

我遇到了类似的情况,因为 loc 导致运行时为我炸毁。在摆弄了很多之后,我找到了一个超级快速的简单解决方案。 使用 set_value 而不是 loc。

示例代码如下所示:您可以针对您的用例对其进行调整。说你的数据框是这样的

Index  'A'  'B' 'Label'
23      0    1    Y
45      3    2    N

self.data.set_value(45,'Label,'NA')

这会将第二行的“标签”列的值设置为 NA。

更多关于 set_value 的内容可以从下面的链接中阅读:

http://pandas.pydata.org/pandas-docs/version/0.17/generated/pandas.DataFrame.set_value.html

【讨论】:

【参考方案2】:

我遇到了同样的问题,正如@oliversm 建议的那样,我创建了一个列表,然后将其添加到原始数据集中。 下面是代码的样子:

....

results_list=[]

for i, IP in enumerate(df_IP["IP"]):
    try :
        response = reader.city(IP)
     results_list.append( response.city.name,response.location.latitude,response.location.longitude,response.subdivisions.most_specific.iso_code)
    except Exception as e:
        print ("error with line , IP : ").format(i,df_IP["IP"][i],e )

results_array=np.asarray(results_list) #list to array to add to the dataframe as a new column

results['results_column']=pd.Series(results_array,index=results.index)

【讨论】:

以上是关于加速数据帧 .loc()的主要内容,如果未能解决你的问题,请参考以下文章

Pandas:加速遍历两个数据帧

在数据块上将严重分区的数据帧加速到 s3

加速R应用于数据帧

为具有大量字符串的数据帧加速 PyArrow Parquet 到 Pandas

Python:Pandas:加速应用函数

使用 Opencv 加速从摄像头读取视频帧