dataframe 中的多层索引

本文介绍了如何在Python pandas库中使用多层索引,包括DataFrame和Series的索引操作,如排序、显式和隐式切片,以及pd.IndexSlice、pd.xs()和索引转换技巧。涵盖了索引转换、命名、取值、列转行和行转列等实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、生成两层行索引、列索引的样本数据

1)生成 DataFrame

import pandas as pd
import numpy as np

pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)

df = pd.DataFrame(np.random.randint(80,150,size=(9, 9)),
				  columns=pd.MultiIndex.from_product([['last year', 'this year', 'next year'],['price', 'height', 'weight']]), 
				  index=pd.MultiIndex.from_product([['xiaoming', 'lili', 'xiaohong'],['chicken', 'dog', 'cat']]))
df
Out[67]:
                 last year               this year               next year              
                     price height weight     price height weight     price height weight
xiaoming chicken       148    137    121       119     95     98        90    118    110
         dog            88    143    117       100     86     95        82    122    142
         cat           120     93    145       137    148    136       110     99     88
lili     chicken       146     86     90        91    116    134       124    116     94
         dog           103    144    141       131    104    108        90     87    121
         cat           120    119     88       102    129    113       131    118     98
xiaohong chicken       132    146    103       128     98    143       126     81    136
         dog           129     92     99       103     84    116        99    100     85
         cat           131    125    129       146    104    119       135    115    117

2)生成 Series

ser = pd.Series(np.random.randint(0,150,size=6),
			    index=pd.MultiIndex.from_product([['xiaoming', 'lili'],['chicken', 'dog', 'cat']]))
ser
Out[23]: 
xiaoming  chicken    135
          dog         94
          cat         74
lili      chicken     24
          dog        142
          cat          4
dtype: int32

2、索引使用总体原则

1)在进行多重索引操作之前要对索引进行排序

df2 = df.sort_index()
df2
Out[16]: 
                 last year               this year               next year              
                     price height weight     price height weight     price height weight
lili     cat           120    119     88       102    129    113       131    118     98
         chicken       146     86     90        91    116    134       124    116     94
         dog           103    144    141       131    104    108        90     87    121
xiaohong cat           131    125    129       146    104    119       135    115    117
         chicken       132    146    103       128     98    143       126     81    136
         dog           129     92     99       103     84    116        99    100     85
xiaoming cat           120     93    145       137    148    136       110     99     88
         chicken       148    137    121       119     95     98        90    118    110
         dog            88    143    117       100     86     95        82    122    142

2)索引的顺序一般是先外层,再内层

3、 索引与切片 —— Series

1)显式

从最外层开始索引, 不能直接索引最内侧层索引。

ser['lili', 'dog']
Out[27]: 142

或者

ser.loc['lili', :]
Out[28]: 
chicken     24
dog        142
cat          4
dtype: int32

2)隐式

不区分层级索引。

ser.iloc[[1,3,4]]
Out[29]: 
xiaoming  dog         94
lili      chicken     24
          dog        142
dtype: int32

4、索引与切片 —— DataFrame

1)列索引:直接用列名索引

# 以下几种用法,效果相同
df['last year']['price']

df['last year', 'price']

df[('last year', 'price')]

df.iloc[:, 0]
Out[30]:
lili      cat        120
          chicken    146
          dog        103
xiaohong  cat        131
          chicken    132
          dog        129
xiaoming  cat        120
          chicken    148
          dog         88
Name: (last year, price), dtype: int32

2)列切片

# 显式
df.loc[:, 'this year']

# 隐式
df.iloc[:, 3:6]
Out[45]:
                 this year              
                     price height weight
lili     cat           109    138     91
         chicken       106    111    103
         dog           119    106     84
xiaohong cat           112    125    135
         chicken       119     85    129
         dog           114     90    102
xiaoming cat           111    117     89
         chicken        95     99    113
         dog           135     90    136

3)行索引

#外层[ ] 表示返回原数据类型(df),否则返回 series
# 显式
df.loc[[('lili', 'dog')]]

# 隐式
df.iloc[[0]]
Out[31]:
         last year               this year              
             price height weight     price height weight
lili dog       140    147     92       135     92     94

4)行切片

df.loc['lili':'xiaohong']
Out[32]:
                 last year               this year               next year              
                     price height weight     price height weight     price height weight
lili     cat           120    121    106       109    138     91        85    111    114
         chicken       117    124     93       106    111    103       133    115    140
         dog           107    112    141       119    106     84       138    119     93
