【问题标题】:How to test which cell in a pandas dataframe string column contains a substring of a given reference string?如何测试熊猫数据框字符串列中的哪个单元格包含给定参考字符串的子字符串?
【发布时间】:2018-05-28 04:38:00
【问题描述】:

我正在处理一个看起来像这样的熊猫数据框:

0 Item         Category
1 Hammer       A
2 Car          A
3 Cardiologist B
4 Park         A
5 Parkway      A
6 CarparkCar   A

我需要找到Item 中包含特定字母序列的所有单元格,这些字母定义为我的参考词的子字符串。我对包含参考词中没有的其他字母的单元格不感兴趣。

reference_word = Carpark

期望的输出:

0 Item         Category   Contains_substring_of_reference_word
1 Hammer       A          FALSE
2 Car          A          TRUE
3 Cardiologist B          FALSE
4 Park         A          TRUE
5 Parkway      A          FALSE
6 CarparkCar   A          TRUE

如何检查 pandas 数据框列的哪个单元格包含给定单词/字符串的子字符串?

【问题讨论】:

  • 使用 apply 和 indexof 方法来做到这一点
  • 请问是否可以更具体一些(即包含链接或一些代码)
  • @sudonym 是的,这是可能的。看看我的回答。请记住,无论使用什么语言或方法,集合操作(​​您要查找的内容)通常都很慢。

标签: python string pandas substring


【解决方案1】:

您可以使用推导式创建集合并使用<= 表示子集。

sets = np.array([set(x.lower()) for x in df.Item.values.tolist()])
df.assign(Bool=sets <= set('carpark'))

           Item Category   Bool
0                              
1        Hammer        A  False
2           Car        A   True
3  Cardiologist        B  False
4          Park        A   True
5       Parkway        A  False
6    CarparkCar        A   True

【讨论】:

  • 我删除了分配并对其进行了测试。这给出了1 loop, best of 3: 555 ms per loop。太棒了!
【解决方案2】:

选项 1
一种简单的方法是使用apply + set.issubset -

v = df.Item.str.lower().apply(lambda x: set(x).issubset('carpark'))
v

0    False
1     True
2    False
3     True
4    False
5     True
Name: Item, dtype: bool

将结果分配回去 -

df['Contains_substring_of_reference_word'] = v
df

           Item Category  Contains_substring_of_reference_word
0        Hammer        A                                 False
1           Car        A                                  True
2  Cardiologist        B                                 False
3          Park        A                                  True
4       Parkway        A                                 False
5    CarparkCar        A                                  True

选项 2
使用set.difference 操作的另一种解决方案 -

(df.Item.str.lower().apply(set) - set('carpark')).str.len() == 0

0    False
1     True
2    False
3     True
4    False
5     True
Name: Item, dtype: bool

选项 3
使用np.vectorize 添加另一个选项,这应该会更快。

c = set('carpark')
def foo(x):
     return c.issuperset(x.lower())

v = np.vectorize(foo)

v(df.Item)
array([False,  True, False,  True, False,  True], dtype=bool)

时间

df = pd.concat([df] * 100000, ignore_index=True)  

%timeit df.Item.str.lower().apply(lambda x: set(x).issubset('carpark'))
1 loop, best of 3: 927 ms per loop

%timeit (df.Item.str.lower().apply(set) - set('carpark')).str.len() == 0
1 loop, best of 3: 1.13 s per loop

%timeit v(df.Item)
1 loop, best of 3: 497 ms per loop

【讨论】:

  • 第二种解决方案很好,也更快? (+1)
  • @jezrael 谢谢!还有,好问题。我刚试过这个,它比第一个慢一点。有趣!
  • @jezrael 您的评论鼓励我找到更快的解决方案!
猜你喜欢
  • 2020-06-22
  • 2021-06-15
  • 1970-01-01
  • 2018-09-24
  • 2021-09-28
  • 1970-01-01
  • 2017-12-29
相关资源
最近更新 更多