【问题标题】:How to subtract rows of one pandas data frame from another?如何从另一个熊猫数据框中减去一行?
【发布时间】:2014-06-10 15:41:34
【问题描述】:

我想做的操作类似于合并。例如,通过inner 合并,我们得到一个数据帧,其中包含第一个和第二个数据帧中存在的行。通过outer 合并,我们得到一个数据帧,它出现在第一个或第二个数据帧中。

我需要一个数据框,其中包含第一个数据框中存在但第二个数据框中不存在的行?有没有一种快速而优雅的方式来做到这一点?

【问题讨论】:

  • 如何='左'?这肯定不是你想要的(考虑到你的 SO 分数,它一定比这更复杂)
  • 左或右合并为我提供了一个数据框,其中包含存在于其中一个数据框中的行。但我需要一个数据帧,其中包含一个数据帧中存在的行而不存在于另一个数据帧中。
  • 如果它只是一个合并键,那么您可以使用 isin~ 来完成
  • 我在对自己笑,实际上是在试图了解如何将某物从 object2 移动到 object1,条件是该东西在对象 1 中,而不是在对象 2 中。对我来说,这听起来就像 object1 - 不需要任何操作!我不认为我明白这一点。忽略我,对不起,它只是让我微笑......
  • @KarlD.,我有多个合并键。

标签: python merge pandas


【解决方案1】:

考虑以下:

  1. df_one 是第一个 DataFrame
  2. df_two 是第二个 DataFrame

存在于第一个数据帧不在第二个数据帧中

解决方案:按索引 df = df_one[~df_one.index.isin(df_two.index)]

index 可以替换为您希望对其进行排除的必需column。 在上面的示例中,我使用索引作为两个数据框之间的参考

此外,您还可以使用更复杂的查询,使用布尔值 pandas.Series 来解决上述问题。

【讨论】:

    【解决方案2】:

    下面这样的怎么样?

    print df1
    
        Team  Year  foo
    0   Hawks  2001    5
    1   Hawks  2004    4
    2    Nets  1987    3
    3    Nets  1988    6
    4    Nets  2001    8
    5    Nets  2000   10
    6    Heat  2004    6
    7  Pacers  2003   12
    
    print df2
    
        Team  Year  foo
    0  Pacers  2003   12
    1    Heat  2004    6
    2    Nets  1988    6
    

    只要有一个非key的通用列,就可以让添加的on后缀来做(如果没有非key的通用列,你可以创建一个临时使用...df1['common'] = 1df2['common'] = 1):

    new = df1.merge(df2,on=['Team','Year'],how='left')
    print new[new.foo_y.isnull()]
    
         Team  Year  foo_x  foo_y
    0  Hawks  2001      5    NaN
    1  Hawks  2004      4    NaN
    2   Nets  1987      3    NaN
    4   Nets  2001      8    NaN
    5   Nets  2000     10    NaN
    

    或者您可以使用isin,但您必须创建一个密钥:

    df1['key'] = df1['Team'] + df1['Year'].astype(str)
    df2['key'] = df1['Team'] + df2['Year'].astype(str)
    print df1[~df1.key.isin(df2.key)]
    
         Team  Year  foo         key
    0   Hawks  2001    5   Hawks2001
    2    Nets  1987    3    Nets1987
    4    Nets  2001    8    Nets2001
    5    Nets  2000   10    Nets2000
    6    Heat  2004    6    Heat2004
    7  Pacers  2003   12  Pacers2003
    

    【讨论】:

      【解决方案3】:

      如果您的非索引列包含带有 NaN 的单元格,您可能会遇到错误。

      print df1
      
          Team   Year  foo
      0   Hawks  2001    5
      1   Hawks  2004    4
      2    Nets  1987    3
      3    Nets  1988    6
      4    Nets  2001    8
      5    Nets  2000   10
      6    Heat  2004    6
      7  Pacers  2003   12
      8 Problem  2112  NaN
      
      
      print df2
      
           Team  Year  foo
      0  Pacers  2003   12
      1    Heat  2004    6
      2    Nets  1988    6
      3 Problem  2112  NaN
      
      new = df1.merge(df2,on=['Team','Year'],how='left')
      print new[new.foo_y.isnull()]
      
           Team  Year  foo_x  foo_y
      0   Hawks  2001      5    NaN
      1   Hawks  2004      4    NaN
      2    Nets  1987      3    NaN
      4    Nets  2001      8    NaN
      5    Nets  2000     10    NaN
      6 Problem  2112    NaN    NaN
      

      2112 年的问题团队在两个表中都没有 foo 的值。因此,此处的左连接将错误地返回在两个 DataFrame 中都匹配的行,因为它不存在于右 DataFrame 中。

      解决方案:

      我所做的是向内部 DataFrame 添加一个唯一列并为所有行设置一个值。然后,当您加入时,您可以检查该列是否为内部表的 NaN 以在外部表中查找唯一记录。

      df2['in_df2']='yes'
      
      print df2
      
           Team  Year  foo  in_df2
      0  Pacers  2003   12     yes
      1    Heat  2004    6     yes
      2    Nets  1988    6     yes
      3 Problem  2112  NaN     yes
      
      
      new = df1.merge(df2,on=['Team','Year'],how='left')
      print new[new.in_df2.isnull()]
      
           Team  Year  foo_x  foo_y  in_df1  in_df2
      0   Hawks  2001      5    NaN     yes     NaN
      1   Hawks  2004      4    NaN     yes     NaN
      2    Nets  1987      3    NaN     yes     NaN
      4    Nets  2001      8    NaN     yes     NaN
      5    Nets  2000     10    NaN     yes     NaN
      

      注意。问题行现在已正确过滤掉,因为它具有 in_df2 的值。

        Problem  2112    NaN    NaN     yes     yes
      

      【讨论】:

        【解决方案4】:

        我建议在合并中使用参数'indicator'。此外,如果“on”为 None,则默认为两个 DataFrame 中列的交集。

        new = df1.merge(df2,how='left', indicator=True) # adds a new column '_merge'
        new = new[(new['_merge']=='left_only')].copy() #rows only in df1 and not df2
        new = new.drop(columns='_merge').copy()
        
            Team    Year    foo
        0   Hawks   2001    5
        1   Hawks   2004    4
        2   Nets    1987    3
        4   Nets    2001    8
        5   Nets    2000    10
        

        参考:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.merge.html

        indicator : boolean or string, default False
        
        If True, adds a column to output DataFrame called “_merge” with information on the source of each row. 
        Information column is Categorical-type and takes on a value of 
        “left_only” for observations whose merge key only appears in ‘left’ DataFrame,
        “right_only” for observations whose merge key only appears in ‘right’ DataFrame, 
        and “both” if the observation’s merge key is found in both.
        

        【讨论】:

          猜你喜欢
          • 2013-12-04
          • 2014-12-28
          • 2019-08-07
          • 2020-12-30
          • 1970-01-01
          • 2013-12-10
          • 2022-10-18
          • 2017-02-20
          相关资源
          最近更新 更多