pandas数据结构中最常用的是Series和DataFrame,它们分别用于处理一维数据和二维数据。但我们也经常遇到存储多维数据的需求,数据索引超过一两个键,这种情况下的数据超出了上面两种数据结构能够表示的范围,Pandas提供了Panel和Panel4D对象来解决三维数据和四维数据。而实践中,更直观的形式是通过层级索引,配合多个不同等级(level)的一级索引一起使用,这样就可以将高维数组转化为类似一维Series和二维DataFrame对象的形式。
我们先来看个通过层级索引将DataFrame数据转化为Series数据结构的例子:
import numpy as np
import pandas as pd
#创建一个DataFrame对象
data = [[33871648, 37253956],
[18976457, 19378102],
[20851820, 25145561]]
pop = pd.DataFrame(data,columns=[2000, 2010],index=['California', 'New York', 'Texas'])
pop
Out[30]:
2000 2010
California 33871648 37253956
New York 18976457 19378102
Texas 20851820 25145561
#通过层级索引创建一个与上面DataFrame等价的Series
data_1 = [33871648, 37253956, 18976457, 19378102, 20851820, 25145561]
#通过两个索引的笛卡尔积,创建MultiIndex对象
index_1 = pd.MultiIndex.from_product([['California', 'New York','Texas'],[2000, 2010]])
df = pd.Series(data_1, index=index_1)
df
Out[32]:
California 2010 33871648
2010 37253956
New York 2010 18976457
2010 19378102
Texas 2010 20851820
2010 25145561
dtype: int64
层级索引最大的作用在于能够将超过二维的数据结构转化为等价的DataFrame,下面展示将四维的数据通过行多层索引(2层)和列多层索引(2层)进行降维
#多级行列索引,并为每项索引分别命名
index = pd.MultiIndex.from_product([[2013, 2014],[1, 2]], names=['year', 'visit'])
columns = pd.MultiIndex.from_product([['Bob', 'Duido', 'Sue'],['HR', 'Temp']],
names=['subject', 'type'])
#模拟数据
data = np.round(np.random.randn(4,6), 1)
data[:, ::2] *= 10
data += 37
#创建DataFrame
health_data = pd.DataFrame(data, index=index, columns=columns)
health_data
Out[37]:
subject Bob Duido Sue
type HR Temp HR Temp HR Temp
year visit
2013 1 27.0 37.2 32.0 36.8 21.0 37.1
2 29.0 36.9 17.0 38.1 22.0 37.2
2014 1 33.0 36.9 26.0 37.1 22.0 36.0
2 29.0 38.2 36.0 35.9 23.0 38.5
#使用unstack()方法可以将层次索引的数据结构转化为一个普通的DataFrame,stack()方法作用相反
health_data.unstack()
Out[48]:
subject Bob Duido ... Sue
type HR Temp HR ... Temp HR Temp
visit 1 2 1 2 1 ... 2 1 2 1 2
year ...
2013 27.0 29.0 37.2 36.9 32.0 ... 38.1 21.0 22.0 37.1 37.2
2014 33.0 29.0 36.9 38.2 26.0 ... 35.9 22.0 23.0 36.0 38.5
[2 rows x 12 columns]
#这里已上文得到的health_data做为实验对象
#选取Sue的心率速度
health_data['Sue', 'HR']
Out[77]:
year visit
2013 1 21.0
2 22.0
2014 1 22.0
2 23.0
Name: (Sue, HR), dtype: float64
#如果想要对health_data多个维度进行切片,可以使用pands提供的loc、iloc索引器
#使用iloc索引器
health_data.iloc[:2, :2]
Out[83]:
subject Bob
type HR Temp
year visit
2013 1 27.0 37.2
2 29.0 36.9
#使用loc索引器
health_data.loc[2013, ('Bob','HR')]
Out[88]:
visit
1 27.0
2 29.0
Name: (Bob, HR), dtype: float64
#直接使用上面的两种索引器跳过行或列的第一级索引对第二索引进行切片会发生报错,使用IndexSlice对象,可以解决这个问题
idx = pd.IndexSlice
health_data.loc[idx[:, 1], idx[:, 'HR']]
Out[94]:
subject Bob Duido Sue
type HR HR HR
year visit
2013 1 27.0 32.0 21.0
2014 1 33.0 26.0 22.0
#Pandas自带了一些数据累计方法,比如mean(),sum(),max(),对于层级索引器,可以设置参数level实现对数据子集的累计操作
#计算各项指标每年的平均值
data_mean = health_data.mean(level='year')
data_mean
Out[100]:
subject Bob Duido Sue
type HR Temp HR Temp HR Temp
year
2013 28.0 37.05 24.5 37.45 21.5 37.15
2014 31.0 37.55 31.0 36.50 22.5 37.25
#计算每一年所有人的平均心率和体温
data_mean.mean(axis=1, level='type')
Out[103]:
type HR Temp
year
2013 24.666667 37.216667
2014 28.166667 37.100000