使用〜isin([list_of_substrings])过滤数据框

时间:2020-02-12 22:39:01

标签: python pandas dataframe filter substring

鉴于一个充满电子邮件的数据框,我想过滤出包含可能被阻止的域名或明显伪造的电子邮件的行。下面的数据框代表了我的数据示例。

>> print(df)

        email                number
1   fake@fake.com              2
2   real.email@gmail.com       1
3   no.email@email.com         5
4   real@yahoo.com             2  
5   rich@money.com             1            

我想按两个列表进行过滤。第一个列表是fake_lst = ['noemail', 'noaddress', 'fake', ... 'no.email']。 第二个列表只是将集合from disposable_email_domains import blocklist转换为列表(或保留为集合)。

当我使用df = df[~df['email'].str.contains('noemail')]时,它可以正常工作并过滤掉该条目。然而,当我做df = df[~df['email'].str.contains(fake_lst)]时,我得到TypeError: unhashable type: 'list'

显而易见的答案是,像在其他许多Filter Pandas Dataframe based on List of substringspandas filtering using isin function这样的stackoverflow问题中一样,使用df = df[~df['email'].isin(fake_lst)],但最终没有效果。

我想我可以为每个可能的列表条目使用str.contains('string'),但这很麻烦。

因此,我需要根据两个列表中包含的子字符串来过滤此数据帧,以便删除任何包含要删除的特定子字符串的电子邮件以及包含该子字符串的后续行。

在上面的示例中,过滤后的数据帧为:

>> print(df)

        email                number
2   real.email@gmail.com       1
4   real@yahoo.com             2  
5   rich@money.com             1            

2 个答案:

答案 0 :(得分:1)

如果您关注dffake_lst

,这是一个潜在的解决方案
df = pd.DataFrame({
    'email': ['fake@fake.com', 'real.email@gmail.com', 'no.email@email.com',
              'real@yahoo.com', 'rich@money.com'],
    'number': [2, 1, 5, 2, 1]
})

fake_lst = ['fake', 'money']

选项1:

使用fake_lst过滤电子邮件中包含任何apply个单词的行:

df.loc[
    ~df['email'].apply(lambda x: any([i in x for i in fake_lst]))
]
                  email  number
1  real.email@gmail.com       1
2    no.email@email.com       5
3        real@yahoo.com       2

选项2:

过滤掉没有apply

df.loc[
    [not any(i) for i in zip(*[df['email'].str.contains(word) for word in fake_lst])]
]
                  email  number
1  real.email@gmail.com       1
2    no.email@email.com       5
3        real@yahoo.com       2

答案 1 :(得分:0)

使用DataFrame.isin检查DataFrame中的每个元素是否包含在值中。另一个问题是,假列表中包含不带域名的名称,因此您需要str.split来删除与之不匹配的字符。

注意:str.contains测试模式或正则表达式是否包含在Series的字符串中,因此您的代码df ['email']。str.contains('noemail')工作正常,但不适用于列表

df[~df['email'].str.split('@').str[0].isin(fake_lst)]


    email                   number
0   fake@fake.com           2
1   real.email@gmail.com    1
3   real@yahoo.com          2
4   rich@money.com          1