xiaohong cat           102     93     80       112    125    135       101    115     94
         chicken        83    107     86       119     85    129        85    127    139
         dog           116    110    103       114     90    102        90    130    117

5、pd.IndexSlice 的用法

多层索引的切片,跟单层索引的不大一样,比如:

In[45]:  df.loc[[:, 'dog'], [:, 'price']]

  File "<ipython-input-117-9275508ae997>", line 1
    df.loc[[:, 'dog'], [:, 'price']]
            ^
SyntaxError: invalid syntax

此时需要用 IndexSlice 实现单层索引的使用习惯。

In[46]:  
idx = pd.IndexSlice
df.loc[idx[:, 'dog'], idx[:, 'price']]

Out[46]:
             last year this year next year
                 price     price     price
lili     dog       107       119       138
xiaohong dog       116       114        90
xiaoming dog       115       135        83

6、pd.xs() 的索引与切片

优点:pd.xs() 能跳过最外层索引,直接从指定层按索引取数据。
缺点
1)不能通过它进行值的设定。
2)同一级别只能索引单值。

pd.xs() 的语法是

DataFrame.xs(key, axis=0, level=None, drop_level=True)

其中:
key : label 或 tuple 类型的 label
axis : {0 或 ‘index’, 1 或 ‘columns’}, 默认 0
level : 索引所在的层级,默认为前n层(n=1或len(key)),如果 key 部分包含在多索引中,请指示在哪个层级上使用。层级可以通过 label 或 position来引用。
drop_level : bool, 默认True。如果为False,返回与自己级别相同的对象。

返回:
在原始 Series 或者 DataFrame 中按指定索引得到的横截面数据 (也是 Series 或者 DataFrame 类型)
# 基本使用方法
In[137]: df.xs(('xiaoming', 'cat))

Out[137]: 
last year  price     115
           height    134
           weight    100
this year  price     111
           height    117
           weight     89
next year  price     133
           height     85
           weight     83
Name: (xiaoming, cat), dtype: int32
# 同一级别只能索引单值,索引多值会报错
In[46]: df.xs(('xiaoming', 'lili'))

KeyError: ('xiaoming', 'lili')
# 取出所有行索引含 'cat' 的数据
In[47]: df.xs('cat', axis=0, level=1)

Out[47]:
         last year               this year               next year              
             price height weight     price height weight     price height weight
lili           107    112    141       119    106     84       138    119     93
xiaohong       116    110    103       114     90    102        90    130    117
xiaoming       115    140    121       135     90    136        83     88    127
# 取出所有行索引含 'cat' ,列索引含 'height' 的数据
In[130]: df.xs('cat', axis=0, level=1).xs('height', axis=1, level=1)
Out[130]: 
          last year  this year  next year
lili            121        138        111
xiaohong         93        125        115
xiaoming        134        117         85

7、索引转换

列索引转成行索引,用参数 level 指定要转的索引层级,默认是最内层。
df.stack()

行索引转成列索引,用参数 level 指定要转的索引层级,默认是最内层。
df.unstack()

相关应用有

1)Series 转 DataFrame

In[131]: ser.unstack()

Out[131]: 
          cat  chicken  dog
lili        4       24  142
xiaoming   74      135   94

2)DataFrame 转 Series

In[136]: df.stack().stack()

Out[136]:
lili      cat  height  last year    121
                       next year    111
                       this year    138
               price   last year    120
                       next year     85
                                   ... 
xiaoming  dog  price   next year     83
                       this year    135
               weight  last year    121
                       next year    127
                       this year    136
Length: 81, dtype: int32

3)多层索引转单层索引

In[146]: df.stack().stack().reset_index()

Out[146]: 
     level_0 level_1 level_2    level_3    0
0       lili     cat  height  last year  121
1       lili     cat  height  next year  111
2       lili     cat  height  this year  138
3       lili     cat   price  last year  120
4       lili     cat   price  next year   85
..       ...     ...     ...        ...  ...
76  xiaoming     dog   price  next year   83
77  xiaoming     dog   price  this year  135
78  xiaoming     dog  weight  last year  121
79  xiaoming     dog  weight  next year  127
80  xiaoming     dog  weight  this year  136

4)多层索引在不同轴上的转换

# 最外层的列索引转到行索引
In[156]:  df.stack(level=0)

Out[156]: 
                            height  price  weight
lili     cat     last year     121    120     106
                 next year     111     85     114
                 this year     138    109      91
         chicken last year     124    117      93
                 next year     115    133     140
                 this year     111    106     103
         dog     last year     112    107     141
                 next year     119    138      93
                 this year     106    119      84
