使用标签集合过滤 Pandas DataFrame。

7

假设我有一个包含标签列表或集合的DataFrame,我想根据某个标签是否是该行的一部分来过滤DataFrame,使用pandas实现最常用的方法是什么?

import pandas as pd

df = pd.DataFrame({
    'amount': [15, 20, 40],
    'tags': [["Food", "Eating Out"], ["Food", "Groceries"], ["Clothes"]],
    'description': ["Garfunkel's", "Tesco", "Hollister"]
})

我有一段代码可以运行,但是写起来非常笨拙:

criterion = lambda row: 'Food' in row['tags']
df[df.apply(criterion, axis=1)]

结果应该是:

结果


2
pandas中,单个单元格中具有多个值并不是特别惯用的方式-我自己有时会这样做,但它使得使用典型的pandas习语变得非常困难。考虑到你目前的解决方案看起来相当不错,我不确定你能得到多少更好的解决方案。 - Marius
这是 Kaggle 的购物比赛之一吗? - smci
1
实际上,您可以将字符串转换为“分类变量”,无需每次进行字符串匹配(假设已知完整的标签集)。 - smci
@smci 我没有具体说明,因为我可以很容易地更改它。集合显然更适合这种情况,但如果有仅适用于列表的东西,那也没关系,因为N非常低。 - passy
1
将分类/布尔列分开比包含集合或列表的列更好,否则将会混乱向量化。自己尝试并证明它。 - smci
显示剩余2条评论
3个回答

5
您可以将lambda应用于仅相关列,而不是整个行:
df[df['tags'].map(lambda tags: 'Food' in tags)]

1
我曾经写过这样的代码,每次想要进行逻辑索引时,每一行都要搜索列表,非常慢。而且,字符串集/列表在内存方面也更糟糕。建议避免使用。 - smci
谢谢,这似乎是最不侵入性的更改,使其工作,尽管@smci绝对正确,我应该以不同的方式切片我的数据以更有效地查询它。 - passy

2
为了效率起见,每次想要进行逻辑索引时搜索字符串标签列表会很糟糕。因此:
扩展df['tags']为多个列。
要么:
如果最多有T个标签,添加T个布尔列 df['tFood'] = [ 'Food' in tt for tt in df['tags'] ]
如果每个项目最多只能有N个标签,而且N很小,则添加字符串列tag1、tag2...tagN。实际上,您可以将字符串转换为Categoricals,无需每次进行字符串匹配。
现在,您可以快速进行逻辑索引:
df.loc[df['tFood']==True,]
# amount  description                tags tFood
# 0      15  Garfunkel's  [Food, Eating Out]  True
# 1      20        Tesco   [Food, Groceries]  True

1
尝试一下这个。它不是完美的解决方案,但它可以工作。
print df[df['tags'].astype(str).str.contains('Food')]

您甚至可以在contains()中使用正则表达式来匹配多个模式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接