2017-09-06 39 views
2
类别

滤波大熊猫数据帧的方法我有100万行和分类列非常大的数据帧。我想知道是否有比使用.isin()方法或.join()方法here更快地选择按类别排列的行。最快通过

鉴于该数据已经分类,我认为这应该是非常快的,选择类别,但几个测试我跑了令人失望的表现。我发现的唯一的其他解决方案是从here,但解决方案似乎不适用于熊猫0.20.2。

下面是一个例子的数据集。

import pandas as pd 
import random 
import string 
df = pd.DataFrame({'categories': [random.choice(string.ascii_letters) 
            for _ in range(1000000)]*100, 
        'values': [random.choice([0,1]) 
           for _ in range(1000000)]*100}) 
df['categories'] = df['categories'].astype('category') 

测试与.isin()

%timeit df[df['categories'].isin(list(string.ascii_lowercase))] 
44 s ± 894 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 

使用.join()

%timeit df.set_index('categories').join(
    pd.Series(index=list(string.ascii_lowercase), name='temp'), 
    how='inner').rename_axis('categories').reset_index().drop('temp', 1) 
24.7 s ± 1.69 s per loop (mean ± std. dev. of 7 runs, 1 loop each) 
+0

只是一个供参考,而定时为*高*此处的随机种子depedent。你应该修复你的问题。 – Jeff

+0

经过几次更多的测试后,每种方法使用相同的随机种子并使用我的真实数据进行测试,我发现'map'方法始终更快,所以我将其标记为解决方案。 – kayoz

回答

2

这里有一个类似的,但不同的方法,直接值进行比较,而不是使用isin

基本map /λ比较:

%timeit df[df['categories'].map(lambda x: x in string.ascii_lowercase)] 
> 1 loop, best of 3: 12.3 s per loop 

使用isin

%timeit df[df['categories'].isin(list(string.ascii_lowercase))] 
> 1 loop, best of 3: 55.1 s per loop 

版本:PY 3.5.1/5.1.0的IPython /大熊猫0.20.3

背景:我注意到one of the SO posts您链接到一个评论者提到,isin需要在执行过程中创建set(),所以跳过这一步,做一个基本的列表查找似乎是加速这里。

Disclamer:不是我经常处理的尺度类型,所以在那里可能会有更快的选项。

编辑:在意见请求从JohnGalt额外的细节:

df.shape 
> (100000000, 2) 
df.dtypes 
> categories category 
values   int64 
dtype: object 

要创建示例数据,我复制/粘贴从最初的问题的样品DF。运行于2015年初的MBP模型。

+0

你可以添加'df.shape'和'df.dtypes'这些时间完成? – Zero

+0

@JohnGalt我明白你为什么问(很快),我刚刚重新运行并得到不同的结果。这两次运行之间的唯一区别是我刚刚将我的开发熊猫从0.19升级到0.20的当前点数版本。我已经用新的时间更新了答案,但会用较老的python再试一次,看看更快的结果是否会回来。 –

+0

这似乎表现更好。使用问题中的相同示例数据,我得到以下性能: 每循环8.7 s±1.23 s(平均值±标准差7次运行,每次循环1次)' 我只是想知道是否可以做任何事情用类别的“猫”方法。例如,这是相当快速的:'df ['categories']。cat.set_categories(list(string.ascii_lowercase))' 但在结果上使用'.loc'要慢得多。 – kayoz

1

这里是1/10样品运行。 Groupby自然地利用了分类。目前的df.loc[list_of_items]对于分类的实施是不是很有效,但可以利用这种引擎盖下。

In [68]: %timeit -n 3 -r 1 df[df['categories'].isin(list(string.ascii_lowercase))] 
3.67 s +- 0 ns per loop (mean +- std. dev. of 1 run, 3 loops each) 

In [69]: s = set(list(string.ascii_lowercase)) 

In [70]: %timeit -n 3 -r 1 df.groupby('categories', as_index=False).filter(lambda x: x.name in s) 
1.09 s +- 0 ns per loop (mean +- std. dev. of 1 run, 3 loops each) 

In [71]: result2 = df.groupby('categories', as_index=False).filter(lambda x: x.name in s) 

In [72]: result1 = df[df['categories'].isin(list(string.ascii_lowercase))] 
result1.equals 

In [73]: result1.equals(result2) 
Out[73]: True 
+0

谢谢你的答案杰夫。我发现菲尔的解决方案是用map来比groupby快。我想知道是否可以使用'df ['categories'] .cat.set_categories()'作为掩码?由于此操作似乎非常快速。 – kayoz