学科分类
目录
数据分析

认识层次化索引

前面所涉及的Pandas对象都只有一层索引结构(行索引、列索引),又称为单层索引,层次化索引可以理解为单层索引的延伸,即在一个轴方向上具有多层索引。

对于两层索引结构来说,它可以分为内层索引和外层索引。以某些省市的面积表格为例,我们来认识一下什么是层次化索引,具体如图1所示。

img

图1 层次化索引图示

在图1中,按照从左往右的顺序,位于最左边的一列是省的名称,表示外层索引,位于中间的一列是城市的名称,表示内层索引,位于最右边的一列是面积大小,表示数据。

Series和DataFrame均可以实现层次化索引,最常见的方式是在构造方法的index参数中传入一个嵌套列表。接下来,以图1为例,创建具有两层索引结构的Series和DataFrame对象,具体如下:

(1)创建具有两层索引结构的Series对象,具体代码如下。

 In [65]: import numpy as np
          import pandas as pd
          mulitindex_series = pd.Series([15848,13472,12073.8,7813,7446,6444,15230,8269],
                                        index=[['河北省','河北省','河北省','河北省',
                                                '河南省','河南省','河南省','河南省'],
                                               ['石家庄市','唐山市','邯郸市','秦皇岛市',
                                                '郑州市','开封市','洛阳市','新乡市']])
          mulitindex_series

 Out[65]:
 河北省 石家庄市  15848.0
       唐山市   13472.0
       邯郸市   12073.8
       秦皇岛市  7813.0
 河南省 郑州市   7446.0
       开封市   6444.0
       洛阳市   15230.0
       新乡市   8269.0

上述示例中,在使用构造方法创建Series对象时,index参数接收了一个嵌套列表来设置索引的层级,其中,嵌套的第一个列表会作为外层索引,而嵌套的第二个列表会作为内层索引。

从输出结果看出,创建了一个跟图3-6一样的Series对象。

(2)创建具有两层索引结构的DataFrame对象,具体代码如下。

 In [66]: import pandas as pd
          from pandas import DataFrame, Series
          # 占地面积为增加的列索引
          mulitindex_df = DataFrame({'占地面积':[15848, 13472, 12073.8, 
                                             7813, 7446, 6444, 15230, 8269]},
                                    index=[['河北省','河北省','河北省','河北省',
                                            '河南省','河南省','河南省','河南省'],
                                           ['石家庄市','唐山市','邯郸市','秦皇岛市',
                                            '郑州市','开封市','洛阳市','新乡市']])
         mulitindex_df

 Out[66]:
​             占地面积
河北省 石家庄市  15848.0
​     唐山市  13472.0
​     邯郸市  12073.8
​     秦皇岛市   7813.0
河南省 郑州市  7446.0
​     开封市  6444.0
​     洛阳市  15230.0
​     新乡市  8269.0

使用DataFrame生成层次化索引的方式与Series生成层次化索引的方式大致相同,都是对参数index进行设置。

需要注意的是,在创建层次化索引对象时,嵌套函数中两个列表的长度必须是保持一致的,否则将会出现ValueError错误。

除了使用嵌套列表创建多层索引以外,还可以通过MultiIndex类的方法构建一个层次化索引。MultiIndex类提供了3种创建层次化索引的方法,具体如下:

  • MultiIndex.from_tuples():将元组列表转换为MultiIndex。

  • MultiIndex.from_arrays():将数组列表转换为MultiIndex。

  • MultiIndex.from_product():从多个集合的笛卡尔乘积中创建一个MultiIndex。

使用上面的任一种方法,都可以返回一个MultiIndex类对象。在MultiIndex类对象中有三个比较重要的属性,分别是levels、labels和names,其中,levels表示每个级别的唯一标签,labels表示每一个索引列中每个元素在levels中对应的第几个元素,names可以设置索引等级名称。

为了让读者更好地理解,接下来,分别使用上面介绍的三种方法来创建MultiIndex对象,具体内容如下。

1. 通过from_tuples()方法创建MultiIndex对象

from_tuples()方法可以将包含若干个元组的列表转换为MultiIndex对象,其中元组的第一个元素作为外层索引,元组的第二个元素作为内层索引,示例代码如下。

In [67]: from pandas import MultiIndex
         # 创建包含多个元组的列表
         list_tuples = [('A','A1'), ('A','A2'), ('B','B1'),('B','B2'), ('B','B3')]
         # 根据元组列表创建一个MultiIndex对象
         multi_index = MultiIndex.from_tuples(tuples=list_tuples, 
                                              names=[ '外层索引', '内层索引'])
         multi_index
