【问题标题】:Diff of two Dataframes两个数据框的差异
【发布时间】:2023-03-12 14:12:01
【问题描述】:

我需要逐行比较两个不同大小的数据帧并打印出不匹配的行。让我们采取以下两个:

df1 = DataFrame({
'Buyer': ['Carl', 'Carl', 'Carl'],
'Quantity': [18, 3, 5, ]})

df2 = DataFrame({
'Buyer': ['Carl', 'Mark', 'Carl', 'Carl'],
'Quantity': [2, 1, 18, 5]})

在 df2 上逐行并打印出不在 df1 中的行的最有效方法是什么,例如

Buyer     Quantity 
Carl         2
Mark         1

重要提示:我不想排:

Buyer     Quantity 
Carl         3

包含在差异中:

我已经尝试过: Comparing two dataframes of different length row by row and adding columns for each row with equal valueCompare two DataFrames and output their differences side-by-side

但是这些不符合我的问题。

【问题讨论】:

    标签: python pandas dataframe diff


    【解决方案1】:

    merge 2 dfs 使用方法 'outer' 并传递参数 indicator=True 这将告诉您行是否存在于两个/仅左/仅右,然后您可以在之后过滤合并的 df:

    In [22]:
    merged = df1.merge(df2, indicator=True, how='outer')
    merged[merged['_merge'] == 'right_only']
    
    Out[22]:
      Buyer  Quantity      _merge
    3  Carl         2  right_only
    4  Mark         1  right_only
    

    【讨论】:

    • 如果一行在一个数据帧中出现一次,在另一个数据帧中出现两次 - 此方法将无法检测到。理想情况下,其中一个条目应标记为“right_only”,另一个条目应标记为两者。
    【解决方案2】:

    您可能会发现这是最好的:

    df2[ ~df2.isin(df1)].dropna()
    

    【讨论】:

      【解决方案3】:
      diff = set(zip(df2.Buyer, df2.Quantity)) - set(zip(df1.Buyer, df1.Quantity))
      

      这是我想到的第一个解决方案。然后,您可以将 diff 集放回 DF 中进行演示。

      【讨论】:

        【解决方案4】:

        @EdChum 的回答不言自明。但是使用not 'both' 条件更有意义,您不需要关心比较的顺序,这才是真正的 diff 应该是什么。为了回答您的问题:

        merged = df1.merge(df2, indicator=True, how='outer')
        merged.loc = [merged['_merge'] != 'both']
        

        【讨论】:

        • 这是一个完全反连接,OP要求正确的反连接
        • 第二行失败,应该换成:merged.loc[merged['_merge'] != 'both']
        【解决方案5】:

        从 Pandas 1.1.0 开始,有 pandas.DataFrame.compare:

        df1.compare(df2)
        

        https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.compare.html

        【讨论】:

          【解决方案6】:

          如果您只关心将新买家添加到其他 df,请尝试以下操作:

          df_delta=df2[df2['Buyer'].apply(lambda x: x not in df1['Buyer'].values)]
          

          【讨论】:

            【解决方案7】:

            一个重要的边缘案例

            考虑以下情况,您在第二个数据框中有一个额外的重复条目。 ('Carl', 5)

            df1 = DataFrame({ 'Buyer':    ['Carl', 'Carl', 'Carl'],
                              'Quantity': [   18 ,     3 ,     5 ]  })
            
            df2 = DataFrame({ 'Buyer':    ['Carl', 'Mark', 'Carl', 'Carl', 'Carl'],
                              'Quantity': [    2 ,     1 ,    18 ,     5 ,     5 ]  })
            

            EdChum 的回答将为您提供以下信息:

            merged = df1.merge(df2, indicator=True, how='outer')
            print(merged[merged['_merge'] == 'right_only'])
            
              Buyer  Quantity      _merge
            4  Carl         2  right_only
            5  Mark         1  right_only
            

            如您所见,该解决方案忽略了额外的重复值,这取决于您正在做的事情是您想要避免的。

            这是一个更有可能满足您需求的解决方案:

            df1['duplicate_counter'] = df1.groupby(list(df1.columns)).cumcount()
            df2['duplicate_counter'] = df2.groupby(list(df2.columns)).cumcount()
            merged = df1.merge(df2, indicator=True, how='outer')
            merged[merged['_merge'] == 'right_only']
            
              Buyer  Quantity  duplicate_counter      _merge
            3  Carl         2                  0  right_only
            4  Mark         1                  0  right_only
            5  Carl         5                  1  right_only
            

            重复计数器确保每一行都是唯一的,这意味着不会删除重复值。合并后可以删除duplicate_counter。

            【讨论】:

              猜你喜欢
              • 2013-11-23
              • 2021-11-28
              • 2017-07-11
              • 2018-04-18
              • 1970-01-01
              • 1970-01-01
              • 2021-11-25
              • 2018-09-28
              相关资源
              最近更新 更多