我有一个多级数据框,其中的列名为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
将其分解为步骤:
按名称排序最深级别(即X.X.X.X)。在上面的原始DF中,将交换1.3.3.1(SSS)和1.3.3.2(TTT)。 1.3.1.1(XXX)保持不变,因为1.3.1.X组中没有其他项目。
向上看一级(即X.X.X-GGG,EEE,FFF)。 1.3.1(GGG)及其以下的所有子项(即1.3.1.1),需要移到EEE和FFF(及其子项)以下。 EEE和FFF(及其子代)已经处于正确的位置。
在下一个级别重复此过程,对父母及其所有子孙进行排序。
我尝试通过用点将级别列拆分来将Dataframe分为多个索引:
df = pd.concat([df['level'].str.split('.', expand=True), df], axis=1) \
.set_index([0,1,2,3])
一旦达到这一点,我就有点卡住了。我已经尝试过各种方法(sort_value
,sort_index
,reset_index
等),但无法对其进行分类(双关语意)。为了使事情更复杂,'level'
可以是我的真实数据的任意长度(例如1.2.2.1.2.3.1 ...),并且name列也可以是任意的(请参阅AAA如何在不同级别重复)示例数据)。
这似乎很简单,但是我花了几个小时进行研究,并竭尽全力试图找出答案。任何帮助将不胜感激!
答案 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']]