我试图从模糊匹配列表中项目的数据框中删除值。
我有一个类似于:
的数据框(test_df) id email created_at
0 1 son@mail_a.com 2017-01-21 18:19:00
1 2 boy@mail_b.com 2017-01-22 01:19:00
2 3 girl@mail_c.com 2017-01-22 01:19:00
我有一个包含几百个电子邮件域名的列表,我正在从一个类似于以下内容的txt文件中读取:
mail_a.com
mail_d.com
mail_e.com
我尝试使用以下方式从数据框中删除包含匹配电子邮件域的任何行:
email_domains = open('file.txt', 'r')
to_drop = email_domains.read().splitlines()
dropped_df = test_df[~test_df['email'].isin(to_drop)]
print(test_df)
因此,结果应如下所示:
id email created_at
0 2 boy@mail_b.com 2017-01-22 01:19:00
1 3 girl@mail_c.com 2017-01-22 01:19:00
但第一行是" son@mail_a.com"没有丢弃。有什么建议?
答案 0 :(得分:3)
从电子邮件中解析域名非常容易,因此我们可以先使用.str.split('@')
解析域名,然后使用isin()
方法进行检查:
In [12]: df[~df.email.str.split('@').str[1].isin(domains.domain)]
Out[12]:
id email created_at
1 2 boy@mail_b.com 2017-01-22 01:19:00
2 3 girl@mail_c.com 2017-01-22 01:19:00
其中:
In [13]: domains
Out[13]:
domain
0 mail_a.com
1 mail_d.com
2 mail_e.com
答案 1 :(得分:3)
isin
查找完全匹配。您的情况更适合endswith
或contains
:
df[~df['email'].str.endswith(tuple(to_drop))]
Out:
id email created_at
1 2 boy@mail_b.com 2017-01-22 01:19:00
2 3 girl@mail_c.com 2017-01-22 01:19:00
df[~df['email'].str.contains('|'.join(to_drop))]
Out:
id email created_at
1 2 boy@mail_b.com 2017-01-22 01:19:00
2 3 girl@mail_c.com 2017-01-22 01:19:00
答案 2 :(得分:0)
您可以使用if (objects.count)
和apply
字符串并将其用于split
isin
结果
print test_df[~test_df['email'].apply(lambda x: x.split('@')[1]).isin(to_drop)]
答案 3 :(得分:0)
又一个答案......这是一个单行:
exclude = ['mail_a.com','mail_d.com','mail_e.com']
df[df.apply(lambda x: all([x['email'].rfind(ex) < 0 for ex in exclude]), axis=1)]
# OUTPUT
# Out[50]:
# created_at email id
# 1 2017-01-22 01:19:00 boy@mail_b.com 2
# 2 2017-01-22 01:19:00 girl@mail_c.com 3
如果找不到模式,我在这里使用rfind返回-1。