认识层次化索引
前面所涉及的Pandas对象都只有一层索引结构(行索引、列索引),又称为单层索引,层次化索引可以理解为单层索引的延伸,即在一个轴方向上具有多层索引。
对于两层索引结构来说,它可以分为内层索引和外层索引。以某些省市的面积表格为例,我们来认识一下什么是层次化索引,具体如图1所示。
图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)}。