【问题标题】:pandas concat DataFrame on different Index不同索引上的 pandas concat DataFrame
【发布时间】:2015-01-14 19:56:43
【问题描述】:

一般问题

我有一个pandas.DataFrame 的任意列表(让我们使用 2 来保持示例清晰),我想在 Indexconcat 他们:

  1. 既不是inner 也不是现有DataFramesouter 连接
  2. 是一个不同的、独立的Index,但在所有DataFrame 中都有日期

例如,取以下 2 个DataFrame 的(注意Index 形状的区别):

In [01]: d1 = pandas.DataFrame( numpy.random.randn(15, 4), 
                                columns = ['a', 'b', 'c', 'd'], 
                                index = pandas.DatetimeIndex(start = '01/01/2001', 
                                                             freq = 'b', 
                                                             periods = 15)
          )

In [02]: d2 = pandas.DataFrame( numpy.random.randn(17, 4), 
                                columns = ['e', 'f', 'g', 'h'], 
                                index = pandas.DatetimeIndex(start = '01/05/2001', 
                                                             freq = 'b', 
                                                             periods = 17)
          )

我想将这两个DataFrame 加入到相交的Index 上,例如my_index,在这里构造:

In [03]: ind = range(0, 10, 2)
In [04]: my_index = d2.index[ind].copy()

所以下面的结果应该和下面的结果一样:

In [05]: d1.loc[my_index, :].join(d2.loc[my_index, :] )
Out[65]: 
               a         b         c         d         e         f  \
2001-01-05  1.702556 -0.885554  0.766257 -0.731700 -1.071232  1.806680   
2001-01-09 -0.968689 -0.700311  1.024988 -0.705764  0.804285 -0.337177   
2001-01-11  1.249893 -0.613356  1.975736 -0.093838  0.428004  0.634204   
2001-01-15  0.430000  0.502100  0.194092  0.588685 -0.507332  1.404635   
2001-01-17  1.005721  0.604771 -2.296667  0.157201  1.583537  1.359332   

               g         h  
2001-01-05 -1.183528  1.260880  
2001-01-09  0.352487  0.700853  
2001-01-11  1.060694  0.040667  
2001-01-15 -0.044510  0.565152  
2001-01-17 -0.731624 -0.331027  

个人考虑

因为这是一个更大的应用程序,我将有任意数量的DataFrame 我想要:

  1. 使用现有的 pandas 功能而不是构建我自己的 hack,即 reduce( map ( ) ) 等。
  2. 返回 DataFrame 的交叉点的视图,而不是创建 DataFrame 的副本

