我有一个名为products`的50k字符串数组和一个大约2200万行的数据框,称为all
我想迭代数组,然后选择包含数组值的数据帧的相应子集:
for i in products:
all.query('id == i')
每个查询需要大约1.5秒进行计算,在我的数组中有50k值,这将花费我大约20个小时。
你知道更快的计算方法吗?
答案 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
的值,则速度要快得多(正如我所做的那样,是按products
对all_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