3、pandas-多层索引

1. 创建多层行索引

1.1 隐式构造

  • 最常见的方法是给DataFrame构造函数的index参数传递两个或更多的数组
    • Series也可以创建多层索引
1
2
3
4
5
6
7
8
9
10
11
12
13
In [1]: import numpy as np

In [2]: import pandas as pd

In [3]: s = pd.Series([1,2,3,4],index=[['a','a','b','b'],[0,0,1,1]])

In [4]: s
Out[4]:
a 0 1
0 2
b 1 3
1 4
dtype: int64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
In [6]: df = pd.DataFrame(np.random.randint(0,150,size=(6,3)),
...: columns=['语文','数学','Python'],
...: index=[['Michael','Michael','Lisa','Lisa','Po','Po'],
...: ['Mid','End','Mid','End','Mid','End']])

In [7]: df
Out[7]:
语文 数学 Python
Michael Mid 117 50 144
End 39 56 56
Lisa Mid 110 103 148
End 119 91 116
Po Mid 69 67 13
End 120 127 105

1.2 显示构造pd.MultiIndex

  • 使用数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
In [8]: df1 = pd.DataFrame(np.random.randint(0,150,size=(6,3)),
...: columns=['Java','Python','Scala'],
...: index=pd.MultiIndex.from_arrays([['张三','张三','李四','李四','王五','王五'],
...: ['期中','期末','期中','期末','期中','期末']]))

In [9]: df1
Out[9]:
Java Python Scala
张三 期中 19 147 7
期末 145 29 109
李四 期中 83 84 105
期末 136 145 92
王五 期中 64 17 98
期末 40 60 90
  • 使用tuple
