【问题标题】:Pandas - merge two dataframes, sum similar columns, only keep rows with matching keys (inner join)Pandas - 合并两个数据框,对相似的列求和,只保留具有匹配键的行(内连接)
【发布时间】:2020-02-24 22:28:56
【问题描述】:

我被困在 pandas concatmerge 函数之间,努力使两者兼得。我需要对名称和日期的行进行内部连接,对公共列 A 和 B 求和,并保留类别中的值(如果需要,我真的可以将其添加到连接中,它们匹配)。

例子-

df1

| name | date     | A | B | category |
|------|----------|---|---|----------|
| W    | 1/1/2020 | 1 | 1 | home     |
| W    | 1/2/2020 | 1 | 1 | home     |
| Y    | 1/3/2020 | 1 | 1 | garden   |
| Y    | 1/4/2020 | 1 | 1 | garden   |

df2

| name | date     | A | B | category |
|------|----------|---|---|----------|
| W    | 1/1/2020 | 2 | 2 | home     |
| W    | 1/2/2020 | 1 | 1 | home     |
| Y    | 1/3/2020 | 1 | 1 | garden   |
| Y    | 1/5/2020 | 1 | 1 | garden   |

想要的结果 -

| name | date     | A | B | category |
|------|----------|---|---|----------|
| W    | 1/1/2020 | 3 | 3 | home     |
| W    | 1/2/2020 | 2 | 2 | home     |
| Y    | 1/3/2020 | 2 | 2 | garden   |

我发现merge 将加入行,但会复制任何未加入的列而不是将它们相加。

concat 将对行求和,但不进行内部连接,因此我仅从一个数据帧或另一个数据帧中获取包含数据的行。我试过pd.concat([df_1, df_2], join='inner',但“内在”并没有达到我想要的效果。

【问题讨论】:

  • 我会说在datecategory 上使用groupby,以及sum(A)sum(B) 作为您的聚合。

标签: python pandas


【解决方案1】:

我会在 namedatecategory 上使用 groupby,并使用 sum 聚合(总结 AB)。不过,这会提供额外的列,因为日期为 1/4/20201/5/2020 的行不会消失,而是总和为 1。

这是代码:

import pandas as pd

df = pd.DataFrame({'name': ['W', 'W', 'Y', 'Y'], 
                   'date': ['1/1/2020', '1/2/2020', '1/3/2020', '1/4/2020 '],
                   'A': [1, 1, 1, 1],
                   'B': [1, 1, 1, 1],
                   'category': ['home', 'home', 'garden', 'garden']})

df2 = pd.DataFrame({'name': ['W', 'W', 'Y', 'Y'], 
                   'date': ['1/1/2020', '1/2/2020', '1/3/2020', '1/5/2020 '],
                   'A': [2, 1, 1, 1],
                   'B': [2, 1, 1, 1],
                   'category': ['home', 'home', 'garden', 'garden']})

df3 = pd.concat([df, df2]).groupby(by=['name', 'date', 'category']).sum()

这给了你:

                         A  B
name date      category      
W    1/1/2020  home      3  3
     1/2/2020  home      2  2
Y    1/3/2020  garden    2  2
     1/4/2020  garden    1  1
     1/5/2020  garden    1  1

如果您不想看到总和 = 1 的行,则可以过滤 A 或/和 B 的值

希望这会有所帮助。

【讨论】:

  • 我同意,append() + groupby() 是最好的选择,但如果 df1 上没有名称-日期匹配,他不想保留 df2 的任何内容。得到结果后,可能只是在 df1 上进行快速左合并。
【解决方案2】:

第一个“天真的”解决方案:

d3 = pd.merge(d1,d2, left_on = ["name","date","category"], right_on = ["name","date","category"])
d3 = d3.assign(A = d3.A_x + d3.A_y, B = d3.B_x + d3.B_y, ).drop(columns=["A_y","A_x","B_y","B_x"])

更好的解决方案,无需手动添加列:

key = ["name","date","category"]
d3 = pd.merge(d1,d2, left_on = key, right_on = key)[key]
d4 = pd.concat([d1, d2]).groupby(by=key).sum()
d5 = pd.merge(d3,d4,right_on = key, left_on = key)

结果:

     name        date    category  A  B
0   W       1/1/2020    home       3  3
1   W       1/2/2020    home       2  2
2   Y       1/3/2020    garden     2  2

使用pd.merge 可以指定组合键["name","date","category"] 加入2 个数据帧。

【讨论】:

  • 我确实最终做了这样的事情,但如果有一个不涉及手动求和/重命名列的解决方案,我会保持开放状态。我的数据集中有 6 个常见的列,所以我必须对 12 个列进行求和并删除,这很乏味。
【解决方案3】:

这个怎么样:

dff = df1
    .set_index(['name', 'date', 'category'])
    .add(df2.set_index(['name', 'date', 'category'])
    .reset_index()
    .dropna()
    .reindex(columns=df1.columns)

dff

输出:

    name    date    A   B   category
 0  W   1/1/2020    3   3   home
 1  W   1/2/2020    2   2   home
 2  Y   1/3/2020    2   2   garden

这就是你想要的?

【讨论】:

  • 关闭,但结果只有 3 行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-24
  • 2013-02-04
  • 2020-11-21
  • 1970-01-01
  • 2018-10-16
相关资源
最近更新 更多