【问题标题】:How to merge two Data Frames based on a few columns in second Data Frame in Python Pandas?如何根据 Python Pandas 中第二个数据框中的几列合并两个数据框?
【发布时间】:2021-10-16 21:32:05
【问题描述】:

我在 Python 中有两个 Pandas 数据框,如下所示:

df1

ID
----
11
22
33
44

df2

ID1   ID2   ID3
--------------------
11  | 5   | 114
88  | 22  | 18
99  | 45  | 33
  • df1 的行数比 df2 多
  • 两个数据框中的值类型都是 int

我需要执行类似 df1 LEFT JOIN df2 之类的操作,并使用 df1 中的“ID”和 df2 中的“ID1”、“ID2”、“ID3”将 df1 与 df2 合并

  1. 合并 ID (df1) 和 ID1 (df2) 上的数据帧
  2. 如果 ID 不与 ID1 合并 --> 在 ID 和 ID2 上合并
  3. 如果 ID 不与 ID2 合并 --> 在 ID 和 ID3 上合并
  4. 如果行不合并,则返回 123456

因此,我需要以下内容:

ID    ID1   ID2   ID3
--------------------------
11  | 11     | 5       | 114
22  | 88     | 22      | 18
33  | 99     | 45      | 33
44  | 123456 | 123456  | 123456

如何在 Python Pandas 中做到这一点?我完全不知道。

【问题讨论】:

  • 如果您的第一个数据帧上的 ID=0,预期结果是什么?
  • ID 在您的第一个数据帧中是唯一的吗?
  • 是的,id在df1中是唯一的
  • 对于像 0 这样的多重匹配?
  • 任务是这样的:通过ID = ID1将df与df2合并,但它不合并make ID = ID2,但它不合并make ID = ID3,但如果ID确实与任何ID1合并, ID2,ID3 写入 123456,df1 或 df2 中的任何一个都不可能为 0,我更改了它有问题:)

标签: python pandas dataframe merge


【解决方案1】:

您可以将df2 堆叠成df2a,然后左连接df1df2a,然后左连接原始df2 匹配原始索引。用123456 填充NaN 并删除中间列以达到所需的输出:

df2a = df2.stack().reset_index(name='ID')

df_out = (df1.merge(df2a, on='ID', how='left')
             .merge(df2, left_on='level_0', right_index=True, how='left')
             .fillna(123456, downcast='infer')
             .drop(['level_0', 'level_1'], axis=1)
         )

或者将第二个.merge简化为.join(感谢@HenryEcker的建议),如下:

df2a = df2.stack().reset_index(name='ID')

df_out = (df1.merge(df2a, on='ID', how='left')
             .join(df2, on='level_0')
             .fillna(123456, downcast='infer')
             .drop(['level_0', 'level_1'], axis=1)
         )

结果:

print(df_out)

   ID     ID1     ID2     ID3
0  11      11       5     114
1  22      88      22      18
2  33      99      45      33
3  44  123456  123456  123456

步骤分解:

print(df2a)

   level_0 level_1   ID
0        0     ID1   11
1        0     ID2    5
2        0     ID3  114
3        1     ID1   88
4        1     ID2   22
5        1     ID3   18
6        2     ID1   99
7        2     ID2   45
8        2     ID3   33

【讨论】:

  • Seabean 第一行应该是:df1a = df1.stack().reset_index(name='ID') ?因为在 df2 中没有 ID 在 df2 中是 ID1,ID2,在 df1 中的 ID3 是 ID 吗?
  • @Matop 第一行是正确的。 ID 创建为 ID1ID2ID3 的聚合。你可以打印df2a的结果并查看。
  • @Matop 我已经包含了df2a 的结果供您参考。
  • 哇,完美,它有效!我给了你最好的答案!谢谢你 SeanBean :)
  • .join(df2, on='level_0') 等价于 .merge(df2, left_on='level_0', right_index=True, how='left') 并避免了一些合并的开销,必须通过 arg 解析在内部找到 join 命令。
【解决方案2】:

你应该看看这里 (https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html),你有很多不同的解决方案。例如:

import pandas as pd

df1 = pd.DataFrame(
    {
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"],
    }
)


df2 = pd.DataFrame(
    {
        "A": ["A4", "A5", "A6", "A7"],
        "B": ["B4", "B5", "B6", "B7"],
        "C": ["C4", "C5", "C6", "C7"],
        "D": ["D4", "D5", "D6", "D7"],
    }
)


df3 = pd.DataFrame(
{
    "A": ["A8", "A9", "A10", "A11", "A12"],
    "B": ["B8", "B9", "B10", "B11", "B12"],
    "C": ["C8", "C9", "C10", "C11", "C12"],
    "D": ["D8", "D9", "D10", "D11", "D12"],
}
)
df = pd.concat([df1, df2, df3], axis=1)

给你:

     A    B    C    D    A    B    C    D    A    B    C    D
0   A0   B0   C0   D0   A4   B4   C4   D4   A8   B8   C8   D8
1   A1   B1   C1   D1   A5   B5   C5   D5   A9   B9   C9   D9
2   A2   B2   C2   D2   A6   B6   C6   D6  A10  B10  C10  D10
3   A3   B3   C3   D3   A7   B7   C7   D7  A11  B11  C11  D11
4  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  A12  B12  C12  D12

所以,在你的情况下:

df1 = pd.DataFrame(
    {
        "ID": [11, 22, 33, 44]
    }
)


df2 = pd.DataFrame(
    {
        "ID1": [11, 88, 99],
        "ID2": [5, 22, 45],
        "ID3": [114, 18, 33]
    }
)


df = pd.concat([df1, df2], axis=1)
df.fillna('123456', inplace=True) # to replace NaNs with the values you want

给予:

   ID     ID1     ID2     ID3
0  11    11.0     5.0   114.0
1  22    88.0    22.0    18.0
2  33    99.0    45.0    33.0
3  44  123456  123456  123456

【讨论】:

  • 对我来说这并不容易,您能提出一种可能的解决方案吗?你认为最简单的? :)
  • Alessandro Peca,您能否使用我的示例 df1 和 df2 展示此解决方案?
  • 已更新。如果对您有用,请将其标记为正确答案。
  • 我很确定这只适用于这个特定的实例,因为 df2 的顺序已经正确。如果您对 df2 中的行进行洗牌,则此方法不再有效。
猜你喜欢
  • 2016-10-08
  • 1970-01-01
  • 2021-01-11
  • 2016-01-06
  • 1970-01-01
  • 2017-09-03
相关资源
最近更新 更多