# 3.2.2:多级索引的数据转换与累计方法 ## 多级索引行列转换 使用多级索引的关键是掌握有效数据转换的方法,`Pandas`提供了许多操作,可以让数据在内容保持不变的同时,按照需要进行行列转换。上一关我们用`stack()`和`unstack()`演示过简单的行列转换,但其实还有许多合理控制层级行列索引的方法,让我们来一探究竟。 1. 有序和无序的索引 如果`MultiIndex`不是有序的索引,那么大多数切片操作都会失败,如下例: ```python # 首先创建一个不按字典顺序排列的多级索引Series index = pd.MultiIndex.from_product([['a', 'c', 'b'], [1, 2]]) data = pd.Series(np.random.rand(6), index=index) data.index.names = ['char', 'int'] data Out: char int a 1 0.003001 2 0.164974 c 1 0.741650 2 0.569264 b 1 0.001693 2 0.526226 dtype: float64 # 如果对该多级索引使用局部切片,就会报错 try: data['a':'b'] except KeyError as e: print(type(e)) print(e) Out: 'Key length (1) was greater than MultiIndex lexsort depth (0)' ``` 问题是出在`MultiIndex`无序排列上,局部切片和许多其他相似的操作都要求`MultiIndex`的各级索引是有序的。为此,`Pandas`提供了许多便捷的操作完成排序,如`sort_index()`和`sortlevel()`方法。 ```python data = data.sort_index() data["a":"b"] Out: char int a 1 0.003001 2 0.164974 b 1 0.001693 2 0.526226 dtype: float64 ``` 2. 索引stack与unstack 上一节提过,我们可以将一个多级索引数据集转换成简单的二维形式,可以通过`level`参数设置转换的索引层级。 ```python pop Out: state year California 2000 33871648 2010 37253956 New York 2000 18976457 2010 19378102 Texas 2000 20851820 2010 25145561 dtype: int64 # level=0 pop.unstack(level=0) Out: state California New York Texas year 2000 33871648 18976457 20851820 2010 37253956 19378102 2514556 # level=1 pop.unstack(level=1) Out: year 2000 2010 state California 33871648 37253956 New York 18976457 19378102 Texas 20851820 25145561 ``` `unstack()`是`stack()`的逆操作,同时使用这两种方法`(pop.unstack().stack())`让数据保持不变。 3. 索引的设置与重置 层级数据维度转换的另一种方法是行列标签转换,可以通过`reset_index`方法实现。也可以用数据的`name`属性为列设置名称: ```python pop_flat = pop.reset_index(name='population') pop_flat Out: state year population 0 California 2000 33871648 1 California 2010 37253956 2 New York 2000 18976457 3 New York 2010 19378102 4 Texas 2000 20851820 5 Texas 2010 25145561 ``` 在解决实际问题的时候,可以使用`DataFrame`的`set_index`方法将类似这样的原始输入数据的列直接转换成`MultiIndex`,返回结果就会是一个带多级索引的`DataFrame`。 ```python pop_flat.set_index(['state', 'year']) Out: population state year California 2000 33871648 2010 37253956 New York 2000 18976457 2010 19378102 Texas 2000 20851820 2010 25145561 ``` ## 多级索引的数据累计方法 `Pandas`有一些自带的数据累计方法,比如`mean()`、`sum()`和`max()`。而对于层级索引数据,可以设置参数`level`实现对数据子集的累计操作。以体检数据为例: ```python health_data Out: subject Bob Guido Sue type HR Temp HR Temp HR Temp year visit 2013 1 31.0 38.7 32.0 36.7 35.0 37.2 2 44.0 37.7 50.0 35.0 29.0 36.7 2014 1 30.0 37.4 39.0 37.8 61.0 36.9 2 47.0 37.8 48.0 37.3 51.0 36.5 ``` 如果你需要计算每一年各项指标的平均值,那么可以将参数`level`设置为索引`year`: ```python data_mean = health_data.mean(level='year') data_mean Out: subject Bob Guido Sue type HR Temp HR Temp HR Temp year 2013 37.5 38.2 41.0 35.85 32.0 36.95 2014 38.5 37.6 43.5 37.55 56.0 36.70 ``` 如果再设置`axis`参数,就可以对列索引进行类似的累计操作了: ```python data_mean.mean(axis=1, level='type') Out: type HR Temp year 2013 36.833333 37.000000 2014 46.000000 37.283333 ```