Python 仅当df2中某列的值在df1中时,才将2个数据帧附加在一起

Python 仅当df2中某列的值在df1中时,才将2个数据帧附加在一起,python,pandas,dataframe,Python,Pandas,Dataframe,我有两个数据帧,一个是电子邮件列表,另一个是附件列表。我想创建一个包含电子邮件和附件的数据框,但是,并非所有附件都有相应的电子邮件,这些附件应该从最终数据框中排除 可以使用GROUPID将每个附件与其父电子邮件进行匹配,GROUPID将与电子邮件的GROUPID相匹配(因为它们位于同一文档组中)。下表举例: 父数据帧 附件数据帧 所需输出数据帧 请注意,从上述示例中,最终输出中不包括两个带有GROUPIDs DOC-0000000 11和DOC-0000000 28的附件,因为它们在父电子邮件数

我有两个数据帧,一个是电子邮件列表,另一个是附件列表。我想创建一个包含电子邮件和附件的数据框,但是,并非所有附件都有相应的电子邮件,这些附件应该从最终数据框中排除

可以使用GROUPID将每个附件与其父电子邮件进行匹配,GROUPID将与电子邮件的GROUPID相匹配(因为它们位于同一文档组中)。下表举例:

父数据帧

附件数据帧

所需输出数据帧

请注意,从上述示例中,最终输出中不包括两个带有GROUPIDs DOC-0000000 11和DOC-0000000 28的附件,因为它们在父电子邮件数据框中没有相应的父电子邮件

我已经成功地编写了代码来实现这一点,但是,它的效率非常低。首先,我将“附件”数据框中每一行的GROUPID与“父电子邮件”数据框进行比较。结果(true或false)被传递到一个系列中,然后该系列被映射回attachments数据框中的一个新列“Has Parent Email”。然后,我合并“父电子邮件”数据框和附件数据框(按“Has parent Email”==True进行筛选)。下面的代码片段:

has_email = pd.Series({})
for index, row in attachments.iterrows():
    if (len(parent_emails[parent_emails['GROUPID'] 
                             == row['GROUPID']]) >0):
        has_email[index]=True
    else:
        has_email[index]=False

attachments.loc[:,'Has Parent Email'] = has_email

emails_attachments = parent_emails.append(
    attachments[attachments['Has Parent Email']==True])
这给了我所需的结果,但必须有一个更有效的方法,如果有任何建议,我将不胜感激


提前感谢。

我建议查看Pandas用户指南,了解有关如何合并、连接和连接数据帧的更多信息:

根据经验,您不必迭代数据帧的行来将它们合并在一起

如果不知道您试图附加的数据帧是如何组织的,那么很难为您提供帮助,但是如果“GROUPID”是“家长电子邮件”和“附件”共享的唯一列,那么您可以使用
concat

required\u output=pd.concat([parent\u email,attachments],axis=1,join='inner')


将join设置为INTERNAL将阻止包含GROUPID的行(在“parents_email”(例如DOC-0000000 11)中没有等效项)显示在连接的数据帧中。

我建议查看Pandas用户指南以了解有关如何合并、连接和连接数据帧的更多信息:

根据经验,您不必迭代数据帧的行来将它们合并在一起

如果不知道您试图附加的数据帧是如何组织的,那么很难为您提供帮助,但是如果“GROUPID”是“家长电子邮件”和“附件”共享的唯一列,那么您可以使用
concat

required\u output=pd.concat([parent\u email,attachments],axis=1,join='inner')


将join设置为internal将阻止包含GROUPID的行在“parents\u email”中没有等效项(例如DOC-0000000 11)通过
合并
在两个数据帧之间检索唯一的ID列表,然后使用
isin
查询
按列表过滤,并连接两个子集:

shared_ids = pd.merge(emails, attachments, on='GROUPID')['GROUPID'].unique().tolist()

# CONCATENATE WITH LIST FILTERING (TWO EQUAL VERSIONS)
email_attachments = (pd.concat([emails[emails['GROUPID'].isin(shared_ids)],
                                attachments.query("GROUPID == @shared_ids")],
                               sort = False)
                      .reset_index(drop = True)
                    )
用数据证明:

emails = pd.DataFrame({'Parent': [True, True],
                       'DOCID': ['DOC008', 'DOC023'],
                       'GROUPID': ['DOC008', 'DOC023'],
                       'FileName': ['epe model for 01/25/02', 'PLEASE READ'],
                       'FileType': ['Microsoft Outlook Note', 'Microsoft Outlook Note']})

attachments = pd. DataFrame({'EmailAttachment': ['Attachment']*4,
                             'DOCID': ['DOC008', 'DOC012', 'DOC024', 'DOC029'],
                             'GROUPID': ['DOC008', 'DOC011', 'DOC023', 'DOC028'],
                             'FileName': ['1-25act.xls', '1-29act.xls', 
                                          'Certification.doc', 'Certification.doc'],
                             'FileType': ['Microsoft Excel Spreadsheet', 'Microsoft Excel Spreadsheet',
                                          'Microsoft Word Document', 'Microsoft Word Document']})

shared_ids = pd.merge(emails, attachments, on='GROUPID')['GROUPID'].unique().tolist()

email_attachments = (pd.concat([emails[emails['GROUPID'].isin(shared_ids)],
                                attachments.query("GROUPID == @shared_ids")],
                               sort = False)
                      .reset_index(drop = True)
                    )

