Pandas 搜索速度/性能/效率

Posted

技术标签:

【中文标题】Pandas 搜索速度/性能/效率【英文标题】:Pandas search speed/performance/efficiency 【发布时间】:2017-05-13 00:48:26 【问题描述】:
ID  outcome Source_doc
23145   A   ARR
23145   A   CRE
23145   B   ARR
23145   C   CRE
23456   B   ARR
23456   B   CRE

来自 ARR 的 ID #145 具有 [A,B] 结果。来自 CRE 的 ID #145 具有 [A,C] 结果。您可以在下面看到我会将 ID #145 放在“not_same_list”中。我的数据集包括 445,000 行。我执行的过程每 100 行需要 21 秒。所以这将需要7个多小时!

这个循环中最慢的部分是什么?

我执行 Pandas 搜索的效率最高吗?

iterrows() 会更快吗?

编辑:关于预期输出的要点。我实际上只是期待一个 ID 列表。如果 AAR_list 和 CRE_list 不相同,我想标记该 ID 并将其放入列表 (not_same_list)。所以我正在寻找 [145, 178, ..., 989, (任何结果与源文档不匹配的 ID)]

not_same_list = []
total_search_start_time = time.time()
tick = 0
for IDs in uniq_IDs['ID'].unique():
    #Isolate rows by their ID and source doc
    sco_ARR = uniq_IDs['outcome'][uniq_IDs['ID'] == IDs][uniq_IDs['Source_Doc'] == 'ARR']
    sco_CRE = uniq_IDs['outcome'][uniq_IDs['ID'] == IDs][uniq_IDs['Source_Doc'] == 'CRE']
    #Remove duplicates 
    ARR_list = set(sco_ARR.values.tolist())
    CRE_list = set(sco_CRE.values.tolist())

#Check to see if outcomes match between source docs
if ARR_list != CHRI_list:
    not_same_list.append(IDs)       

if str(tick)[-2:] == '00':
    print ('The last  rows have taken  seconds...'.format(tick,round(time.time()-total_search_start_time,2)))
    tick += 1 
else:
    tick += 1

print ('The last  rows have taken  seconds...'.format(tick,round(time.time()-total_search_start_time,2))) 
print (not_same_list)

如果有人可以为这个问题制作一个更好的表格,请这样做:

【问题讨论】:

我怀疑drop_duplicates 方法会有所帮助。 你能不能也放下预期的输出? 除了 Jack Maney 的建议之外,我认为 pandas 代码中的一般危险信号是使用 for 循环。将其组合为向量/矩阵运算通常会加快速度。 实际上,格式关闭了吗?在我看来,你在这里的 for 循环只是一遍又一遍地设置,而不是使用 ARR_listCRE_list。我同意 John Galt 的观点,您应该提供预期的输出,以便更清楚您想要做什么。 【参考方案1】:

我会尝试这样的事情

d1 = df.groupby(['ID', 'Source_doc']).outcome.apply(set).unstack()
print(d1)

Source_doc     ARR     CRE
ID                        
23145       B, A  A, C
23456          B     B

然后检查是否相等

d1.ARR == d1.CRE

ID
23145    False
23456     True
dtype: bool

您可以过滤d1的索引以获取not_equalID的列表

d1.index[d1.ARR != d1.CRE]

Int64Index([23145], dtype='int64', name='ID')

【讨论】:

【参考方案2】:

重写 for 循环的 pandas 惯用方法是:

(df.groupby(['ID', 'Source_doc'])['outcome'].apply(set)
   .groupby(level=0).nunique()[lambda x: x==2].index)

# Int64Index([23145], dtype='int64', name='ID')

你的 for 循环很慢的原因是因为你正在处理 unsorted 数据,也就是说你用ID子集你的数据帧,然后用Source_doc子集你去以矢量扫描方式多次通过数据帧(取决于您拥有多少唯一 ID 和 Source_doc);使用groupby()避免了这个问题,因为它通过组变量对数据帧进行排序,然后逐块处理;

要了解有关此理念的更多信息,请查看this answer。

【讨论】:

感谢您的澄清。我要试试这个并比较时间。 这实际上已经完成了,所以我头晕目眩。我只是在验证结果。从 7 小时缩短到 5 分钟真是太棒了。这有意义吗? 如果你有很多IDs,这是有道理的,ID 的数量决定了你的 for 循环必须遍历整个数据帧并将其子集的次数,这可能非常耗时消费。 太好了,看来要退房了。谢谢!

以上是关于Pandas 搜索速度/性能/效率的主要内容,如果未能解决你的问题,请参考以下文章

使用 pandas 解析大量日期 - 可扩展性 - 性能下降速度比线性快

为啥我的 Spark 运行速度比纯 Python 慢?性能比较

android--性能优化1--首屏优化&启动速度与执行效率检测

Python Pandas 遍历DataFrame的正确姿势 速度提升一万倍

Python Pandas 遍历DataFrame的正确姿势 速度提升一万倍

Python Pandas 遍历DataFrame的正确姿势 速度提升一万倍