使用 ~isin([子字符串列表]) 过滤数据框架。

3

给定一个包含电子邮件的数据框,我想要过滤掉包含潜在被屏蔽域名或明显欺诈邮件的行。下面的数据框代表我的数据示例。

>> 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']。 第二个列表只是将disposable_email_domains import blocklist转换为列表(或保留为集合)。

当我使用df = df [~ df ['email'] .str.contains('noemail')]时,它可以正常工作并过滤掉该条目。但是当我执行df = df [~ df ['email'] .str.contains(fake_lst)]时,会出现类型错误:不可哈希类型:'list'

明显的答案是像许多其他stackoverflow问题一样使用df = df [~ df ['email'] .isin(fake_lst)],比如Filter Pandas Dataframe based on List of substringspandas filtering using isin function,但这最终没有任何影响。

我想对此数据帧进行过滤,基于两个列表中包含的子字符串,使得任何包含特定子字符串的电子邮件都被去除,并且包含它的后续行也被删除。

在上面的示例中,过滤后的数据框将是:

>> print(df)

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

可能是Pandas过滤系列中的多个子字符串的重复问题。 - jpp
2个回答

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:

使用apply过滤掉在邮件中出现任何fake_lst单词的行:

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

这个方法很有效,但我正在尝试避免使用 apply,因为在大型数据框上它需要很长时间。 - DrakeMurdoch
1
@DrakeMurdoch 我增加了另一个选项,这次没有使用 apply - Ali Cirik

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

它在实践中可能有效,但这不是问题的关键。 你假设假名总是出现在“@”之前,但没有人说一定是这样。 - Binyamin Even
3
pat = '|'.join(fake_lst); df[~df.email.str.contains(pat)] - wwii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接