层次化索引(hierarchical indexing)是pandas的一个重要的功能,它可以在一个轴上有多个(两个以上)的索引,这就表示着,它能够以低维度形式来表示高维度的数据。
一. 创建多层行索引
1、 隐式构造
1)最常见的方法是给DataFrame构造函数的index参数传递两个或更多的数组,Series也可以创建多层索引。
s = Series(np.random.randint(0,150,size=10),index=list('qwertyuiop'))
print(s)
'''
q 63
w 71
e 80
r 78
t 9
y 27
u 107
i 1
o 68
p 69
dtype: int32
'''
s = Series(np.random.randint(0,150,size=6),
index=[['a','a','b','b','c','c'],
['期中','期末','期中','期末','期中','期末']])
print(s)
'''
a 期中 16
期末 93
b 期中 149
期末 6
c 期中 86
期末 52
dtype: int32
'''
df = DataFrame(s,columns=['python'])
print(df)
'''
python
a 期中 140
期末 91
b 期中 101
期末 37
c 期中 1
期末 47
'''
2)DataFrame建立2级列索引
df1 = DataFrame(np.random.randint(0,150,size=(4,6)),
index = list('东南西北'),
columns=[['python','python','math','math','En','En'],
['期中','期末','期中','期末','期中','期末']])
print(df1)
'''
python math En
期中 期末 期中 期末 期中 期末
东 143 107 33 107 86 117
南 8 147 5 35 106 23
西 115 124 77 76 39 30
北 27 141 126 50 70 88
'''
2、 显示构造pd.MultiIndex
1)使用数组构造
df2 = DataFrame(np.random.randint(0,150,size=(4,6)),
index = list('东南西北'),
columns=[['python','python','math','math','En','En'],
['期中','期末','期中','期末','期中','期末']])
print(df2)
'''
python math En
期中 期末 期中 期末 期中 期末
东 99 51 144 65 36 147
南 18 65 2 59 125 107
西 50 61 131 85 40 118
北 82 31 106 21 75 129
'''
2)使用tuple
构造
df3 = DataFrame(np.random.randint(0,150,size=(4,6)),
index = list('东南西北'),
columns =pd.MultiIndex.from_tuples([('python','期中'),('python','期末'),
('math','期中'),('math','期末'),
('En','期中'),('En','期末')]))
'''
python math En
期中 期末 期中 期末 期中 期末
东 129 122 32 17 93 35
南 89 125 73 112 10 140
西 23 65 84 8 24 144
北 136 127 119 147 122 136
'''
3)使用product
构造(推荐)
df4 = DataFrame(np.random.randint(0,150,size=(8,12)),
columns = pd.MultiIndex.from_product([['模拟考','正式考'],
['数学','语文','英语','物理','化学','生物']]),
index = pd.MultiIndex.from_product([['期中','期末'],
['雷军','李斌'],
['测试一','测试二']]))
print(df4)
'''
模拟考 正式考
数学 语文 英语 物理 化学 生物 数学 语文 英语 物理 化学 生物
期中 雷军 测试一 8 116 5 110 135 73 65 50 123 103 50 83
测试二 146 118 17 137 113 69 103 76 146 24 63 127
李斌 测试一 142 122 104 39 35 66 56 107 7 133 73 111
测试二 45 43 10 43 118 90 106 45 35 43 22 127
期末 雷军 测试一 66 26 133 84 42 109 101 100 52 125 118 115
测试二 96 55 29 39 95 122 124 62 90 46 101 103
李斌 测试一 5 109 123 18 102 106 129 8 97 123 147 75
测试二 122 32 1 15 119 0 60 149 3 135 13 20
'''
二. 多层索引对象的索引与切片操作
1、Series的操作
注意:对于Series来说,直接中括号[]与使用.loc()完全一样,推荐使用中括号索引和切片
s = Series(np.random.randint(0,150,size=6),
index=[['a','a','b','b','c','c'],
['期中','期末','期中','期末','期中','期末']])
print(s)
# 输出
a 期中 59
期末 43
b 期中 28
期末 99
c 期中 92
期末 58
dtype: int32
s['a','期中']
# 输出
59
s[['a','b']] #取多层的外层索引时,内层索引不可用
#输出
a 期中 59
期末 43
b 期中 28
期末 99
dtype: int32
s['a'][['期中','期末']]['期中']
# 输出
59
s.loc['a']
# 输出
期中 59
期末 43
dtype: int32
s.iloc[:5] #iloc计算的是最内层索引
# 输出
a 期中 59
期末 43
b 期中 28
期末 99
c 期中 92
dtype: int32
2、DataFrame操作
(1) 可以直接使用列名称来进行列索引
(2) 使用行索引需要用ix()
,loc()
等函数
推荐使用loc()函数
注意:在对行索引的时候,若一级行索引还有多个,对二级行索引会遇到问题!也就是说,无法直接对二级索引进行索引,必须让二级索引变成一级索引后才能对其进行索引!
df4 = DataFrame(np.random.randint(0,150,size=(8,12)),
columns = pd.MultiIndex.from_product([['模拟考','正式考'],
['数学','语文','英语','物理','化学','生物']]),
index = pd.MultiIndex.from_product([['期中','期末'],
['雷军','李斌'],
['测试一','测试二']]))
df4['模拟考'][['语文','数学']]
df4.loc['期中','雷军','测试一']['模拟考','数学']
# 输出
61
df4.loc['期中','雷军','测试一']
# 输出
模拟考 数学 61
语文 90
英语 97
物理 6
化学 118
生物 127
正式考 数学 143
语文 35
英语 79
物理 4
化学 90
生物 54
Name: (期中, 雷军, 测试一), dtype: int32
df4.iloc[0] #iloc是只取最内层的索引的
模拟考 数学 61
语文 90
英语 97
物理 6
化学 118
生物 127
正式考 数学 143
语文 35
英语 79
物理 4
化学 90
生物 54
Name: (期中, 雷军, 测试一), dtype: int32
df4['正式考']
注意:列索引从列开始取,必须一层层取,取完列索引,才可以取行索引,先取行索引同理。
三、重排分级顺序
在使用层次化索引的时候,我们可以重新调整某条轴上各级别的顺序,或根据级别上的值对数据进行排序。swaplevel接受两个级别编号或名称,返回一个互换了级别的新对象(数据不变)。我们可以对每个级别设置一个名称,就像对DataFrame设置行列索引的名称一样。
data = DataFrame(np.arange(12).reshape(4,3),
index=[["a","a","b","b"],[1,2,1,2]],
columns=[["A","A","B"],["Z","X","C"]])
print(data)
'''
A B
Z X C
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
'''
#对每一个级别设置一个名称
#设置行级别的名称
data.index.names=["row1","row2"]
#设置列级别的名称
data.columns.names=["column1","column2"]
print(data)
'''
column1 A B
column2 Z X C
row1 row2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
'''
#通过swaplevel,调整行的顺序
print(data.swaplevel("row1","row2"))
'''
column1 A B
column2 Z X C
row2 row1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11
'''
#对指定级别中的值进行排序
#对级别名称为row2中的值进行排序
print(data.sortlevel(1))#等价于data.swaplevel(0,1).sortlevel(0)
'''
column1 A B
column2 Z X C
row1 row2
a 1 0 1 2
b 1 6 7 8
a 2 3 4 5
b 2 9 10 11
'''
四、根据级别汇总统计
data = DataFrame(np.arange(12).reshape(4,3),
index=[["a","a","b","b"],[1,2,1,2]],
columns=[["A","A","B"],["Z","X","C"]])
print(data)
'''
A B
Z X C
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
'''
#对每一个级别设置一个名称
#设置行级别的名称
data.index.names=["row1","row2"]
#设置列级别的名称
data.columns.names=["column1","column2"]
print(data)
'''
column1 A B
column2 Z X C
row1 row2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
'''
#指定行级别的名称进行求和
print(data.sum(level="row1"))
'''
column1 A B
column2 Z X C
row1
a 3 5 7
b 15 17 19
'''
#指定列级别的名称进求和
print(data.sum(level="column1",axis=1))
'''
column1 A B
row1 row2
a 1 1 2
2 7 5
b 1 13 8
2 19 11
'''