如何在 pandas 中测试字符串是否包含列表中的子字符串之一?

How to test if a string contains one of the substrings in a list, in pandas?

提问人:ari 提问时间:10/27/2014 最后编辑:smciari 更新时间:10/28/2023 访问量:343384

问:

是否有任何函数等效于 和 的组合?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()

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

Python 字符串 pandas 数据帧 匹配

评论

5赞 jpp 5/7/2018
注意@unutbu描述了一种解决方案,它比使用 更有效。如果性能是一个问题,那么这可能值得研究。pd.Series.str.contains
5赞 cs95 4/8/2019
强烈建议查看此答案,以使用多个关键字/正则表达式进行部分字符串搜索(向下滚动到“多个子字符串搜索”副标题)。
0赞 user7868 10/20/2022
在问题的特定示例中,您可以与元组参数一起使用:pandas.pydata.org/docs/reference/api/...pd.Series.str.endswith

答:

436赞 Alex Riley 10/27/2014 #1

一种选择是仅使用正则表达式字符来尝试匹配 Series 中单词中的每个子字符串(仍在使用 )。|sstr.contains

您可以通过将单词加入 with 来构造正则表达式:searchfor|

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

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

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

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

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

评论

4赞 goofd 10/27/2014
也许最好添加此链接 pandas.pydata.org/pandas-docs/stable/...。从 pandas 0.15 开始,字符串操作更加简单
7赞 Andy Hayden 10/27/2014
您必须注意的一件事是 searchfor 中的字符串是否具有特殊的正则表达式字符(您可以使用 re.escape 进行映射)。
0赞 Doo Hyun Shin 2/17/2019
我不知道为什么你的方法不适用于“str.startswith('|'。join(searchfor))”
2赞 The Dan 2/12/2021
在这种情况下,我知道我们使用“|”表示 OR,我们如何使用 AND??
105赞 l'L'l 10/27/2014 #2

您可以使用以下命令单独使用正则表达式模式:str.containsOR (|)

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

或者您可以将该系列添加到然后使用:dataframestr.contains

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

输出:

0 cat
1 hat
2 dog
3 fog 

评论

3赞 JacoSolari 3/26/2020
如何为AND做?
3赞 James 3/26/2020
@JacoSolari看看这个答案 stackoverflow.com/questions/37011734/......
3赞 JacoSolari 3/26/2020
@James是的,谢谢。为了完成,这里是该答案中投票最多的一句话。df.col.str.contains(r'(?=.*apple)(?=.*banana)',regex=True)
15赞 Grant Shannon 4/2/2020 #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

评论

7赞 emremrah 12/21/2020
我照做了,进展顺利,谢谢。df.loc[df.col1.apply(lambda x: True if any(i in x for i in searchfor) else False)]
0赞 Mammatt 12/16/2022 #4

有同样的问题。在不让它太复杂的情况下,您可以在每个条目之间添加,例如作品|fieldname.str.contains("cat|dog")

评论

0赞 Alexander L. Hayes 12/20/2022
嗨,您好👋,已经提供了此解决方案(stackoverflow.com/a/26578218/12439119),尽量不要重复答案。