熊猫-按列对多级数据进行排序,但保留级组顺序

时间:2019-01-08 16:20:55

标签: python pandas dataframe

我有一个多级数据框,其中的列名为name。我想维护数据的父子级别分组,但是请按此name列对每个级别A-Z进行排序。

换句话说,对于每一行,如果对父项进行排序,则所有较低级别的子项也将作为一个块进行排序。

以下是我当前数据框的一个示例:

df = pd.DataFrame(columns=['level', 'name'],                        
                  data=[['1','AAA'],                                  
                        ['1.1', 'ZZZ'],                               
                        ['1.2', 'XXX'],                               
                        ['1.3', 'YYY'],                               
                        ['1.3.1', 'GGG'],                             
                        ['1.3.1.1', 'XXX'],                           
                        ['1.3.2', 'EEE'],                             
                        ['1.3.3', 'FFF'],                             
                        ['1.3.3.1', 'TTT'],                           
                        ['1.3.3.2', 'SSS'],                           
                        ['2', 'CCC'],                                 
                        ['3', 'BBB'],                                 
                        ['3.1', 'AAA']])                              

以及排序后的数据框的外观:

sorted_df = pd.DataFrame(columns=['level', 'name'],                 
                  data=[['1','AAA'],           # No Change            
                        ['1.1', 'XXX'],        # Was 1.2              
                        ['1.2', 'YYY'],        # Was 1.3              
                        ['1.2.1', 'EEE'],      # Was 1.3.2            
                        ['1.2.2', 'FFF'],      # Was 1.3.3            
                        ['1.2.3', 'GGG'],      # Was 1.3.1            
                        ['1.2.3.1', 'XXX'],    # Was 1.3.1.1          
                        ['1.2.3.1', 'SSS'],    # Was 1.3.3.2          
                        ['1.2.3.2', 'TTT'],    # was 1.3.3.1          
                        ['1.3', 'ZZZ'],        # Was 1.1              
                        ['2', 'BBB'],          # Was 3                
                        ['2.1', 'AAA'],        # Was 3.1              
                        ['3', 'CCC']])         # Was 2

将其分解为步骤:

  1. 按名称排序最深级别(即X.X.X.X)。在上面的原始DF中,将交换1.3.3.1(SSS)和1.3.3.2(TTT)。 1.3.1.1(XXX)保持不变,因为1.3.1.X组中没有其他项目。

  2. 向上看一级(即X.X.X-GGG,EEE,FFF)。 1.3.1(GGG)及其以下的所有子项(即1.3.1.1),需要移到EEE和FFF(及其子项)以下。 EEE和FFF(及其子代)已经处于正确的位置。

  3. 在下一个级别重复此过程,对父母及其所有子孙进行排序。

我尝试通过用点将级别列拆分来将Dataframe分为多个索引:

df = pd.concat([df['level'].str.split('.', expand=True), df], axis=1) \
      .set_index([0,1,2,3])

一旦达到这一点,我就有点卡住了。我已经尝试过各种方法(sort_valuesort_indexreset_index等),但无法对其进行分类(双关语意)。为了使事情更复杂,'level'可以是我的真实数据的任意长度(例如1.2.2.1.2.3.1 ...),并且name列也可以是任意的(请参阅AAA如何在不同级别重复)示例数据)。

这似乎很简单,但是我花了几个小时进行研究,并竭尽全力试图找出答案。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

尝试使用fillna

df.join(df.level.str.split('.', expand=True).fillna(-1))\
  .sort_values([0,1,2,3])[['level','name']]

输出:

      level name
0         1  AAA
1       1.1  ZZZ
2       1.2  XXX
3       1.3  YYY
4     1.3.1  GGG
5   1.3.1.1  XXX
6     1.3.2  EEE
7     1.3.3  FFF
8   1.3.3.1  TTT
9   1.3.3.2  SSS
10        2  CCC
11        3  BBB
12      3.1  AAA

未知深度:

df.join(df.level.str.split('.', expand=True)).fillna(-1)\
  .pipe(lambda x: x.sort_values(x.filter(regex='\d+').columns.tolist()))[['level','name']]