1
2
3
4
5
6
7
8
9
10
11
12
13
14
In [10]: df2 = pd.DataFrame(np.random.randint(0,150,size=(6,3)),
...: columns=['Java','Python','Scala'],
...: index=pd.MultiIndex.from_tuples([('张三','期中'),('张三','期末'),('李四','期中'),('李四','
...: 期末'),('王五','期中'),('王五','期末')]))

In [11]: df2
Out[11]:
Java Python Scala
张三 期中 80 108 108
期末 146 84 85
李四 期中 139 136 66
期末 149 92 94
王五 期中 27 83 143
期末 109 4 90
  • 使用product 【最简单,推荐使用】
1
2
3
4
5
6
7
8
9
10
11
12
13
In [12]: df3 = pd.DataFrame(np.random.randint(0,150,size=(6,3)),
...: columns=['Java','Python','Scala'],
...: index=pd.MultiIndex.from_product([['张三','李四','王五'],['期中','期末']]))

In [13]: df3
Out[13]:
Java Python Scala
张三 期中 48 131 73
期末 69 60 67
李四 期中 17 50 106
期末 140 32 10
王五 期中 40 113 73
期末 37 105 103
1
2
3
4
5
6
7
8
9
10
11
12
#对于DataFrame列同样可以设置多层索引
In [14]: df4 = pd.DataFrame(np.random.randint(0,150,size=(3,6)),
...: columns=pd.MultiIndex.from_product([['Java','Python','Scala'],['期中','期末']]),
...: index=['张三','李四','王五'])

In [15]: df4
Out[15]:
Java Python Scala
期中 期末 期中 期末 期中 期末
张三 81 17 49 83 104 123
李四 30 119 23 65 11 138
王五 65 147 17 25 148 149

2. 多层索引对象的索引与切片操作

2.1 Series的操作

  • 【重要】对于Series来说,直接中括号[]与使用.loc()完全一样,推荐使用中括号索引和切片
  • (1)索引
1
2
3
4
5
6
7
8
9
10
In [16]: s = pd.Series(np.random.randint(0,150,size=4),index=[['a','a','b','b'],['期中','期末','期
...: 中','期末']])

In [17]: s
Out[17]:
a 期中 19
期末 16
b 期中 2
期末 126
dtype: int32
1
2
In [18]: s['a','期末']
Out[18]: 16
1
2
3
4
5
In [19]: s[['a','期中']]
Out[19]:
a 期中 19
期末 16
dtype: int32
  • (2)切片
1
2
3
4
5
6
7
In [20]: s['a':'b']
Out[20]:
a 期中 19
期末 16
b 期中 2
期末 126
dtype: int32
1
2
3
4
5
6
In [21]: s.iloc[0:3]
Out[21]:
a 期中 19
期末 16
b 期中 2
dtype: int32

2.2 DataFrame的操作

  • (1)可以直接使用列名称来进行行列索引
1
2
3
4
5
6
7
8
9
In [22]: df1
Out[22]:
Java Python Scala
张三 期中 19 147 7
期末 145 29 109
李四 期中 83 84 105
期末 136 145 92
王五 期中 64 17 98
期末 40 60 90
1
2
3
4
5
6
7
In [23]: df1['张三':'李四']
Out[23]:
Java Python Scala
张三 期中 19 147 7
期末 145 29 109
李四 期中 83 84 105
期末 136 145 92
1
2
3
4
5
6
7
In [24]: df1.loc['张三':'李四']
Out[24]:
Java Python Scala
张三 期中 19 147 7
期末 145 29 109
李四 期中 83 84 105
期末 136 145 92
  • (2)使用行索引需要用ix()loc()等函数
  • 【极其重要】推荐使用loc()函数
  • 注意在对行索引的时候,若一级行索引还有多个,对二级行索引会遇到问题!也就是说,无法直接对二级索引进行索引,必须让二级索引变成一级索引后才能对其进行索引!
1
2
3
4
5
6
In [25]: df1.loc['张三','期中']
Out[25]:
Java 19
Python 147
Scala 7
Name: (张三, 期中), dtype: int32
1
2
3
4
5
6
In [26]: df1.loc['张三'].loc['期中']
Out[26]:
Java 19
Python 147
Scala 7
Name: 期中, dtype: int32
1
2
3
4
5
6
7
In [27]: df1.loc[['张三','李四']]
Out[27]:
Java Python Scala
张三 期中 19 147 7
期末 145 29 109
李四 期中 83 84 105
期末 136 145 92
1
2
df1.loc[:,'期中']
#报错

3. 索引的堆(stack)

  • stack()
  • unstack()
  • 【小技巧】使用stack()的时候,level等于哪一个,哪一个就消失,出现在行里。
1
2
3
4
5
6
7
In [29]: df4
Out[29]:
Java Python Scala
期中 期末 期中 期末 期中 期末
张三 81 17 49 83 104 123
李四 30 119 23 65 11 138
王五 65 147 17 25 148 149
1
2
3
4
5
6
7
8
9
10
#stack = 堆  --->行
In [30]: df4.stack()
Out[30]:
Java Python Scala
张三 期中 81 49 104
期末 17 83 123
李四 期中 30 23 11
期末 119 65 138
王五 期中 65 17 148
期末 147 25 149
1
2
3
4
5
6
7
8
9
10
11
12
13
#多层索引而言0,1,2:从上往下数
In [31]: df4.stack(level=0)
Out[31]:
期中 期末
张三 Java 81 17
Python 49 83
Scala 104 123
李四 Java 30 119
Python 23 65
Scala 11 138
王五 Java 65 147
Python 17 25
Scala 148 149
1
2
3
4
5
6
7
8
9
In [32]: df4.stack(level=1)
Out[32]:
Java Python Scala
张三 期中 81 49 104
期末 17 83 123
李四 期中 30 23 11
期末 119 65 138
王五 期中 65 17 148
期末 147 25 149
  • 【小技巧】使用unstack()的时候,level()等于哪一个,哪一个就消失,出现在列里面。
1
2
3
4
5
6
7
8
9
In [33]: df2
Out[33]:
Java Python Scala
张三 期中 80 108 108
期末 146 84 85
李四 期中 139 136 66
期末 149 92 94
王五 期中 27 83 143
期末 109 4 90
1
2
3
4
5
6
7
In [34]: df2.unstack()
Out[34]:
Java Python Scala
期中 期末 期中 期末 期中 期末
张三 80 146 108 84 108 85
李四 139 149 136 92 66 94
王五 27 109 83 4 143 90
1
2
3
4
5
6
In [35]: df2.unstack(level=0)
Out[35]:
Java Python Scala
张三 李四 王五 张三 李四 王五 张三 李四 王五
期中 80 139 27 108 136 83 108 66 143
期末 146 149 109 84 92 4 85 94 90
1
2
3
4
5
6
7
In [36]: df2.unstack(level=1)
Out[36]:
Java Python Scala
期中 期末 期中 期末 期中 期末
张三 80 146 108 84 108 85
李四 139 149 136 92 66 94
王五 27 109 83 4 143 90

4. 聚合操作

  • 【注意】
    • 需要指定axis
    • 【小技巧】和unstack()相反,聚合的时候,axis等于哪一个,哪一个就保留
  • 所谓的聚合操作:平均数,方差,最大值,最小值
1
2
3
4
5
6
7
8
9
In [37]: df1
Out[37]:
Java Python Scala
张三 期中 19 147 7
期末 145 29 109
李四 期中 83 84 105
期末 136 145 92
王五 期中 64 17 98
期末 40 60 90
1
2
3
4
5
6
7
#求和操作
In [38]: df1.sum()
Out[38]:
Java 487
Python 482
Scala 501
dtype: int64
1
2
3
4
5
6
7
#axis = 0 行,对行进行求和操作,行的数据就加到一起了,行就消失了
In [39]: df1.sum(axis=0)
Out[39]:
Java 487
Python 482
Scala 501
dtype: int64
1
2
3
4
5
6
7
8
9
In [40]: df1.sum(axis=1)
Out[40]:
张三 期中 173
期末 283
李四 期中 272
期末 373
王五 期中 179
期末 190
dtype: int64
1
2
3
4
5
6
7
8
9
10
#求方差
In [41]: df1.std(axis=1)
Out[41]:
张三 期中 77.597251
期末 59.374518
李四 期中 12.423097
期末 28.360771
王五 期中 40.673497
期末 25.166115
dtype: float64