【问题标题】:How to split a dataframe based on consecutive index?如何根据连续索引拆分数据框?
【发布时间】:2019-05-22 12:56:02
【问题描述】:

我有一个带有非连续索引的数据框“工作”,这里是一个例子:

Index Column1 Column2
4464  10.5    12.7
4465  11.3    12.8
4466  10.3    22.8
5123  11.3    21.8
5124  10.6    22.4
5323  18.6    23.5

我需要从这个数据帧中提取仅包含索引连续行的新数据帧,所以在这种情况下,我的目标是得到

DF_1.index=[4464,4465,4466]
DF_2.index=[5123,5124]
DF_3.index=[5323]

维护所有列。

谁能帮助我?谢谢!

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    groupby

    你可以用

    制作一个完美的“连续”数组
    np.arange(10)
    
    array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    

    如果我从单调递增的索引中减去它,只有那些“连续”的索引成员才会显示为相等的。这是建立分组依据的一种巧妙方法。

    list_of_df = [d for _, d in df.groupby(df.index - np.arange(len(df)))]
    

    并打印每一个来证明这一点

    print(*list_of_df, sep='\n\n')
    
           Column1  Column2
    Index                  
    4464      10.5     12.7
    4465      11.3     12.8
    4466      10.3     22.8
    
           Column1  Column2
    Index                  
    5123      11.3     21.8
    5124      10.6     22.4
    
           Column1  Column2
    Index                  
    5323      18.6     23.5
    

    np.split

    您可以使用np.flatnonzero 来识别差异不等于1 并避免使用cumsumgroupby

    list_of_df = np.split(df, np.flatnonzero(np.diff(df.index) != 1) + 1)
    

    证明

    print(*list_of_df, sep='\n\n')
    
           Column1  Column2
    Index                  
    4464      10.5     12.7
    4465      11.3     12.8
    4466      10.3     22.8
    
           Column1  Column2
    Index                  
    5123      11.3     21.8
    5124      10.6     22.4
    
           Column1  Column2
    Index                  
    5323      18.6     23.5
    

    【讨论】:

      【解决方案2】:

      这里有一个替代方案:

      grouper = (~(pd.Series(df.index).diff() == 1)).cumsum().values  
      dfs = [dfx for _ , dfx in df.groupby(grouper)]
      

      我们使用连续差 1 等于序列 (diff == 1) 的事实。

      完整示例:

      import pandas as pd
      
      data = '''\
      Index Column1 Column2
      4464  10.5    12.7
      4465  11.3    12.8
      4466  10.3    22.8
      5123  11.3    21.8
      5124  10.6    22.4
      5323  18.6    23.5
      '''
      
      fileobj = pd.compat.StringIO(data)
      df = pd.read_csv(fileobj, sep='\s+', index_col='Index')
      
      non_sequence = pd.Series(df.index).diff() != 1
      grouper = non_sequence.cumsum().values
      dfs = [dfx for _ , dfx in df.groupby(grouper)]
      
      print(dfs[0])
      
      #       Column1  Column2
      #Index                  
      #4464      10.5     12.7
      #4465      11.3     12.8
      #4466      10.3     22.8
      

      另一种看待它的方式是,我们寻找 groupby 的非序列,可能更具可读性:

      non_sequence = pd.Series(df.index).diff() != 1
      grouper = non_sequence.cumsum().values
      dfs = [dfx for _ , dfx in df.groupby(grouper)]
      

      【讨论】:

        【解决方案3】:

        您可以使用 exec 创建多个数据框并获得预期的结果:

        df = pd.DataFrame({'Column1' : [10.5,11.3,10.3,11.3,10.6,18.6], 'Column2' : [10.5,11.3,10.3,11.3,10.6,18.6]})
        df.index = [4464, 4465, 4466, 5123, 5124, 5323]
        
        prev_index = df.index[0]
        df_1 = pd.DataFrame(df.iloc[0]).T
        num_df = 1
        for i in df.index[1:]:
            if i == prev_index+1:
                exec('df_{} = df_{}.append(df.loc[{}])'.format(num_df, num_df, i))
            else :
                num_df += 1
                exec('df_{} = pd.DataFrame(df.loc[{}]).T'.format(num_df, i))
            prev_index = i
        

        【讨论】:

          【解决方案4】:

          也许有一种更优雅的方式来写下来,但这对我有用:

          previous_index = df.index[0]
          groups = {}
          for x in df.index:
              if (x-previous_index) ==1 : 
                  groups[max(groups.keys())].append(x)
              else:
                  groups[len(groups.keys())]=[x]
              previous_index = x
          
          output_dfs = []
          for key, val in groups.items():
              print(key, val)
              output_dfs.append(df[df.index.isin(val)])
          

          您的数据框将存储在output_dfs

          output_dfs[0].index
          

          [4464,4465,4466]

          【讨论】:

          • 对不起,我不明白,如果 'previous_index' 总是 0,那么你永远不应该得到 x-previous_index ==1。我尝试运行你的代码,但我没有得到你的解决方案,因为条件从未得到验证,也许我做错了什么?
          • 其实previous_index在每次迭代结束时都会更新。我将只编辑代码以获取实际值而不是初始任意 0
          猜你喜欢
          • 2018-08-14
          • 1970-01-01
          • 1970-01-01
          • 2018-03-09
          • 2016-05-05
          • 2017-01-19
          • 2022-12-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多