概述
多层数据可以只有行上的多层,可以只有在列上为多层,也可以在两个方向都为多层,理论上层数是没有上限的。除了原生的数据为多层外,在数据分组聚合等操作时也会产生多层数据。
多层是一个低维的形式展示的多维数据,可以用这种形式处理高维数据。
通过分组产生多层索引
# 按团队分组,个团队中平均成绩及格的人数
df.groupby(['team',df.mean(1)>=60]).count()
# name Q1 Q2 Q3 Q4
# team
# A False 14 14 14 14 14
# True 3 3 3 3 3
# B False 14 14 14 14 14
# True 8 8 8 8 8
# C False 17 17 17 17 17
# True 5 5 5 5 5
# D False 10 10 10 10 10
# True 9 9 9 9 9
# E False 15 15 15 15 15
# True 5 5 5 5 5
创建多层索引
MultiIndex对象是Pandas标准Index的子类,由它来表示多层索引。可以将MultiIndex视为一个元组对序列,其中每个元组对都是唯一的。
# 序列数据 pd.MultiIndex.from_arrays
arrays=[[1,1,2,2],['A','B','A','B']] # 定义一个序列
index = pd.MultiIndex.from_arrays(arrays,names=('class','team'))
# 用这个多层索引生成对象DataFrame
pd.DataFrame({['Q1':60,'Q2':}],index=index)
# 由元组创建多层索引 pd.MultiIndex.from_tuples
# 定义一个两层的索引
arrays = [[1,1,2,2],['A','B','A','B']]
# 转换为元组
tuples = list(zip(*arrays))
# 将元组转换为多层索引
index = pd.MultiIndex.from_tuples(tuples,names=['class','team'])
# 使用多层索引对象
pd.Series(np.random.randn(4),index=index)
# 通过笛卡儿积生成多层索引
# pd.MultiIndex.from_product(),将所有情况排列组合出来
_class = [1,2]
_team = ['A','B']
index = pd.MultiIndex.from_product([_class,_team],names=['class','team'])
pd.Series(np.random.randn(4),index=index
# 将DataFrame转为多层索引
# pd.MultiIndex.from_frame()可以将DataFrame转成多层索引对象
df_i = pd.DataFrame([['1','A'],['1','B'],
['2','A'],['2','B']],columns=['class','team'])
index = pd.MultiIndex.from_frame(df_i)
pd.Series(np.random.randn(4),index=index
多层索引操作
# 索引
index_arrays = [[1,1,2,2],['男','女','男','女']]
# 列名
columns_arrays = [['2019','2019','2020','2020'],
['上半年','下半年','上半年','下半年']]
# 索引转为多层
index = pd.MultiIndex.from_arrays(index_arrays,names=('班级','性别'))
columns = pd.MultiIndex.from_arrays(columns_arrays,names=('年份','学期'))
# 应用到DataFrame中
df = pd.DataFrame([(88,99,88,99),(77,88,97,98),
(76,89,54,78),(34,67,89,54)],
columns=columns,index=index)
## 索引信息
和普通索引一样,多层索引也可以查看行、列及行列的名称
df.index # 索引 是一个MultiIndex
df.columns # 列索引 也是一个MultiIndex
df.index.names # 查看行索引名称
df.columns #查看列索引名称
查看层级
多层索引由于层级较多,在数据分析时需要查看它共有多少个层级。
df.index.nlevels # 行层级数
df.index.levels # 行的层级
df.columns.nlevels # 列层级数
df.columns.levels # 列的层级
索引内容
可以取指定层级的索引内容,也可以按索引名去索引内容
# 获取索引第二层内容
df.index.get_level_values(1)
# 获取列索引的第一层数据
df.columns.get_level_values(0)
# 按索引名称获取索引内容
df.index.get_level_values('班级')
df.columns.get_level_values('年份')
排序
多层索引可以根据需要实现较为复杂的排序操作
# 使用索引名进行排序,可以指定具体的列
df.sort_values(by=['性别',('2020','下半年')])
df.index.reorder_levels([1,0]) # 等级顺序互换 返回一个多层索引对象
df.index.sortlevel(level=0,ascending=True) # 按指定级别排序 返回一个多层索引对象
df.index.reindex(df.index[::-1]) # 更换顺序,或者指定一个顺序 返回一个多层索引对象
# 其他操作
df.index.to_numpy() #生成一个笛卡儿积的元组对序列
df.index.remove_unused_levels() # 返回没有使用的层级
df.swaplevel(0,1) # 交换索引 返回一个DataFrame
df.index.droplevel(0) # 删除指定等级
数据查询
查询行
查询第一层级下的某个索引的所有内容,可以直接使用df.loc[]传入它的索引值:
df.loc[1] # 查询一班的数据
切片(如df.loc[1:2]查询1~2班的数据)也适用
如果我们要同时根据一二级索引查询,可以将需要查询的索引条件组成一个元组
df.loc[(1,'男')] # 查询1班男
查询列
查询列时,可以直接使用切片选择需要查询的列,使用元组指定相关的层级数据
df['2020'] #整个一级索引下
df[('2020','上半年')] # 指定二级索引
df['2020']['上半年'] #同上
行列查询
行列查询和单层索引一样,指定层级内容也用元组表示。slice(None)可以在元组中占位,表示本层所有内容
df.loc[(1,'男'),'2020'] # 只显示2020年1班男生
df.loc[:,(slice(None),'下半年')] #只看下半年
df.loc[(slice(None),'女'),:] #只看女生
df.loc[(1,slice(None)),:] #只看1班
df.loc[1,:] #同上
df.loc[:,('2020',slice(None))] # 只看2020年数据
条件查询
按照一定的条件查询数据,和单层索引的数据查询一样,不过是在选择列上要按多层的规则。
# 2020 年上半年大于80的数据
df[df[('2020','上半年')]>80]
pd.IndexSlice索引数据
pd.IndeSlice 可以创建一个切片对象,轻松执行复杂的索引切片操作
idx = pd.IndexSlice
idx[0] # 0
idx[:] # slice(None,None,None)
idx[0,'x'] # (0,x)
idx[0:3] # slice(0,3,None)
idx[0:5,'x':'y'] # slice(0,5,None),slice('x','y',None)
idx = pd.IndexSlice
df.loc[idx[:,['男']],:] # 只显示男生 df.loc[idx[:,('男')],:]
df.loc[:,idx[:,['上半年']]] # 只显示上半年
df.xs()
使用df.xs()方法采用索引内容作为参数来选择多层索引数据中特定级别的数据
df.xs((1,'男')) # 1班男生
df.xs('2020',axis=1) # 2020年
df.xs('男',level=1) # 所有男生