通过Pandas Dataframe迭代和索引的最快方法

时间:2017-06-25 23:14:00

标签: python arrays pandas numpy indexing

我有一个名为products`的50k字符串数组和一个大约2200万行的数据框,称为all

我想迭代数组,然后选择包含数组值的数据帧的相应子集:

for i in products:
 all.query('id == i')

每个查询需要大约1.5秒进行计算,在我的数组中有50k值,这将花费我大约20个小时。

你知道更快的计算方法吗?

2 个答案:

答案 0 :(得分:1)

如果要在产品列表中选择带有ID的所有行,这应该比for循环快得多:

[1,2,2,3,4,4,3]

答案 1 :(得分:1)

为了测试这个,我生成了我自己的这些数据帧版本(不确定统计属性是否相同,但时间结果看起来与你得到的相似):

import pandas as pd
import numpy as np

import uuid

products = pd.Series([uuid.uuid4().hex for i in range(50000)])
all_products = pd.DataFrame(np.random.choice(products,
                                             size=(int(22e6),), replace=True),
                            columns=['id'])

二进制搜索方法

执行此操作的一种方法是对all数据框进行排序,并使用searchsorted以二进制搜索方式执行查询 - 这对于22M行({{1} }),但使查找更快(n log n)。这可能是实现明确规定目标的最快方式:

log n

所以看起来您可以期望在大约12秒内对行进行排序,然后在另一个〜20秒内查询50,000行,总共32秒。在我的示例中,我实际上并没有保存结果,但我假设一旦你将索引放入import timeit s = timeit.default_timer() all_products_sorted = all_products.sort_values(by='id') e = timeit.default_timer() print('Time to sort: {:0.5f}'.format((e - s) / N)) # Time to sort: 11.27207 N = 1000 s = timeit.default_timer() for _, i in zip(range(N), products): start = all_products_sorted['id'].searchsorted(i, side='left') end = all_products_sorted['id'].searchsorted(i, side='right') x = all_products_sorted['id'].iloc[start[0]:end[0]] e = timeit.default_timer() print('{:0.5f}s per query'.format((e - s) / N)) # 0.00038s per query 数据帧(不要称之为all_products,因为那是一个Python内置!),您可以根据需要存储它们。

分组方法

另一种方法(根据我的测试),如果all 完全 来自all_products的值,则速度要快得多(正如我所做的那样,是按productsall_products进行分组,并将结果转储到字典中(或者你想用它做什么):

id

请注意,在这种情况下,它显然比s = timeit.default_timer() x_dict = {k: v for k, v in all_products.groupby('id')} e = timeit.default_timer() print('{:0.5f}s per query'.format((e - s) / len(products))) # 0.00032s per query 方法快(虽然不是很大),不需要首先对输入进行排序。

请注意,如果您真正想要做的是转换这些行或以某种方式修改它们,在这种情况下searchsorted绝对是要走的路 - 甚至不打算转储到字典,而是看到split-apply-combine page以这种方式处理Dataframes的策略。

天真的方法

为了进行比较,以下是两种涉及完整搜索的方法:

groupby