Python - 根据部分字符串匹配将行保留在数据框中
Python - keep rows in dataframe based on partial string match
我有 2 个数据框:
df1 是邮箱和电子邮件 ID 的列表
df2 显示已批准的域列表
我从 excel sheet
中读取了两个数据帧
xls = pd.ExcelFile(input_file_shared_mailbox)
df = pd.read_excel(xls, sheet_name = sheet_name_shared_mailbox)
我只想在 df1 中保留记录,其中 df1[Email_Id] 包含 df2[approved_domain]
print(df1)
Mailbox Email_Id
0 mailbox1 abc@gmail.com
1 mailbox2 def@yahoo.com
2 mailbox3 ghi@msn.com
print(df2)
approved_domain
0 msn.com
1 gmail.com
我想要 df3,它基本上显示
print (df3)
Mailbox Email_Id
0 mailbox1 abc@gmail.com
1 mailbox3 ghi@msn.com
这是我现在拥有的代码,我认为它很接近,但我无法找出语法中的确切问题
df3 = df1[df1['Email_Id'].apply(lambda x: [item for item in x if item in df2['Approved_Domains'].tolist()])]
但是得到这个错误
TypeError: unhashable type: 'list'
我花了很多时间在论坛上寻找解决方案,但找不到我要找的东西。感谢所有帮助。
解决方案
df1 = {'MailBox': ['mailbox1', 'mailbox2', 'mailbox3'], 'Email_Id': ['abc@gmail.com', 'def@yahoo.com', 'ghi@msn.com']}
df2 = {'approved_domain':['msn.com', 'gmail.com']}
mailboxes, emails = zip( # unzip the columns
*filter( # filter
lambda i: any([ # i = ('mailbox1', 'abc@gmail.com')
approved_domain in i[1] for approved_domain in df2['approved_domain']
]),
zip(df1['MailBox'], df1['Email_Id']) # zip the columns
)
)
df3 = {
'MailBox': mailboxes,
'Email_I': emails
}
print(df3)
输出:
> {'Email_ID': ('abc@gmail.com', 'ghi@msn.com'), 'MailBox': ('mailbox1', 'mailbox3')}
一些注意事项:
这段代码的大部分基本上只是用于解析数据结构。压缩和解压缩仅用于将列列表转换为行列表并返回。如果你已经有一个行列表,你只需要做过滤部分
所以这些是你需要遵循的步骤来为你的两个数据框做你想做的事
1.Split 您的 email_address 列分为两个单独的列
df1['add'], df1['domain'] = df1['email_address'].str.split('@', 1).str
2.Then 删除添加列以保持数据框干净
df1 = df1.drop('add',axis =1)
3.Get 通过不选择 'domain' 列中与 'approved_doman' 列
不匹配的任何值,只包含所需值的新数据框
df_new = df1[~df1['domain'].isin(df2['approved_domain'])]
4。将 'domain' 列拖放到 df_new
中
df_new = df_new.drop('domain',axis = 1)
这就是结果
mailbox email_address
1 mailbox2 def@yahoo.com
2 mailbox3 ghi@msn.com
您可以使用动态创建的正则表达式来搜索列表中的有效域并最终将其过滤掉。
这里是代码,供大家参考。
# -*- coding: utf-8 -*-
import pandas as pd
import re
mailbox_list = [
['mailbox1', 'abc@gmail.com'],
['mailbox2', 'def@yahoo.com'],
['mailbox3', 'ghi@msn.com']]
valid_domains = ['msn.com', 'gmail.com']
df1 = pd.DataFrame(mailbox_list, columns=['Mailbox', 'EmailID'])
df2 = pd.DataFrame(valid_domains)
valid_list = []
for index, row in df1.iterrows():
for idx, record in df2.iterrows():
if re.search(rf"@{record[0]}", row[1], re.IGNORECASE):
valid_list.append([row[0], row[1]])
df3 = pd.DataFrame(valid_list, columns=['Mailbox', 'EmailID'])
print(df3)
这个输出是:
Mailbox EmailID
0 mailbox1 abc@gmail.com
1 mailbox3 ghi@msn.com
我有 2 个数据框:
df1 是邮箱和电子邮件 ID 的列表
df2 显示已批准的域列表
我从 excel sheet
中读取了两个数据帧 xls = pd.ExcelFile(input_file_shared_mailbox)
df = pd.read_excel(xls, sheet_name = sheet_name_shared_mailbox)
我只想在 df1 中保留记录,其中 df1[Email_Id] 包含 df2[approved_domain]
print(df1)
Mailbox Email_Id
0 mailbox1 abc@gmail.com
1 mailbox2 def@yahoo.com
2 mailbox3 ghi@msn.com
print(df2)
approved_domain
0 msn.com
1 gmail.com
我想要 df3,它基本上显示
print (df3)
Mailbox Email_Id
0 mailbox1 abc@gmail.com
1 mailbox3 ghi@msn.com
这是我现在拥有的代码,我认为它很接近,但我无法找出语法中的确切问题
df3 = df1[df1['Email_Id'].apply(lambda x: [item for item in x if item in df2['Approved_Domains'].tolist()])]
但是得到这个错误
TypeError: unhashable type: 'list'
我花了很多时间在论坛上寻找解决方案,但找不到我要找的东西。感谢所有帮助。
解决方案
df1 = {'MailBox': ['mailbox1', 'mailbox2', 'mailbox3'], 'Email_Id': ['abc@gmail.com', 'def@yahoo.com', 'ghi@msn.com']}
df2 = {'approved_domain':['msn.com', 'gmail.com']}
mailboxes, emails = zip( # unzip the columns
*filter( # filter
lambda i: any([ # i = ('mailbox1', 'abc@gmail.com')
approved_domain in i[1] for approved_domain in df2['approved_domain']
]),
zip(df1['MailBox'], df1['Email_Id']) # zip the columns
)
)
df3 = {
'MailBox': mailboxes,
'Email_I': emails
}
print(df3)
输出:
> {'Email_ID': ('abc@gmail.com', 'ghi@msn.com'), 'MailBox': ('mailbox1', 'mailbox3')}
一些注意事项:
这段代码的大部分基本上只是用于解析数据结构。压缩和解压缩仅用于将列列表转换为行列表并返回。如果你已经有一个行列表,你只需要做过滤部分
所以这些是你需要遵循的步骤来为你的两个数据框做你想做的事
1.Split 您的 email_address 列分为两个单独的列
df1['add'], df1['domain'] = df1['email_address'].str.split('@', 1).str
2.Then 删除添加列以保持数据框干净
df1 = df1.drop('add',axis =1)
3.Get 通过不选择 'domain' 列中与 'approved_doman' 列
不匹配的任何值,只包含所需值的新数据框 df_new = df1[~df1['domain'].isin(df2['approved_domain'])]
4。将 'domain' 列拖放到 df_new
中 df_new = df_new.drop('domain',axis = 1)
这就是结果
mailbox email_address
1 mailbox2 def@yahoo.com
2 mailbox3 ghi@msn.com
您可以使用动态创建的正则表达式来搜索列表中的有效域并最终将其过滤掉。
这里是代码,供大家参考。
# -*- coding: utf-8 -*-
import pandas as pd
import re
mailbox_list = [
['mailbox1', 'abc@gmail.com'],
['mailbox2', 'def@yahoo.com'],
['mailbox3', 'ghi@msn.com']]
valid_domains = ['msn.com', 'gmail.com']
df1 = pd.DataFrame(mailbox_list, columns=['Mailbox', 'EmailID'])
df2 = pd.DataFrame(valid_domains)
valid_list = []
for index, row in df1.iterrows():
for idx, record in df2.iterrows():
if re.search(rf"@{record[0]}", row[1], re.IGNORECASE):
valid_list.append([row[0], row[1]])
df3 = pd.DataFrame(valid_list, columns=['Mailbox', 'EmailID'])
print(df3)
这个输出是:
Mailbox EmailID
0 mailbox1 abc@gmail.com
1 mailbox3 ghi@msn.com