email_attachments
#   Parent   DOCID GROUPID                FileName                     FileType EmailAttachment
# 0   True  DOC008  DOC008  epe model for 01/25/02       Microsoft Outlook Note             NaN
# 1   True  DOC023  DOC023             PLEASE READ       Microsoft Outlook Note             NaN
# 2    NaN  DOC008  DOC008             1-25act.xls  Microsoft Excel Spreadsheet      Attachment
# 3    NaN  DOC024  DOC023       Certification.doc      Microsoft Word Document      Attachment

考虑通过
merge
检索两个数据帧之间的唯一ID列表,然后使用
isin
query
按列表过滤,并连接两个子集:

shared_ids = pd.merge(emails, attachments, on='GROUPID')['GROUPID'].unique().tolist()

# CONCATENATE WITH LIST FILTERING (TWO EQUAL VERSIONS)
email_attachments = (pd.concat([emails[emails['GROUPID'].isin(shared_ids)],
                                attachments.query("GROUPID == @shared_ids")],
                               sort = False)
                      .reset_index(drop = True)
                    )
用数据证明:

emails = pd.DataFrame({'Parent': [True, True],
                       'DOCID': ['DOC008', 'DOC023'],
                       'GROUPID': ['DOC008', 'DOC023'],
                       'FileName': ['epe model for 01/25/02', 'PLEASE READ'],
                       'FileType': ['Microsoft Outlook Note', 'Microsoft Outlook Note']})

attachments = pd. DataFrame({'EmailAttachment': ['Attachment']*4,
                             'DOCID': ['DOC008', 'DOC012', 'DOC024', 'DOC029'],
                             'GROUPID': ['DOC008', 'DOC011', 'DOC023', 'DOC028'],
                             'FileName': ['1-25act.xls', '1-29act.xls', 
                                          'Certification.doc', 'Certification.doc'],
                             'FileType': ['Microsoft Excel Spreadsheet', 'Microsoft Excel Spreadsheet',
                                          'Microsoft Word Document', 'Microsoft Word Document']})

shared_ids = pd.merge(emails, attachments, on='GROUPID')['GROUPID'].unique().tolist()

email_attachments = (pd.concat([emails[emails['GROUPID'].isin(shared_ids)],
                                attachments.query("GROUPID == @shared_ids")],
                               sort = False)
                      .reset_index(drop = True)
                    )

email_attachments
#   Parent   DOCID GROUPID                FileName                     FileType EmailAttachment
# 0   True  DOC008  DOC008  epe model for 01/25/02       Microsoft Outlook Note             NaN
# 1   True  DOC023  DOC023             PLEASE READ       Microsoft Outlook Note             NaN
# 2    NaN  DOC008  DOC008             1-25act.xls  Microsoft Excel Spreadsheet      Attachment
# 3    NaN  DOC024  DOC023       Certification.doc      Microsoft Word Document      Attachment

请注意,“父邮件数据框”和“必需的输出数据框”没有正确显示。请注意,“父邮件数据框”和“必需的输出数据框”没有正确显示。感谢您的回复,这似乎只是将两个数据框合并为一个整体。很抱歉,S/O不允许我添加图像。但实际上,我的两个数据帧都有相同的列,让我们只取关键列:DOCID | GROUPID DOCID被设置为两个数据帧的索引,作为其唯一性。GROUPID不是唯一的,电子邮件及其所有附件将具有相同的GROUPID。此外,对于父电子邮件,DOCID==GROUPID如果我有一个5封电子邮件的列表,和一个20个附件的列表,只有5个附件与5封电子邮件相关,我只想返回一个包含10个条目的2x2数据帧。感谢您的回复,这似乎只是将两个数据帧全部合并。很抱歉,S/O不允许我添加图像。但实际上,我的两个数据帧都有相同的列,让我们只取关键列:DOCID | GROUPID DOCID被设置为两个数据帧的索引,作为其唯一性。GROUPID不是唯一的,电子邮件及其所有附件将具有相同的GROUPID。此外,对于父电子邮件,DOCID==GROUPID如果我有一个包含5封电子邮件的列表,以及一个包含20个附件的列表,只有5个附件与5封电子邮件相关,我只想返回一个包含10个条目的2x2数据框。感谢您的回复。不幸的是,这种方法似乎返回了两个数据帧的完整列表。请参阅更新的答案。我在想一个与前一个版本不同的概念。冻糕,谢谢你在这方面的帮助,看来这已经做到了(仍然做一些测试来确认)。我不得不稍微修改你的代码来解释那些没有附件的电子邮件,因为它们也需要包括在内,这仅仅意味着将你的merdge修改为:shared_id=unique_top_level['BEGINGROUP'].unique().tolist()。非常感谢您抽出时间整理出如此翔实的回复。很高兴听到您的回复!是的,相应地调整。我不知道所有的电子邮件都应该保留。另外,下次不要发布这么难读的屏幕截图,而是嵌入可运行代码(就像我在这里做的那样)来重现数据。祝你快乐,干杯!谢谢你的回复。不幸的是,这种方法似乎返回了两个数据帧的完整列表。请参阅更新的答案。我在想一个与以前版本不同的概念。冻糕,谢谢你在这方面的帮助,看来这已经成功了(仍然如此)