检查熊猫数据框字符串列是否包含数组中给定的所有元素

时间:2021-07-08 03:24:44

标签: python pandas dataframe

我有一个如下所示的数据框:

>>> import pandas as pd
>>> df = pd.DataFrame(data = [['app;',1,2,3],['app; web;',4,5,6],['web;',7,8,9],['',1,4,5]],columns = ['a','b','c','d'])
>>> df
           a  b  c  d
0       app;  1  2  3
1  app; web;  4  5  6
2       web;  7  8  9
3             1  4  5

我有一个如下所示的输入数组:["app","web"] 对于这些值中的每一个,我想对照数据帧的特定列进行检查并返回如下所示的决定:

>>> df.a.str.contains("app")
0     True
1     True
2    False
3    False

由于 str.contains 只允许我查找单个值,我想知道是否有其他直接方法可以确定相同的值,例如:

 df.a.str.contains(["app","web"]) # Returns TypeError: unhashable type: 'list'

我的最终目标不是进行绝对匹配 (df.a.isin(["app", "web"]),而是执行一个“包含”逻辑,即使这些字符存在于数据框的该单元格中,也返回 true。

注意:我当然可以使用apply方法为相同的逻辑创建我自己的函数,例如:

elementsToLookFor = ["app","web"]
df[header] = df.apply(lambda element: all([a in element for a in elementsToLookFor]))

但我更感兴趣的是为此的最佳算法,因此更喜欢在 Pandas 中使用原生 Pandas 函数,或者下一个最优化的自定义解决方案。

3 个答案:

答案 0 :(得分:2)

这也应该有效:

l = ["app","web"]
df['a'].str.findall('|'.join(l)).map(lambda x: len(set(x)) == len(l))

这也应该有效:

pd.concat([df['a'].str.contains(i) for i in l],axis=1).all(axis = 1)

答案 1 :(得分:1)

试试 str.get_dummies

df.a.str.replace(' ','').str.get_dummies(';')[['web','app']].all(1)
0    False
1     True
2    False
3    False
dtype: bool

更新

df['a'].str.contains(r'^(?=.*web)(?=.*app)')

更新 2:(为了确保不区分大小写并且列 dtype 是 str,否则逻辑可能会失败):

elementList = ['app','web']
for eachValue in elementList:
                    valueString += f'(?=.*{eachValue})'
df[header] = df[header].astype(str).str.lower() #To ensure case insenstivity and the dtype of the column is string
result = df[header].str.contains(valueString)

答案 2 :(得分:1)

<块引用>

这么多方案,哪个最有效

基于 str.contains 的答案通常最快,但 str.findall 在较小的 dfs 上也非常快:

timings vs len(df)

values = ['app', 'web']
pattern = ''.join(f'(?=.*{value})' for value in values)

def replace_dummies_all(df):
    return df.a.str.replace(' ', '').str.get_dummies(';')[values].all(1)

def findall_map(df):
    return df.a.str.findall('|'.join(values)).map(lambda x: len(set(x)) == len(values))

def lower_contains(df):
    return df.a.astype(str).str.lower().str.contains(pattern)

def contains_concat_all(df):
    return pd.concat([df.a.str.contains(l) for l in values], axis=1).all(1)

def contains(df):
    return df.a.str.contains(pattern)