【问题标题】:pandas grouping by multiple categories for duplicatespandas 按多个类别对重复项进行分组
【发布时间】:2020-12-07 22:45:07
【问题描述】:

鉴于此示例数据集,我试图提醒各家公司他们在我们的数据库中有重复项,以便他们都可以相互通信并确定该人所属的公司:

Name            SSN      Company
Smith, John     1234     A
Smith, John     1234     B
Jones, Mary     4567     C
Jones, Mary     4567     D
Williams, Joe   1212     A
Williams, Joe   1212     C

理想的输出是提供给每家公司的数据框,提醒他们注意数据中的重复项以及声称分配给他们的同一个人的另一家公司的身份。像这样的:

A 公司数据框

Name             SSN      Company
Smith, John      1234     A
Smith, John      1234     B
Williams, Joe    1212     A
Williams, Joe    1212     C

C 公司数据帧

Name             SSN      Company
Jones, Mary      4567     C
Jones, Mary      4567     D
Williams, Joe    1212     A
Williams, Joe    1212     C

因此,尝试了 groupby ['Company'],但是,当然,仅将所有公司结果分组到一个组中,它省略了具有重复人员和 SSN 的另一家公司。某些版本的 groupby (在那个逻辑的深处)似乎应该可以工作,但是按多列分组,不完全是。输出将按公司分组,但包含与该公司组中的所有值关联的重复值。一个谜,因此我的帖子。

可能是 groupby Company,然后在 Name 列上将每个 Company 组与其他组连接起来?

【问题讨论】:

  • 为什么没有B公司数据框?
  • @DaniMesejo。哦,只是为了简洁起见。希望结果中每家公司都有一个数据框。

标签: python pandas pandas-groupby


【解决方案1】:

首先,我们以Company 为中心,以便轻松查看多家公司的员工:

df2 = pd.pivot_table(df.assign(count = 1), index = ['Name','SSN'], columns='Company', values='count', aggfunc = 'count')

生产

    Company             A   B   C   D
Name            SSN             
Jones,Mary      4567    NaN NaN 1.0 1.0
Smith,John      1234    1.0 1.0 NaN NaN
Williams,Joe    1212    1.0 NaN 1.0 NaN

其中 values 是该公司的员工人数,NaN 表示他不在该公司

现在我们可以通过操作来为不同的公司提取有用的视图。对于 A,我们可以说“拉动 A 公司的所有人任何其他公司的所有人”:

dfA = df2[(~df2['A'].isna()) & (~df2[['B','C','D']].isna()).any(axis=1) ].dropna(how = 'all', axis=1)
dfA

这会产生

    Company              A  B   C
Name            SSN         
Smith,John      1234    1.0 1.0 NaN
Williams,Joe    1212    1.0 NaN 1.0

请注意,我们通过dropna(...) 删除了与此处无关的公司,在本例中为 D,因为 A 和 D 之间没有重叠。并且 D 列包含所有 NaN

我们可以轻松编写一个函数来为任何公司生成报告

def report_for(company_name):
    companies = df2.columns
    other_companies = [c for c in companies if c != company_name]
    return (df2[(~df2[company_name].isna()) 
              & (~df2[other_companies].isna()).any(axis=1) ]
              .loc[:,[company_name] + other_companies]
              .dropna(how = 'all', axis=1)
              )

请注意,我们还对列进行了重新排序,因此公司“B”的表首先包含“B”列:

report_for('B')

生成

    Company         B   A
Name        SSN     
Smith,John  1234    1.0 1.0

【讨论】:

  • 非常感谢您的回复和解释它的详细信息。在这里可以学到很多东西,这些步骤及其背后的策略非常有效。
  • @JohnTaylor 真棒,很高兴它有帮助!
  • 仅供参考,我进一步扩展了这一步,并用列名替换了 1 值,这样我就可以为每个公司生成数据,每个公司都有一个人和相关的公司名称,为一行中的每个人。再次感谢。
  • @JohnTaylor 听起来像是一个有用的补充。如果您愿意,请随时编辑答案以包含该步骤
猜你喜欢
  • 1970-01-01
  • 2017-09-22
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 2014-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多