xiaohong cat     last year      93    102      80
                 next year     115    101      94
                 this year     125    112     135
...
# 最外层的行索引转到列索引上
In[159]: df.unstack(level=0)

Out[159]: 
        last year                                    ... next year                                  
            price                   height           ...    height          weight                  
             lili xiaohong xiaoming   lili xiaohong  ...  xiaohong xiaoming   lili xiaohong xiaoming
cat           120      102      115    121       93  ...       115       85    114       94       83
chicken       117       83      138    124      107  ...       127       89    140      139      149
dog           107      116      115    112      110  ...       130       88     93      117      127
[3 rows x 27 columns]

5)多层索引在同一个轴内的转换

df.swaplevel(axis=0)

Out[148]: 
                 last year               this year               next year              
                     price height weight     price height weight     price height weight
cat     lili           120    121    106       109    138     91        85    111    114
chicken lili           117    124     93       106    111    103       133    115    140
dog     lili           107    112    141       119    106     84       138    119     93
cat     xiaohong       102     93     80       112    125    135       101    115     94
chicken xiaohong        83    107     86       119     85    129        85    127    139
dog     xiaohong       116    110    103       114     90    102        90    130    117
cat     xiaoming       115    134    100       111    117     89       133     85     83
chicken xiaoming       138     96     82        95     99    113        99     89    149
dog     xiaoming       115    140    121       135     90    136        83     88    127
df.swaplevel(axis=1)

Out[150]: 
                     price    height    weight     price    height    weight     price    height    weight
                 last year last year last year this year this year this year next year next year next year
lili     cat           120       121       106       109       138        91        85       111       114
         chicken       117       124        93       106       111       103       133       115       140
         dog           107       112       141       119       106        84       138       119        93
xiaohong cat           102        93        80       112       125       135       101       115        94
         chicken        83       107        86       119        85       129        85       127       139
         dog           116       110       103       114        90       102        90       130       117
xiaoming cat           115       134       100       111       117        89       133        85        83
         chicken       138        96        82        95        99       113        99        89       149
         dog           115       140       121       135        90       136        83        88       127

8、对索引的操作

1)给索引起名

In[151]: df.index.names
Out[151]: FrozenList([None, None])

In[152]:
df.index.names = ['puple', 'animal']
df

Out[152]: 
Out[165]: 
                 last year               this year               next year              
                     price height weight     price height weight     price height weight
puple    animal                                                                         
lili     cat           120    121    106       109    138     91        85    111    114
         chicken       117    124     93       106    111    103       133    115    140
         dog           107    112    141       119    106     84       138    119     93
xiaohong cat           102     93     80       112    125    135       101    115     94
         chicken        83    107     86       119     85    129        85    127    139
         dog           116    110    103       114     90    102        90    130    117
xiaoming cat           115    134    100       111    117     89       133     85     83
         chicken       138     96     82        95     99    113        99     89    149
         dog           115    140    121       135     90    136        83     88    127

2)取指定层级的索引值

In[160]: df.index.get_level_values(0)
或者
In[160]: df.index.get_level_values('')

Out[160]: Index(['lili', 'lili', 'lili', 'xiaohong', 'xiaohong', 'xiaohong', 'xiaoming', 'xiaoming', 'xiaoming'], dtype='object')

3)索引排序

# 将第二层列索引按降序排列
In[166]: df.sort_index(axis=1, level=1, ascending=False)

Out[166]: 
                 this year next year last year this year next year last year this year next year last year
                    weight    weight    weight     price     price     price    height    height    height
puple    animal                                                                                           
lili     cat            91       114       106       109        85       120       138       111       121
         chicken       103       140        93       106       133       117       111       115       124
         dog            84        93       141       119       138       107       106       119       112
xiaohong cat           135        94        80       112       101       102       125       115        93
         chicken       129       139        86       119        85        83        85       127       107
         dog           102       117       103       114        90       116        90       130       110
xiaoming cat            89        83       100       111       133       115       117        85       134
         chicken       113       149        82        95        99       138        99        89        96
         dog           136       127       121       135        83       115        90        88       140

参考资料:

1、【数据分析day03】pandas“层次化索引对象”的多层索引,切片,stack
2、DataFrame多重索引
3、python Dataframe多索引切片操作 行多层索引
4、python pandas DataFrame.xs用法及代码示例
5、MultiIndex / advanced indexing
6、pandas.DataFrame.xs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值