使用自定义排序在Python中切割多索引标头数据框

时间:2016-03-20 09:08:31

标签: python python-3.x numpy pandas dataframe

我试图解决切片问题。我有以下数据框,df:

    Feeder # 1                               Feeder # 2
    TimeStamp   MW     Month   Day   Hour    TimeStamp      MW     Month     Day    Hour
0   2/3         1.2    1       30    22        2/3          2.4    1         30     22 
1   2/4         2.3    1       31    23        2/3          4.1    1         31     23
2   2/5         3.4    2       1     0         2/3          3.7    2         1      0

共有8个馈线。

如果我想在所有Feeders中选择所有MW列,我可以这样做:

df.xs('MW', level=1, axis=1,drop_level=False)

如果我想要2号到4号馈线,我可以这样做:

df.loc[:,'Feeder #2':'Feeder #4']

但是如果我想通过以下方式在Feed 2到4中通过日期列出MW:

df.loc[:,pd.IndexSlice['Feeder #2':'Feeder #4','MW':'Day']]

我收到以下错误。

MultiIndex Slicing requires the index to be fully lexsorted tuple len (2), lexsort depth (1)

因此,如果我对数据框进行排序,那么我就能做到:

df.sortlevel(level=0,axis=1).loc[:,pd.IndexSlice['Feeder #2':'Feeder #4','Day':'MW']]

但是对数据帧进行排序会破坏标题中级别1的原始顺序 - 所有内容都按字母顺序排列(在Python中使用lexsorted?)?我想要的内容混乱:'Day':'MW'会产生DayHourMW列。但我想要的是'MW':'Day',它会产生MWMonthDay列。

所以我的问题是:是否可以切换我的数据帧并保留列的顺序?或者,我可以lexsort数据帧,执行我需要的切片,然后将数据帧恢复原来的顺序吗?

提前致谢。

1 个答案:

答案 0 :(得分:0)

我认为您可以使用CategoricalIndex来保持订单:

import pandas as pd
import numpy as np

level0 = "Feeder#1 Feeder#2 Feeder#3 Feeder#4".split()
level1 = "TimeStamp   MW     Month   Day   Hour".split()

idx0 = pd.CategoricalIndex(level0, level0, ordered=True)
idx1 = pd.CategoricalIndex(level1, level1, ordered=True)

columns = pd.MultiIndex.from_product([idx0, idx1])

df = pd.DataFrame(np.random.randint(0, 10, (10, 20)), columns=columns)

然后你可以这样做:

df.loc[:, pd.IndexSlice["Feeder#2":"Feeder#3", "MW":"Day"]]

修改

将级别转换为CategoricalIndex

columns = df.columns
for i in range(columns.nlevels):
    level = pd.unique(columns.get_level_values(i))
    cidx = pd.CategoricalIndex(level, level, sorted=True)
    print(cidx)