Out[67]: 
MultiIndex(levels=[['A', 'B'], ['A1', 'A2', 'B1', 'B2', 'B3']],
           labels=[[0, 0, 1, 1, 1], [0, 1, 2, 3, 4]],
           names=['外层索引', '内层索引'])

上述示例中,通过from_tuples()方法创建了一个MultiIndex对象,其中,传入的tuples参数是一个包含多个元组的列表,这表示元组的第一个元素会是外层索引,第二个元素会是内层索引,传入的names参数是一个包含两个字符串的列表,代表着两层索引的名称。

接下来,创建一个DataFrame对象,把刚刚创建的multi_index传递给index参数,让该对象具有两层索引结构,示例代码如下。

In [68]: # 导入所需要的包
        import pandas as pd
        values = [[1, 2, 3], [8, 5, 7], [4, 7, 7], [5, 5, 4], [4, 9, 9]]
        df_indexs = pd.DataFrame(data=values, index=multi_index)
        df_indexs

Out[68]: 
​           0 1 2
外层索引 内层索引
A    A1   1 2 3
​    A2   8 5 7
B    B1   4 7 7
​    B2   5 5 4
​    B3   4 9 9

2. 通过from_arrays()方法创建MultiIndex对象

from_arrays()方法是将数组列表转换为MultiIndex对象,其中嵌套的第一个列表将作为外层索引,嵌套的第二个列表将作为内层索引,示例代码如下。

In [69]: from pandas import MultiIndex
         # 根据列表创建一个MultiIndex对象
         multi_array = MultiIndex.from_arrays(arrays =[['A', 'B', 'A', 'B', 'B'],
                                                       ['A1', 'A2', 'B1', 'B2', 'B3']],
                                              names=['外层索引','内层索引'])
         multi_array
Out[69]: 
MultiIndex(levels=[['A', 'B'], ['A1', 'A2', 'B1', 'B2', 'B3']],
           labels=[[0, 1, 0, 1, 1], [0, 1, 2, 3, 4]],
           names=['outer_index', 'inner_index'])

上述代码中,在创建MultiIndex对象时,arrays参数接收了一个嵌套列表,表示多级索引的标签。需要注意的是,参数arrays既可以接收列表,也可以接收数组,不过每个列表或数组的长度必须是相同的。

接下来,创建一个DataFrame对象,把刚刚创建的multi_array传递给index参数,让该对象具有层级索引结构,示例代码如下。

In [70]: # 导入所需要的包
        import pandas as pd
        import numpy as np
        values = np.array([[1, 2, 3], [8, 5, 7], [4, 7, 7],
                           [5, 5, 4], [4, 9, 9]])
        df_array = pd.DataFrame(data=values, index=multi_array)
        df_array

Out[70]: 
​           0 1 2
外层索引 内层索引
A    A1  1 2 3
B    A2  8 5 7
A    B1  4 7 7
B    B2  5 5 4
​    B3  4 9 9

3. 通过from_product()方法创建MultiIndex对象

from_product()方法表示从多个集合的笛卡尔乘积中创建一个MultiIndex对象,示例代码如下。

In [71]: from pandas import MultiIndex
         import pandas as pd
         numbers = [0, 1, 2]
         colors = ['green', 'purple']
         multi_product = pd.MultiIndex.from_product(iterables=[numbers, colors], 
                                                    names=['number', 'color'])
         multi_product

Out[71]: 
MultiIndex(levels=[[0, 1, 2], ['green', 'purple']],labels=[[0, 0, 1, 1, 2, 2], 
                                                           [0, 1, 0, 1, 0, 1]],
                                                   names=['number', 'color'])

接下来,创建一个DataFrame对象,把刚刚创建的multi_product传递给index参数,让该对象具有两层索引结构,示例代码如下。

In [72]: # 导入所需要的包
         import pandas as pd
         # 使用变量values接收DataFrame对象的值
         values = np.array([[7, 5], [6, 6], [3, 1], [5, 5], [4, 5], [5, 3]])
         df_product = pd.DataFrame(data=values, index=multi_product)
         df_product

Out[72]: 
                  0 1
number    color
0         green   7 5
          purple  6 6
1         green   3 1
          purple  5 5
2         green   4 5
          purple  5 3

多学一招:笛卡尔乘积

在数学中,两个集合X和Y的笛卡尓积,又称直积,表示为X × Y,第一个对象是X的成员,而第二个对象是Y的所有可能有序对的其中一个成员 。

假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。

点击此处
隐藏目录