【问题标题】:Compare Multiple Columns to Get Rows that are Different in Two Pandas Dataframes比较多个列以获取两个 Pandas 数据框中不同的行
【发布时间】:2016-02-05 01:46:48
【问题描述】:

我有两个数据框:

df1=
    A    B   C
0   A0   B0  C0
1   A1   B1  C1
2   A2   B2  C2

df2=
    A    B   C
0   A2   B2  C10
1   A1   B3  C11
2   A9   B4  C12

并且我想根据一或两列(或更多列)在 df1 中找到在 df2 中找不到的行。因此,如果我只比较列“A”,则在 df2 中找不到来自 df1 的以下行(请注意,“B”列和“C”列不用于比较 df1 和 df2)

    A    B   C
0   A0   B0  C0

我想返回一个系列

0   False
1   True
2   True

或者,如果我只比较列“A”和列“B”,则在 df2 中找不到来自 df1 的以下行(请注意,列“C”不用于比较 df1 和 df2)

    A    B   C
0   A0   B0  C0
1   A1   B1  C1

我想返回一个系列

0   False
1   False
2   True

我知道如何使用集合来完成此任务,但我正在寻找一种简单的 Pandas 方式来完成此任务。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    理想情况下,希望能够只使用 ~df1[COLS].isin(df2[COLS]) 作为掩码,但这需要索引标签匹配 (https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.isin.html)

    这是一个简洁的形式,它使用 .isin 但将第二个 DataFrame 转换为 dict,以便索引标签不需要匹配:

    COLS = ['A', 'B'] # or whichever columns to use for comparison
    
    df1[~df1[COLS].isin(df2[COLS].to_dict(
        orient='list')).all(axis=1)]
    

    【讨论】:

      【解决方案2】:

      方法(一)


      In [63]:
      df1['A'].isin(df2['A']) & df1['B'].isin(df2['B'])
      Out[63]:
      
      0   False
      1   False
      2   True
      

      方法(二)


      您可以使用左合并获取两个帧中都存在的值+ 仅存在于第一个数据帧中的值

      In [10]:
      left = pd.merge(df1 , df2 , on = ['A' , 'B'] ,how = 'left')
      left
      Out[10]:
          A   B   C_x C_y
      0   A0  B0  C0  NaN
      1   A1  B1  C1  NaN
      2   A2  B2  C2  C10
      

      当然,仅存在于第一帧中的值将在另一个数据帧的列中具有 NAN 值,然后您可以通过执行以下操作按此 NAN 值进行过滤

      In [16]:
      left.loc[pd.isnull(left['C_y']) , 'A':'C_x']
      Out[16]:
          A   B   C_x
      0   A0  B0  C0
      1   A1  B1  C1
      
      In [17]:
      

      如果要获取A 中的值是否存在于B 中,可以执行以下操作

      In [20]:
      pd.notnull(left['C_y'])
      Out[20]:
      0    False
      1    False
      2     True
      Name: C_y, dtype: bool
      

      【讨论】:

      • 我想知道当列越来越多时是否有更好的方法来表示方法#1
      • 在什么方面更好?
      • 代码长度。就目前而言,需要继续添加& 才能添加更多列。如果它可以被包装成一个列表理解(或应用函数)会更好,因为每一列都是独立的
      【解决方案3】:

      如果您的版本是0.17.0,那么您可以使用pd.merge 并传递感兴趣的列、how='left' 并将indicator=True 设置为这些值是仅存在于left 中还是两者都存在。然后您可以测试附加的_merge col 是否等于'both':

      In [102]:
      pd.merge(df1, df2, on='A',how='left', indicator=True)['_merge'] == 'both'
      
      Out[102]:
      0    False
      1     True
      2     True
      Name: _merge, dtype: bool
      
      In [103]:
      pd.merge(df1, df2, on=['A', 'B'],how='left', indicator=True)['_merge'] == 'both'
      
      Out[103]:
      0    False
      1    False
      2     True
      Name: _merge, dtype: bool
      

      合并的输出:

      In [104]:
      pd.merge(df1, df2, on='A',how='left', indicator=True)
      
      Out[104]:
          A B_x C_x  B_y  C_y     _merge
      0  A0  B0  C0  NaN  NaN  left_only
      1  A1  B1  C1   B3  C11       both
      2  A2  B2  C2   B2  C10       both
      
      In [105]:    
      pd.merge(df1, df2, on=['A', 'B'],how='left', indicator=True)
      
      Out[105]:
          A   B C_x  C_y     _merge
      0  A0  B0  C0  NaN  left_only
      1  A1  B1  C1  NaN  left_only
      2  A2  B2  C2  C10       both
      

      【讨论】:

        【解决方案4】:
         ~df1['A'].isin(df2['A'])
        

        应该给你你想要的系列

        df1[ ~df1['A'].isin(df2['A'])]
        

        数据框:

            A   B   C
        0   A0  B0  C0
        

        【讨论】:

        • 那有点复杂。我没有意识到您想动态处理可变数量的列。如果其他人在此之前无法帮助您,我可以稍后再处理
        • 对于不止一列,索引标签也需要匹配 - 所以有点棘手。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多