快速熊猫过滤

red*_*bia 4 python pandas

如果名称列条目在给定列表中有一个项目,我想过滤一个pandas数据帧.

这里我们有一个DataFrame

x = DataFrame(
    [['sam', 328], ['ruby', 3213], ['jon', 121]], 
    columns=['name', 'score'])
Run Code Online (Sandbox Code Playgroud)

现在假设我们有一个列表,['sam', 'ruby']我们想要查找名称在列表中的所有行,然后对得分求和.

我的解决方案如下:

total = 0
names = ['sam', 'ruby']
for name in names:
     identified = x[x['name'] == name]
     total = total + sum(identified['score'])
Run Code Online (Sandbox Code Playgroud)

但是,当数据帧变得非常大,并且名称列表也变得非常大时,一切都非常慢.

还有更快的选择吗?

谢谢

unu*_*tbu 13

尝试使用ISIN(感谢DSM的建议locix这里):

In [78]: x = pd.DataFrame([['sam',328],['ruby',3213],['jon',121]], columns = ['name', 'score'])

In [79]: names = ['sam', 'ruby']

In [80]: x['name'].isin(names)
Out[80]: 
0     True
1     True
2    False
Name: name, dtype: bool

In [81]: x.loc[x['name'].isin(names), 'score'].sum()
Out[81]: 3541
Run Code Online (Sandbox Code Playgroud)

CT朱建议使用np.in1d以下更快的替代方案:

In [105]: y = pd.concat([x]*1000)
In [109]: %timeit y.loc[y['name'].isin(names), 'score'].sum()
1000 loops, best of 3: 413 µs per loop

In [110]: %timeit y.loc[np.in1d(y['name'], names), 'score'].sum()
1000 loops, best of 3: 335 µs per loop
Run Code Online (Sandbox Code Playgroud)

  • @CTZhu:试试`x.ix[np.in1d(x['name'], names), 'score'].sum()`。它比在我的机器上使用 `isin` 更快。我认为区别是因为 `x[np.in1d(x['name'], ['sam', 'ruby'])]` 包括 `name` 列,并且对名称求和可能会触发异常。处理异常是缓慢的。 (2认同)

Dhw*_*ade 9

如果我需要在一个字段上进行搜索,我注意到如果我将 DataFrame的索引更改为搜索字段会非常有帮助。对于我的搜索和查找要求之一,我的性能提高了大约500%

因此,在您的情况下,以下内容可用于按名称搜索和过滤。

df = pd.DataFrame([['sam', 328], ['ruby', 3213], ['jon', 121]], 
                 columns=['name', 'score'])
names = ['sam', 'ruby']

df_searchable = df.set_index('name')

df_searchable[df_searchable.index.isin(names)]
Run Code Online (Sandbox Code Playgroud)


rgr*_*opf 5

如果您的数据重复很多值,请尝试对该列使用“分类”数据类型,然后应用布尔过滤。比使用索引灵活得多,至少在我的情况下,速度要快得多。

data = pd.read_csv('data.csv', dtype={'name':'category'})
data[(data.name=='sam')&(data.score>1)]
Run Code Online (Sandbox Code Playgroud)

或者

names=['sam','ruby']    
data[data.name.isin(names)]
Run Code Online (Sandbox Code Playgroud)

对于我在 Pandas 1.2 中使用的约 1500 万行、约 20 万个唯一术语数据集,%timeit结果是:

  • 对象列上的布尔过滤器:608ms
  • 与索引相同的对象列上的 .loc 过滤器:281ms
  • 与“分类”类型相同的对象列上的布尔过滤器:16ms

从那里,添加 .sum() 或您正在寻找的任何聚合函数。

  • 将重复的字符串值转换为分类值(事实上,字符串列实际上是一个类别),将 33 分钟的过程减少到 1.30 分钟!谢谢,简单但有效。 (4认同)
  • 哇,过滤能力提高了 10 倍! (2认同)