【问题讨论】:

    标签: python pandas merge concat


    【解决方案1】:

    我认为没有现成的 Pandas 功能可以做到这一点。 但是,构建自己的并不难:

    def select_join(dfs, index):
        result = dfs[0].reindex(index)
        for df in dfs[1:]:
            result = result.join(df, how='inner')
        return result
    

    例如,

    import numpy as np
    import pandas as pd
    import string
    import itertools as IT
    
    columns = iter(string.letters)
    dfs = []
    for i in range(3):
        d1 = pd.DataFrame( np.random.randn(15, 4), 
                               columns = list(IT.islice(columns, 4)), 
                               index = pd.DatetimeIndex(start = '01/01/2001', 
                                                        freq = 'b', 
                                                        periods = 15))
        dfs.append(d1)
    
    ind = range(0, 10, 2)
    my_index = d1.index[ind].copy()
    print(select_join(dfs, my_index))
    

    产量

                       a         b         c         d         e         f  \
    2001-01-01  0.228430 -1.154375 -0.612703 -2.760826 -0.877355 -0.071581   
    2001-01-03  1.452750  1.341027  0.051486  1.231563  0.428353  1.320172   
    2001-01-05 -0.966979 -1.997200 -0.376060 -0.692346 -1.689897  0.549653   
    2001-01-09 -0.117443 -0.888103  2.092829 -0.467220 -1.083004 -1.443015   
    2001-01-11 -0.168980 -0.152663  0.365618  0.444175 -1.472091 -0.578182   
    
                       g         h         i         j         k         l  
    2001-01-01 -0.098758  0.920457 -1.072377 -0.627720  0.223060  0.903130  
    2001-01-03  1.962124  1.134501 -0.209813 -2.309090  0.358121  0.655156  
    2001-01-05  1.088195 -1.705393 -0.161167 -0.339617  0.945495  0.220701  
    2001-01-09  0.970829  1.931192  0.943150 -1.895580  0.815188 -1.485206  
    2001-01-11  0.747193 -1.221069 -0.164531 -0.395197 -0.754051  0.922090  
    

    关于第二个考虑:如果index返回视图是不可能的 是任意的。 DataFrame 将数据(类似 dtype)存储在 NumPy 数组中。什么时候 您从 NumPy 数组中选择任意行,为新数组分配空间 并将行从原始数组复制到新数组中。只有当 选择可以表示为基本切片是返回的视图。这个 NumPy 的限制——一个很难消除的限制! ——冒泡进入 Pandas,当索引不能表示为时,导致 DataFrames 返回副本 一个基本切片。

    【讨论】:

    • 真的很惊讶没有开箱即用的功能(因为它似乎是微不足道的用例)。在我进行 RTD 之前,我认为 concat( [df_1, df_2], join_axes = my_axis) 是我正在寻找的特定功能,但是,您肯定会知道!感谢@unutbu 的回复!
    • 为了完整起见,我能想到的最快实现是:def join_on_index(df_list, index): return pandas.concat( map( lambda x: x.reindex(index), df_list), axis = 1)
    • 有趣!随意将其发布为答案(如果您发现这是最好的解决方案,请接受它。)我选择避免concat 的原因是因为它can raise an error 如果索引包含重复项而join 不包含重复项。
    • 那么也许我会把它作为完整的答案发布,但我肯定接受你的作为正确答案:-)
    【解决方案2】:

    不同的方法及其时间(为了完整性)

    我已接受 @unutbu 的回答,但我认为展示我创建的两个函数(和 @unutbu 的)及其不同的 %timeitvalues 可能很有价值,以防有人想使用它:

    创建df_listmy_index

    dfs = []
    for i in range(5):
        tmp = pandas.DataFrame( numpy.random.randn(1000, 4), 
                                columns = list(itertools.islice(columns, 4)), 
                                index = pandas.DatetimeIndex(start = '01/01/2000', 
                                                             freq = 'b', 
                                                             periods = 1000)
        )
    
        dfs.append(tmp)
    
    ind = range(0, 1000, 2)
    my_index = tmp.index[ind].copy()
    

    3 种不同的实现

    def join_on_index_a(df_list, index):
        return pandas.concat( 
                              map( lambda x: x.reindex(index), df_list), 
                              axis = 1
        )
    
    #@unutbu's implementation
    def join_on_index_b(df_list, index):
        result = dfs[0].reindex(index)
        for df in dfs[1:]:
            result = result.join(df, how='inner')
        return result
    
    def join_on_index_c(df_list, index):
        return pandas.concat( map( lambda x: x.loc[index, :], df_list), axis = 1)
    

    使用 iPython 的结果%timeit

    In [49]: %timeit join_on_index_a(dfs, my_index)
    1000 loops, best of 3: 1.85 ms per loop
    
    In [50]: %timeit join_on_index_b(dfs, my_index)
    100 loops, best of 3: 1.94 ms per loop
    
    In [51]: %timeit join_on_index_c(dfs, my_index)
    100 loops, best of 3: 21.5 ms per loop
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-22
      • 2016-02-17
      • 2016-08-23
      • 1970-01-01
      • 2016-11-06
      • 1970-01-01
      • 2019-04-13
      • 2018-06-18
      相关资源
      最近更新 更多