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


119

有没有这将是一个组合的等同的任何功能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()

有一个更好的方法吗?


注意@unutbu描述了一种解决方案它比使用效率更高pd.Series.str.contains。如果性能是一个问题,那么这可能值得研究。
jpp

强烈建议使用多个关键字/正则表达式检查此答案以进行部分字符串搜索(向下滚动至“ 多个子字符串搜索 ”子标题)。
cs95

Answers:


219

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

您可以通过将单词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
添加此链接pandas.pydata.org/pandas-docs/stable / ...也可能很好。从pandas 0.15开始,字符串操作甚至更加容易
goofd 2014年

6
您需要注意的一件事是,searchfor中的字符串是否具有特殊的正则表达式字符(您可以使用re.escape进行映射)。
安迪·海登

@AndyHayden谢谢您,我已经改进了答案,以考虑到这种复杂性。
Alex Riley

我不知道为什么您的方法不适用于“ str.startswith('|'.join(searchfor))”
杜炫

48

您可以使用str.containsregex模式单独使用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

1
@JacoSolari看看这个答案stackoverflow.com/questions/37011734/...
詹姆斯

1
@詹姆斯是的,谢谢。为了完成,这里是该答案中最受推崇的oneliner。df.col.str.contains(r'(?=.*apple)(?=.*banana)',regex=True)
JacoSolari

1

这是一个单行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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.