【问题标题】:Pandas Merge - How to avoid duplicating columnsPandas Merge - 如何避免重复列
【发布时间】:2013-10-08 03:19:32
【问题描述】:

我正在尝试合并两个数据框。每个数据框都有两个索引级别(日期、cusip)。例如,在列中,某些列在两者之间匹配(货币、调整日期)。

按索引合并这些的最佳方法是什么,但不要复制两份货币和调整日期。

每个数据框有 90 列,所以我尽量避免手写所有内容。

df:                 currency  adj_date   data_col1 ...
date        cusip
2012-01-01  XSDP      USD      2012-01-03   0.45
...

df2:                currency  adj_date   data_col2 ...
date        cusip
2012-01-01  XSDP      USD      2012-01-03   0.45
...

如果我这样做:

dfNew = merge(df, df2, left_index=True, right_index=True, how='outer')

我明白了

dfNew:              currency_x  adj_date_x   data_col2 ... currency_y adj_date_y
date        cusip
2012-01-01  XSDP      USD      2012-01-03   0.45             USD         2012-01-03

谢谢! ...

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    您可以计算出仅在一个 DataFrame 中的列,并使用它来选择合并中的列子集。

    cols_to_use = df2.columns.difference(df.columns)
    

    然后执行合并(注意这是一个索引对象,但它有一个方便的tolist() 方法)。

    dfNew = merge(df, df2[cols_to_use], left_index=True, right_index=True, how='outer')
    

    这将避免任何列在合并中发生冲突。

    【讨论】:

    • 如果键是一个列并且它被称为相同的怎么办?第一步将被删除。
    • 由于上述评论的限制,我选择了下面@rprog 的答案
    • 如果键是列,要使用此答案,请将要使用的列转换为列表 (cols_to_use = cols_to_use.tolist()) 并将键列的名称附加到此列表 (cols_to_use.append('key_column_name'))。您还需要将合并从使用 left_indexright_index 更改为使用 on='key_column_name'
    【解决方案2】:

    我在.merge() 中使用suffixes 选项:

    dfNew = df.merge(df2, left_index=True, right_index=True,
                     how='outer', suffixes=('', '_y'))
    dfNew.drop(dfNew.filter(regex='_y$').columns.tolist(),axis=1, inplace=True)
    

    感谢@ijoseph

    【讨论】:

    • 如果它包含filtering 的代码将是一个更有帮助的答案(这相当简单,但查找起来仍然很耗时/容易记住)。即dfNew.drop(list(dfNew.filter(regex='_y$')), axis=1, inplace=True)
    【解决方案3】:

    基于@rprog 的回答,您可以使用负正则表达式将后缀和过滤步骤的各个部分组合成一行:

    dfNew = df.merge(df2, left_index=True, right_index=True,
                 how='outer', suffixes=('', '_DROP')).filter(regex='^(?!.*_DROP)')
    

    或者使用df.join:

    dfNew = df.join(df2, lsuffix="DROP").filter(regex="^(?!.*DROP)")
    

    这里的正则表达式保留所有以单词“DROP”结尾的内容,因此请确保使用列中尚未出现的后缀。

    【讨论】:

      【解决方案4】:

      我是 Pandas 的新手,但我想实现相同的目标,自动避免使用 _x 或 _y 的列名并删除重复数据。我终于通过使用 Stackoverflow 中的 answerone 来做到这一点

      sales.csv

      城市;州;单位 门多西诺;CA;1 丹佛;CO;4 奥斯汀;德克萨斯州;2

      收入.csv

      branch_id;city;revenue;state_id 10;奥斯汀;100;德克萨斯州 20;奥斯汀;83;德克萨斯州 30;奥斯汀;4;德克萨斯州 47;奥斯汀;200;德克萨斯州 20;丹佛;83;CO 30;斯普林菲尔德;4;我

      合并.py 导入熊猫

      def drop_y(df):
          # list comprehension of the cols that end with '_y'
          to_drop = [x for x in df if x.endswith('_y')]
          df.drop(to_drop, axis=1, inplace=True)
      
      
      sales = pandas.read_csv('data/sales.csv', delimiter=';')
      revenue = pandas.read_csv('data/revenue.csv', delimiter=';')
      
      result = pandas.merge(sales, revenue,  how='inner', left_on=['state'], right_on=['state_id'], suffixes=('', '_y'))
      drop_y(result)
      result.to_csv('results/output.csv', index=True, index_label='id', sep=';')
      

      执行合并命令时,我将_x 后缀替换为空字符串,我可以删除以_y 结尾的列

      输出.csv

      id;city;state;units;branch_id;revenue;state_id 0;丹佛;一氧化碳;4;20;83;一氧化碳 1;奥斯汀;TX;2;10;100;TX 2;奥斯汀;TX;2;20;83;TX 3;奥斯汀;TX;2;30;4;TX 4;奥斯汀;TX;2;47;200;TX

      【讨论】:

        【解决方案5】:

        这有点解决问题,但我写了一个基本上处理额外列的函数:

        def merge_fix_cols(df_company,df_product,uniqueID):
            
            df_merged = pd.merge(df_company,
                                 df_product,
                                 how='left',left_on=uniqueID,right_on=uniqueID)    
            for col in df_merged:
                if col.endswith('_x'):
                    df_merged.rename(columns = lambda col:col.rstrip('_x'),inplace=True)
                elif col.endswith('_y'):
                    to_drop = [col for col in df_merged if col.endswith('_y')]
                    df_merged.drop(to_drop,axis=1,inplace=True)
                else:
                    pass
            return df_merged
        

        似乎很适合我的合并!

        【讨论】:

          【解决方案6】:

          您不能先将任一 df 中的列子集化吗?

          [i for i in df.columns if i not in df2.columns]
          
          dfNew = merge(df **[i for i in df.columns if i not in df2.columns]**, df2, left_index=True, right_index=True, how='outer')
          

          【讨论】:

            【解决方案7】:

            当您想要避免的列数低于您想要保留的列数时...您可以使用这种过滤:

            df.loc[:, ~df.columns.isin(['currency', 'adj_date'])]
            

            这将过滤数据框中除“货币”和“adj_date”列之外的所有列,您必须像这样编写合并:

                dfNew = merge(df, 
                              df2.loc[:, ~df.columns.isin(['currency', 'adj_date'])], 
                              left_index=True,
                              right_index=True,
                              how='outer')
            

            注意“~”,表示“不”。

            【讨论】:

              【解决方案8】:

              您可以在要合并的键中包含重复的列,以确保结果中只出现一个副本。

              # Generate some dummy data.
              shared = pd.DataFrame({'key': range(5), 'name': list('abcde')})
              a = shared.copy()
              a['value_a'] = np.random.normal(0, 1, 5)
              b = shared.copy()
              b['value_b'] = np.random.normal(0, 1, 5)
              
              # Standard merge.
              merged = pd.merge(a, b, on='key')
              print(merged.columns)  # Index(['key', 'name_x', 'value_a', 'name_y', 'value_b'], dtype='object')
              
              # Merge with both keys.
              merged = pd.merge(a, b, on=['key', 'name'])
              print(merged.columns)  # Index(['key', 'name', 'value_a', 'value_b'], dtype='object')
              

              此方法还确保出现在两个数据框中的列中的值是一致的(例如,两个列中的货币相同)。如果不是,则相应的行将被删除(如果how = 'inner')或出现缺失值(如果how = 'outer')。

              【讨论】:

                猜你喜欢
                • 2018-09-18
                • 2022-01-08
                • 1970-01-01
                • 2020-06-10
                • 1970-01-01
                • 1970-01-01
                • 2021-11-23
                • 2016-05-17
                • 2017-08-23
                相关资源
                最近更新 更多