pandas层次化索引
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
- 创建多层行索引
从一个文件中读取一个多层级索引的表
df = pd.read_excel(’./data/data.xlsx’, sheet_name=1, header=[0,1])
df
---------------------------------
上半年 下半年
北京 上海 广州 北京 上海 广州
手机 89 90 100 88 130 104
电脑 90 68 98 98 127 120
键盘 78 90 100 100 130 115
NaN 0 1 2 3 4 5
product
product = [["上半年","下半年"],["北京","上海","广州"]]
array
array = [[“上半年”,“上半年”,“上半年”,“下半年”,“下半年”,“下半年”],[“北京”,“上海”,“广州”,“北京”,“上海”,“广州”]]
tuple
tuples = [[“上半年”,“北京”],[“上半年”,“上海”],[“上半年”,“广州”],[“下半年”,“北京”],[“下半年”,“上海”],[“下半年”,“广州”]]
- 隐式构造
最常见的方法是给DataFrame构造函数的index参数传递两个或更多的数组
- Series也可以创建多层索引
data = np.random.randint(0,200,size=(3,6))
index = [“手机”,“电脑”,“键盘”]
# 隐式构造只支持使用数组表达多级索引的方式来进行构造,不常用
df = DataFrame(data=data, index=index, columns=array)
df
----------------------------------
上半年 下半年
北京 上海 广州 北京 上海 广州
手机 147 185 181 126 131 197
电脑 61 185 172 177 95 59
键盘 152 105 79 70 99 8
- 显示构造pd.MultiIndex
-
使用数组
column1 = pd.MultiIndex.from_arrays(array)
DataFrame(data=data, index=index, columns=column1)
-----------------------------------
上半年 下半年
北京 上海 广州 北京 上海 广州
手机 134 192 192 187 70 182
电脑 2 177 162 2 93 121
键盘 164 189 184 125 114 155 -
使用tuple
column2 = pd.MultiIndex.from_tuples(tuples)
DataFrame(data=data, index=index, columns=column1)
-----------------------------
上半年 下半年
北京 上海 广州 北京 上海 广州
手机 134 192 192 187 70 182
电脑 2 177 162 2 93 121
键盘 164 189 184 125 114 155 -
使用product
最简单,推荐使用
column3 = pd.MultiIndex.from_product(product)
DataFrame(data=data, index=index, columns=column1)----------------------------------------- 上半年 下半年 北京 上海 广州 北京 上海 广州 手机 134 192 192 187 70 182 电脑 2 177 162 2 93 121 键盘 164 189 184 125 114 155 # 构建一个多层级的行索引表 DataFrame(data=data.reshape(6,3), index=column1, columns=index) ------------------------------------------------------- 手机 电脑 键盘 上半年 北京 170 178 79 上海 161 72 159 广州 53 31 137 下半年 北京 167 77 179 上海 45 121 96 广州 106 34 39
============================================
练习8:
- 创建一个DataFrame,表示出张三李四期中期末各科成绩, 成绩包括python、java、php
============================================
data = np.random.randint(0,100,size=(2,6))
index = ["张三","李四"]
# columns = ["python","java","php"]
columns = pd.MultiIndex.from_product([["期中","期末"],["python","java","php"]])
DataFrame(data=data, index=index, columns=columns)
-----------------------------
期中 期末
python java php python java php
张三 11 98 56 19 63 72
李四 7 57 60 32 9 0
data = data.reshape((4,3))
index = pd.MultiIndex.from_product([["期中","期末"],["张三","李四"]])
columns = ["python","java","php"]
DataFrame(data=data, index=index, columns=columns)
-------------------------------------
python java php
期中 张三 11 98 56
李四 19 63 72
期末 张三 7 57 60
李四 32 9 0
- 多层列索引
除了行索引index,列索引columns也能用同样的方法创建多层索引
- 多层索引对象的索引与切片操作
1)Series的操作
index = pd.MultiIndex.from_product([["期中","期末"],["python","java","html5"]])
data = np.random.randint(0,100,size=6)
s = Series(data=data, index=index)
s
----------------------------
期中 python 56
java 21
html5 12
期末 python 63
java 39
html5 98
dtype: int32
【重要】对于Series来说,直接中括号[]与使用.loc()完全一样,推荐使用.loc中括号索引和切片。
# 首先变成一级索引
# 其他方法,间接访问,只能读取,不能赋值
s.loc["期中"].loc["python"]
# 多层级索引访问的标准方式
# ("期中","python") 多层级索引的特殊表达方式,使用一个元组来表达多层级
# 不是官方给的概念,只能这样去理解记忆
s.loc[("期中","python")]
df.loc["index","column"]
(1) 索引
(2) 切片
s.loc["期中"].loc["python":"html5"]
--------------------------------
python 73
java 11
html5 92
dtype: int32
# ("期中","python")这种方式不适用于切片
s.loc[("期中","python"):("期中","java")]
---------------------------------
# 隐式索引无视多层级索引的存在
s.iloc[0:3]
------------------------
期中 python 56
java 21
html5 12
dtype: int32
# 使用隐式索引访问元素
s.iloc[3]
-------------------------
52
2)DataFrame的操作
index = ["tom","lucy","jack","rose"]
columns = pd.MultiIndex.from_product([["first","second"],["python","java","php"]])
data = np.random.randint(0,100,size=(4,6))
df = DataFrame(data=data, index=index, columns=columns)
df
--------------------------
first second
python java php python java php
tom 3 50 47 24 2 22
lucy 34 17 61 61 57 61
jack 23 29 79 32 86 90
rose 71 24 55 32 33 8
data1 = np.random.randint(0,100,size=(4,6))
data2=data1.reshape((8,3))
index = pd.MultiIndex.from_product([["first","second"],["tom","lucy","jack","rose"]])
columns = ["python","java","php"]
df = DataFrame(data=data2, index=index, columns=columns)
df
--------------------------
python java php
first tom 75 30 73
lucy 86 92 51
jack 47 67 51
rose 95 70 94
second tom 57 65 92
lucy 24 50 72
jack 33 88 4
rose 1 47 60
df.loc[["tom","jack"]]
--------------------------
first second
python java php python java php
tom 3 50 47 24 2 22
jack 23 29 79 32 86 90
# 使用("first","python")元组的方式,访问一列
df.loc[:,("first","python")]
---------------------------------
tom 3
lucy 34
jack 23
rose 71
Name: (first, python), dtype: int32
df.loc[:,("first","python"):("first","java")]
-----------------------------
df.iloc[:,0:4]
----------------------
first second
python java php python
tom 3 50 47 24
lucy 34 17 61 61
jack 23 29 79 32
rose 71 24 55 32
df["first"]["php"]
-----------------------
tom 47
lucy 61
jack 79
rose 55
Name: php, dtype: int32
df["first"].php
----------------------
tom 47
lucy 61
jack 79
rose 55
Name: php, dtype: int32
# 多层级列索引的访问和切片
# 元素访问 df.loc[index,("一级索引","二级索引")]
# 列访问 df.loc[:,("一级索引","二级索引")]
# 列切片 df.iloc[index1:index2]
# 其他访问方式,只访问,不赋值, 先变成一级索引,再访问
data = data.reshape(8,3)
columns = ["python","java","php"]
index = pd.MultiIndex.from_product([["first","second"],["tom","lucy","jack","rose"]])
df2 = DataFrame(data=data, index=index, columns=columns)
df2
--------------------------
python java php
first tom 3 50 47
lucy 24 2 22
jack 34 17 61
rose 61 57 61
second tom 23 29 79
lucy 32 86 90
jack 71 24 55
rose 32 33 8
df2.loc[("first","lucy"),"python"]
------------------
24
df2.iloc[0:4]
---------------------
python java php
first tom 3 50 47
lucy 24 2 22
jack 34 17 61
rose 61 57 61
df2.loc["second"].loc["lucy":"rose"]
# 多层级行索引的访问和切片
# 元素访问 df.loc[("一级索引","二级索引"),"列标签"]
# 行切片 df.iloc[index1:index2]
# 行访问 df.loc(("一级索引","二级索引"))
# 其他访问方式,先变成一级索引的数据,再进一步访问, 只读不写
(1) 可以直接使用列名称来进行列索引
行多级索引的索引和切片操作
列多级索引的索引和切片操作
(2) 使用行索引需要用ix(),loc()等函数
【极其重要】推荐使用loc()函数
注意在对行索引的时候,若一级行索引还有多个,对二级行索引会遇到问题!也就是说,无法直接对二级索引进行索引,必须让二级索引变成一级索引后才能对其进行索引!
============================================
练习9:
- 分析比较Series和DataFrame各种索引的方式,熟练掌握.loc()方法
- 假设张三再一次在期中考试的时候因为特殊原因放弃英语考试,如何实现?
============================================
df.loc["tom",("first","java")] = np.nan
df
------------------
first second
python java php python java php
tom 3 NaN 47 24 2 22
lucy 34 17.0 61 61 57 61
jack 23 29.0 79 32 86 90
rose 71 24.0 55 32 33 8
# 不要使用这种方式赋值
df["first"].loc["tom","python"]
-------------------------------------
3
df
--------------------------
first second
python java php python java php
tom 3 NaN 47 24 2 22
lucy 34 17.0 61 61 57 61
jack 23 29.0 79 32 86 90
rose 71 24.0 55 32 33 8
- 索引的堆(stack)
- stack()
- unstack()
df2 = df.stack(level=0)
df2
----------------------------
java php python
tom first NaN 47 3
second 2.0 22 24
lucy first 17.0 61 34
second 57.0 61 61
jack first 29.0 79 23
second 86.0 90 32
rose first 24.0 55 71
second 33.0 8 32
df2.unstack(level=-1)
----------------------
java php python
first second first second first second
tom NaN 2.0 47 22 3 24
lucy 17.0 57.0 61 61 34 61
jack 29.0 86.0 79 90 23 32
rose 24.0 33.0 55 8 71 32
可以使用stack或unstack来完成切片操作
为了展示数据需要,可以使用stack和unstack来变形
df2.unstack(level=-2).loc[“first”]
-----------------------------------------
java tom NaN
lucy 17.0
jack 29.0
rose 24.0
php tom 47.0
lucy 61.0
jack 79.0
rose 55.0
python tom 3.0
lucy 34.0
jack 23.0
rose 71.0
Name: first, dtype: float64
【小技巧】使用stack()的时候,level等于哪一个,哪一个就消失,出现在行里。
【小技巧】使用unstack()的时候,level等于哪一个,哪一个就消失,出现在列里。
-
聚合操作
mean()
sum()
median()
max()
min()
argmax()
argmin()
std()
prod()
any()
all()
【注意】
- 需要指定axis
- 【小技巧】和unstack()相反,聚合的时候,axis等于哪一个,哪一个就保留。
s = Series(data=np.random.randint(0,100,size=(10)), index=list(“ABCDEFGHIJ”))
s
----------------------------
A 54
B 66
C 5
D 7
E 24
F 91
G 18
H 56
I 20
J 79
dtype: int32
s.mean()
---------------
42.0
s[“C”] = np.nan
s.std()
------------------------
31.026870075253587
pandas里面会自动优化np.nan
np.nanXXX()
s.sum()
-------------------
415.0
data = np.random.randint(0,100,size=(5,5))
index = list(“abcde”)
columns = list(“ABCDE”)
df = DataFrame(data=data, index=index, columns=columns)
df
-----------------------
A B C D E
a 7 51 71 49 12
b 64 40 78 78 71
c 26 53 98 51 71
d 32 49 92 33 54
e 94 29 14 8 44
DataFrame的聚合运算要注意行列方向的控制
df.sum(axis=1)
---------------------------
a 190
b 331
c 299
d 260
e 189
dtype: int64
numpy的聚合默认是不分行和列的
df.values.sum()
---------------------------
1269
df.loc[[True,False,True,True,False]]
---------------------------
A B C D E
a 7 51 71 49 12
c 26 53 98 51 71
d 32 49 92 33 54
df[(df > 90).any(axis=1)]
--------------------
A B C D E
c 26 53 98 51 71
d 32 49 92 33 54
e 94 29 14 8 44
所谓的聚合操作:平均数,方差,最大值,最小值……
============================================
练习11:
- 计算各个科目期中期末平均成绩
- 计算各科目张三李四的最高分
=================================
df.columns = ["python","java","c","c++","php"]
df2 = pd.concat((df, df),axis=1, keys=["期中","期末"])
df2
-----------------------------
期中 期末
python java c c++ php python java c c++ php
a 7 51 71 49 12 7 51 71 49 12
b 64 40 78 78 71 64 40 78 78 71
c 26 53 98 51 71 26 53 98 51 71
d 32 49 92 33 54 32 49 92 33 54
e 94 29 14 8 44 94 29 14 8 44
df2.mean()
----------------------
期中 python 44.6
java 44.4
c 70.6
c++ 43.8
php 50.4
期末 python 44.6
java 44.4
c 70.6
c++ 43.8
php 50.4
dtype: float64
df2.max(axis=1)
-------------------------
a 71
b 78
c 98
d 92
e 94
dtype: int32