[英]Fastest way to iterate and index through Pandas Dataframe
我有一个由5万个字符串组成的数组,称为product`-大约有2200万行的数据框,称为all
我想遍历数组,然后选择包含数组值的数据框的相应子集:
for i in products:
all.query('id == i')
每个查询大约需要1.5秒的时间来计算,而我数组中的50k值将花费我大约20个小时。
您知道更快的方法吗?
如果要在产品列表中选择所有具有ID的行,这应该比for循环快得多:
import numpy as np
df[np.in1d(df.id,products)]
为了测试这一点,我生成了自己的这些数据框版本(不确定统计属性是否相同,但是计时结果似乎与您得到的相似):
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
将查询作为二进制搜索进行-一次性耗费大量时间对2200万行进行排序( n log n
),但使查找速度更快( log n
) 。 这可能是实现您明确声明的目标的最快方法:
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
因此,您似乎可以期望在12秒左右的时间内对行进行排序,然后再在20秒左右的时间内查询50,000行,总共需要32秒。 在我的示例中,我实际上并没有保存结果,但是我假设一旦将索引包含在all_products
数据all_products
(不要all
调用,因为那是Python内置的!),就可以根据需要存储它们了。
分组方式
另一种方法(根据我的测试),如果all_products
全部或大部分由products
值组成(如我的所做的那样),则速度要快得多(按我的方法),该方法是按id
对all_products
进行分组,然后将结果转储到字典中(或您要执行的任何操作)用它):
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
方法要快(尽管不算很多), 并且不需要首先对输入进行排序。
请注意,如果您实际要做的是转换这些行或以某种方式对其进行修改,在这种情况下, groupby
绝对是groupby
的方法-甚至不必费心将其转储到字典中,而是请参见split-apply-combine页面有关以这种方式使用数据框的策略。
天真的方法
为了进行比较,以下是涉及完全搜索的两种方法:
import timeit
N = 5
s = timeit.default_timer()
for _, i in zip(range(N), products):
x = all_products.query('id == "{}"'.format(i))
e = timeit.default_timer()
print('{:0.5f}s per query'.format((e - s) / N)) # 1.60075s per query
s = timeit.default_timer()
for _, i in zip(range(N), products):
x = all_products[all_products['id'] == i]
e = timeit.default_timer()
print('{:0.5f}s per query'.format((e - s) / N)) # 3.00135s per query
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.