【问题标题】:Pandas left merge keeping data in right dataframe on duplicte columns熊猫左合并将数据保留在重复列的右数据框中
【发布时间】:2021-03-24 17:18:29
【问题描述】:

我想合并两个数据框,df2 可能有更多列,并且总是 1 行。我希望 df2 行中的数据覆盖 df 中的匹配行。注意:serno 列一起使一行唯一。

import pandas as pd

df = pd.DataFrame({'ser': {0: 0, 1: 0, 2: 0, 3: 1, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2}, 'no': {0: 0, 1: 1, 2: 2, 3: 0, 4: 1, 5: 2, 6: 0, 7: 1, 8: 2}, 'c': {0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}})

df2 = pd.DataFrame({'ser': {0: 1}, 'no': {0: 2}, 'c': {0: 88}, 'd': {0: 90}})


>>> df
   ser  no  c
0    0   0  1
1    0   1  1
2    0   2  1
3    1   0  1
4    1   1  1
5    1   2  1
6    2   0  1
7    2   1  1
8    2   2  1

>>> df2
   ser  no   c   d
0    1   2  88  90

我尝试过左合并,但这会创建两个 c 列(c_x 和 c_y):

>>> pd.merge(df,df2,how='left',on=['ser','no'])
   ser  no  c_x   c_y     d
0    0   0    1   NaN   NaN
1    0   1    1   NaN   NaN
2    0   2    1   NaN   NaN
3    1   0    1   NaN   NaN
4    1   1    1   NaN   NaN
5    1   2    1  88.0  90.0
6    2   0    1   NaN   NaN
7    2   1    1   NaN   NaN
8    2   2    1   NaN   NaN

期望的输出:

   ser  no    c   d  
0    0   0    1   NaN 
1    0   1    1   NaN  
2    0   2    1   NaN 
3    1   0    1   NaN 
4    1   1    1   NaN 
5    1   2    88  90 
6    2   0    1   NaN
7    2   1    1   NaN
8    2   2    1   NaN

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    弗兰肯斯坦答案

    df[['ser', 'no']].merge(df2, 'left').set_axis(df.index).fillna(df)
    
       ser  no     c     d
    0    0   0   1.0   NaN
    1    0   1   1.0   NaN
    2    0   2   1.0   NaN
    3    1   0   1.0   NaN
    4    1   1   1.0   NaN
    5    1   2  88.0  90.0
    6    2   0   1.0   NaN
    7    2   1   1.0   NaN
    8    2   2   1.0   NaN
    

    说明

    1. 我将合并列 ['ser', 'no'] 并且不想在 merge 调用中指定。另外,我不希望像 'c_x''c_y' 这样愚蠢的重复列名,所以我只切片我想要共同的列然后合并

       df[['ser', 'no']].merge(df2, 'left')
      
    2. 当我合并时,我只想要左侧数据框中的行。但是,merge 通常会生成许多与原始数据帧大不相同的行,因此会生成新的index。但是,注意这是假设正确的数据帧 (df2) 有 NO DUPLICATES 相对于 ['ser', 'no'] 然后是 'left' @987654332 @ 应该产生与左侧数据框 (df) 相同的行数。但它不一定有相同的index。事实证明,在这个例子中确实如此。但我不想冒险。所以我用set_axis

        set_axis(df.index)
      
    3. 最后,由于生成的数据帧与df 具有相同的indexcolumns。我可以用以下方式填充缺失的位:

      fillna(df)
      

    【讨论】:

    • 关于解释 2,AFAIK,左合并以它们在左数据帧中出现的相同顺序返回数据。因此,除非键列中有重复项,否则将获得相同的(范围)索引。
    • 不,我不这么认为。试试:pd.DataFrame({'Col1': 1}, [*'ABC']).merge(pd.DataFrame({'Col1': [1]}), 'left') 它用[0, 1, 2] 替换了我非常好的['A', 'B', 'C'] 索引。对于这个问题,它没有出现。但是 OP 的 实际 数据可能有一个他们想要保留的索引。或者其他任何正在查看问答的人。
    • 我同意,合并总是返回范围索引,这就是 range 在括号中的原因。我试图在df2 上回显重复项。
    • 哦,我明白了。是的。我提到过。我会再强调一点。
    【解决方案2】:

    更新:你要找的是combine_first

    (df2.set_index(['ser','no'])
        .combine_first(df.set_index(['ser','no']))
        .reset_index()
    )
    

    你也可以试试concat,当ser,no是唯一值时,它更类似于'outer'合并。

    pd.concat([df2,df]).groupby(['ser','no'], as_index=False).first()
    

    输出:

       ser  no   c     d
    0    0   0   1   NaN
    1    0   1   1   NaN
    2    0   2   1   NaN
    3    1   0   1   NaN
    4    1   1   1   NaN
    5    1   2  88  90.0
    6    2   0   1   NaN
    7    2   1   1   NaN
    8    2   2   1   NaN
    

    【讨论】:

    • @ALollz 实际上是的。它本身并不是真正的合并。更新中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 2023-03-13
    • 2017-08-13
    • 2018-11-04
    • 1970-01-01
    相关资源
    最近更新 更多