【问题标题】:How to test if a string contains one of the substrings in a list, in pandas?如何在熊猫中测试字符串是否包含列表中的子字符串之一?
【发布时间】:2021-06-15 07:13:56
【问题描述】:

是否有任何功能相当于df.isin()df[col].str.contains() 的组合?

例如,假设我有这个系列 s = pd.Series(['cat','hat','dog','fog','pet']),我想找到所有s 包含任何['og', 'at'] 的地方,我想得到除“宠物”之外的所有东西。

我有一个解决方案,但它相当不雅:

searchfor = ['og', 'at']
found = [s.str.contains(x) for x in searchfor]
result = pd.DataFrame[found]
result.any()

有没有更好的方法来做到这一点?

【问题讨论】:

  • 注意:有一个解决方案described by @unutbu,比使用pd.Series.str.contains效率更高。如果性能是一个问题,那么这可能值得调查。
  • 强烈建议查看this answer 使用多个关键字/正则表达式进行部分字符串搜索(向下滚动到“多个子字符串搜索”子标题)。

标签: python string pandas dataframe match


【解决方案1】:

一种选择是使用正则表达式| 字符来尝试匹配系列中单词s 中的每个子字符串(仍然使用str.contains)。

您可以通过将searchfor 中的单词与| 连接来构造正则表达式:

>>> searchfor = ['og', 'at']
>>> s[s.str.contains('|'.join(searchfor))]
0    cat
1    hat
2    dog
3    fog
dtype: object

正如@AndyHayden 在下面的 cmets 中指出的那样,请注意您的子字符串是否包含您想要逐字匹配的特殊字符,例如 $^。这些字符在正则表达式的上下文中具有特定的含义,会影响匹配。

您可以通过使用re.escape 转义非字母数字字符来使您的子字符串列表更安全:

>>> import re
>>> matches = ['$money', 'x^y']
>>> safe_matches = [re.escape(m) for m in matches]
>>> safe_matches
['\\$money', 'x\\^y']

当与str.contains 一起使用时,此新列表中的字符串将逐字匹配每个字符。

【讨论】:

  • 也可以添加此链接pandas.pydata.org/pandas-docs/stable/…。从 pandas 0.15 开始,字符串操作更加简单
  • 您必须注意的一件事是 searchfor 中的字符串是否包含特殊的正则表达式字符(您可以map with re.escape)。
  • @AndyHayden 谢谢,我已经改进了我的答案以考虑到这种并发症。
  • 我不知道为什么你的方法不适用于“str.startswith('|'.join(searchfor))”
  • 在这种情况下,我知道我们使用“|”对于 OR,我们如何使用 AND??
【解决方案2】:

您可以单独使用str.contains 和使用OR (|) 的正则表达式模式:

s[s.str.contains('og|at')]

或者您可以将系列添加到dataframe,然后使用str.contains

df = pd.DataFrame(s)
df[s.str.contains('og|at')] 

输出:

0 cat
1 hat
2 dog
3 fog 

【讨论】:

  • AND怎么做?
  • @JacoSolari 看看这个答案stackoverflow.com/questions/37011734/…
  • @James 是的,谢谢。为了完成这里是该答案中最受好评的单行者。 df.col.str.contains(r'(?=.*apple)(?=.*banana)',regex=True)
【解决方案3】:

这是一个同样有效的单行 lambda:

df["TrueFalse"] = df['col1'].apply(lambda x: 1 if any(i in x for i in searchfor) else 0)

输入:

searchfor = ['og', 'at']

df = pd.DataFrame([('cat', 1000.0), ('hat', 2000000.0), ('dog', 1000.0), ('fog', 330000.0),('pet', 330000.0)], columns=['col1', 'col2'])

   col1  col2
0   cat 1000.0
1   hat 2000000.0
2   dog 1000.0
3   fog 330000.0
4   pet 330000.0

应用 Lambda:

df["TrueFalse"] = df['col1'].apply(lambda x: 1 if any(i in x for i in searchfor) else 0)

输出:

    col1    col2        TrueFalse
0   cat     1000.0      1
1   hat     2000000.0   1
2   dog     1000.0      1
3   fog     330000.0    1
4   pet     330000.0    0

【讨论】:

  • 我以df.loc[df.col1.apply(lambda x: True if any(i in x for i in searchfor) else False)] 的身份完成了它,并且一切顺利,谢谢。
猜你喜欢
  • 2021-09-28
  • 2020-06-22
  • 2015-09-16
  • 2019-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多