第3章 Pandas数据处理(3.6)_Python数据科学手册学习笔记

3.6 层级索引

之前介绍了一维数组和二维数组, 用Pandas中的Series和DataFrame对象就可以储存. 我们也经常碰到处理多维数组的需求, Pandas提供了Panel和Panel4D对象解决三维数据与四维数据.

在实践中,更直观的形式是通过层级索引(hierarchical indexing),也被称为多级索引,配合多个有不同等级的一级索引一起使用,这样就可以将高维数组转换成类似一维Series和二维DataFrame对象的形式.

3.6.1 多级索引 Series

笨办法,用元组表示索引

import numpy as np
import pandas as pd
index = [('加利福利亚',2000),('加利福利亚',2010),('纽约',2000),('纽约',2010),('德克萨斯',2000),('德克萨斯',2010)]
population = [1123123,213123,543333,53334,45345,435435]
pop = pd.Series(population,index=index)      # index在python中不是关键字
pop
(加利福利亚, 2000)    1123123
(加利福利亚, 2010)     213123
(纽约, 2000)        543333
(纽约, 2010)         53334
(德克萨斯, 2000)       45345
(德克萨斯, 2010)      435435
dtype: int64
pop[('加利福利亚',2010):('德克萨斯',2000)]
(加利福利亚, 2010)    213123
(纽约, 2000)       543333
(纽约, 2010)        53334
(德克萨斯, 2000)      45345
dtype: int64
pop[[i for i in pop.index if i[1]==2010]]
(加利福利亚, 2010)    213123
(纽约, 2010)        53334
(德克萨斯, 2010)     435435
dtype: int64
pop[[i for i in pop.index if index[1]==2010]]    #代码错
Series([], dtype: int64)
pop[i for i in pop.index if i[1]==2010]   # 少打一个中括号 ,报错
  File "<ipython-input-6-fe2fee64d40f>", line 1
    pop[i for i in pop.index if i[1]==2010]   # 少打一个中括号 ,报错
            ^
SyntaxError: invalid syntax

好办法: Pandas多级索引
- 使用MultiIndex方法

index = pd.MultiIndex.from_tuples(index)      # 为什么是from_tuples, index不是一个序列吗
#  有from-tuples, from_arrays(), from_product()三种用法
index
# levels 表示索引的等级, labels可以认为是哑变量
MultiIndex(levels=[['加利福利亚', '德克萨斯', '纽约'], [2000, 2010]],
           labels=[[0, 0, 2, 2, 1, 1], [0, 1, 0, 1, 0, 1]])
pop = pop.reindex(index)
pop
# 布局怎么是这样子的
加利福利亚  2000    1123123
       2010     213123
纽约     2000     543333
       2010      53334
德克萨斯   2000      45345
       2010     435435
dtype: int64
type(pop)   # pop的属性还是Series, 只不过有了多级索引
pandas.core.series.Series
pop[:,2000]    # 在Series通过多级索引筛选
加利福利亚    1123123
纽约        543333
德克萨斯       45345
dtype: int64

高维数据的多级索引
- DataFrame 就可以看作有行,列索引的数据
- 通过unstack()方法可以快速将一个多级索引的Series转化成普通索引的DataFrame

pop
加利福利亚  2000    1123123
       2010     213123
纽约     2000     543333
       2010      53334
德克萨斯   2000      45345
       2010     435435
dtype: int64
pop_df = pop.unstack()    # 程序怎么知道把哪个索引编成列
pop_df
20002010
加利福利亚1123123213123
德克萨斯45345435435
纽约54333353334
pop_df.stack()    # unstack的逆过程
加利福利亚  2000    1123123
       2010     213123
德克萨斯   2000      45345
       2010     435435
纽约     2000     543333
       2010      53334
dtype: int64
pop_df = pd.DataFrame({'total':pop,'under18':[3232,2323,3435,5656,688,1313]})
pop_df
totalunder18
加利福利亚200011231233232
20102131232323
纽约20005433333435
2010533345656
德克萨斯200045345688
20104354351313
f_u18 = pop_df['under18'] / pop_df['total']
#print(f_u18)
print(f_u18.unstack())
f_u18.unstack()   # 为什么两种显示格式不一样呢 
           2000      2010
加利福利亚  0.002878  0.010900
德克萨斯   0.015173  0.003015
纽约     0.006322  0.106049
20002010
加利福利亚0.0028780.010900
德克萨斯0.0151730.003015
纽约0.0063220.106049

3.6.2 多级索引的创建方式

最直接的方法是在Series或DataFrame的index属性使用至少二维的索引数组.

df = pd.DataFrame(np.random.rand(4,2),index=[['a','a','b','b'],[1,2,1,2]],columns=['data1','data2'])
df
# MultiIndex的工作在后台完成
data1data2
a10.4259950.902387
20.0510300.897131
b10.7130830.376870
20.0309570.239390

用MultIndex中的方法显式的创建多级索引

# 方法一
pd.MultiIndex.from_arrays([['a','a','b','b'],[1,2,1,2]])     # 双层中括号,中括号中的数组
MultiIndex(levels=[['a', 'b'], [1, 2]],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
# 方法二
pd.MultiIndex.from_tuples([('a',1),('a',2),('b',1),('b',2)])   # 中括号中的元组
MultiIndex(levels=[['a', 'b'], [1, 2]],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
# 方法三
pd.MultiIndex.from_product([['a','b'],[1,2]])     # 两个索引的笛卡尔积
MultiIndex(levels=[['a', 'b'], [1, 2]],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
# 方法四: 在Series或者DataFrame设置index属性. 在MultIndex中设置levels和labels属性
pd.MultiIndex(levels=[['a','b'],[1,2]],
             labels=[[0,0,1,1],[0,1,0,1]])      # labels的值应该只能为 0 和 1
MultiIndex(levels=[['a', 'b'], [1, 2]],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]])

多级索引的等级名称, 也就是给索引取个名称
- 用index的names属性

# pop.index.names('state','year') 报错
pop.index.names = ['state','year']
pop
state  year
加利福利亚  2000    1123123
       2010     213123
纽约     2000     543333
       2010      53334
德克萨斯   2000      45345
       2010     435435
dtype: int64

多级列索引

index = pd.MultiIndex.from_product([[2013,2014],[1,2]],
                                  names=['year','visit'])
columns = pd.MultiIndex.from_product([['张三','李四','王五'],['HR','Temp']],
                                    names=['subjeck','type'])
data = np.round(np.random.randn(4,6),1)
data[:,::2] *= 10
data += 37
health = pd.DataFrame(data,index=index,columns=columns)
health
subjeck张三李四王五
typeHRTempHRTempHRTemp
yearvisit
2013131.036.842.036.125.035.8
254.036.450.037.233.036.3
2014149.036.954.036.949.035.6
237.035.032.037.750.037.2
health['张三']
typeHRTemp
yearvisit
2013131.036.8
254.036.4
2014149.036.9
237.035.0
health[(:,'张三']    # 为什么出错 ,该怎么表示
  File "<ipython-input-25-91b10134495e>", line 1
    health[(:,'张三']    # 为什么出错 ,该怎么表示
            ^
SyntaxError: invalid syntax

3.6.3 多级索引的取值与切片

- 把索引看作是额外增加的维度

Series多级索引

pop
state  year
加利福利亚  2000    1123123
       2010     213123
纽约     2000     543333
       2010      53334
德克萨斯   2000      45345
       2010     435435
dtype: int64
type(pop)
pandas.core.series.Series
pop[('加利福利亚',2000)]   # pop是一个Series对象, 其索引是一个元组
1123123
pop['加利福利亚']
year
2000    1123123
2010     213123
dtype: int64
# pop[(:,2000)]   # 报错
pop[:,2000]   
state
加利福利亚    1123123
纽约        543333
德克萨斯       45345
dtype: int64
pop[pop>2000]
state  year
加利福利亚  2000    1123123
       2010     213123
纽约     2000     543333
       2010      53334
德克萨斯   2000      45345
       2010     435435
dtype: int64
pop[['加利福利亚','纽约']]
state  year
加利福利亚  2000    1123123
       2010     213123
纽约     2000     543333
       2010      53334
dtype: int64

DataFrame多级索引
- DataFrame的基本索引是列索引. DataFrame中列比行重要

health
subjeck张三李四王五
typeHRTempHRTempHRTemp
yearvisit
2013131.036.842.036.125.035.8
254.036.450.037.233.036.3
2014149.036.954.036.949.035.6
237.035.032.037.750.037.2
health.iloc[:2,:2]  # 隐式索引
# health[:2,:2]    # 报错   
subjeck张三
typeHRTemp
yearvisit
2013131.036.8
254.036.4
health.loc[:,('张三','HR')]   #显式索引
year  visit
2013  1        31.0
      2        54.0
2014  1        49.0
      2        37.0
Name: (张三, HR), dtype: float64
# health.loc[(:,1),(:,'HR')]   # 在元组中用切片会报错
# 使用IndexSlice
idx = pd.IndexSlice
health.loc[idx[:,1],idx[:,'HR']]
subjeck张三李四王五
typeHRHRHR
yearvisit
2013131.042.025.0
2014149.054.049.0

3.6.4 多级索引的行列转换

 - 之前接触过 stack()和unstack()

有序的索引和无序的索引
- 如果MultiIndex不是有序的索引, 那么大多数切片操作都会失败.

index = pd.MultiIndex.from_product([['a','c','b'],[1,2]])
data = pd.Series(np.random.rand(6),index=index)
data.index.names=['char','int']
data
char  int
a     1      0.930251
      2      0.362329
c     1      0.505852
      2      0.544361
b     1      0.683720
      2      0.680830
dtype: float64
# data['a':'b']  报错

局部切片和许多其他相似的操作要求MultiIndex的各级索引是有序的(即按照字典顺序由A至Z).
- Pandas提供了许多其他操作完成排序,sort_index()和sortlevel()方法

data = data.sort_index()
data
char  int
a     1      0.930251
      2      0.362329
b     1      0.683720
      2      0.680830
c     1      0.505852
      2      0.544361
dtype: float64

索引排序之后, 局部切片就可以正常使用了

data['a':'b']
char  int
a     1      0.930251
      2      0.362329
b     1      0.683720
      2      0.680830
dtype: float64

索引stack和unstack
- 前文曾提过, 可以将一个多级索引数据集转换成简单的二维形式, 可以通过Level参数设置转换的索引层级.

pop.unstack(level=0)
state加利福利亚德克萨斯纽约
year
2000112312345345543333
201021312343543553334
pop.unstack(level=1)
year20002010
state
加利福利亚1123123213123
德克萨斯45345435435
纽约54333353334

索引的设置与重置

pop
state  year
加利福利亚  2000    1123123
       2010     213123
纽约     2000     543333
       2010      53334
德克萨斯   2000      45345
       2010     435435
dtype: int64
# 用reset_index方法实现. 生成一个列标签包含之前行索引标签. 也可以用数据的name属性为列设置名.
pop_flat = pop.reset_index(name='population')
pop_flat
stateyearpopulation
0加利福利亚20001123123
1加利福利亚2010213123
2纽约2000543333
3纽约201053334
4德克萨斯200045345
5德克萨斯2010435435
type(pop_flat)
pandas.core.frame.DataFrame

使用DataFrame的set_index方法, 返回一个带多级索引的DataFrame

pop_flat.set_index(['state','year'])
population
stateyear
加利福利亚20001123123
2010213123
纽约2000543333
201053334
德克萨斯200045345
2010435435
pop_flat.set_index(['state','population'])
year
statepopulation
加利福利亚11231232000
2131232010
纽约5433332000
533342010
德克萨斯453452000
4354352010

3.6.5 多级索引的数据累计方法

- Pandas自带数据累计方法,比如mean(),sum()和max()
- 对于层级索引数据, 可以设置level实现对数据子集的累计操作
health
subjeck张三李四王五
typeHRTempHRTempHRTemp
yearvisit
2013131.036.842.036.125.035.8
254.036.450.037.233.036.3
2014149.036.954.036.949.035.6
237.035.032.037.750.037.2
# 计算每一年各项指标的平均值
data_mean= health.mean(level='year')
data_mean
subjeck张三李四王五
typeHRTempHRTempHRTemp
year
201342.536.6046.036.6529.036.05
201443.035.9543.037.3049.536.40
data_mean.mean(axis=1,level='type')
typeHRTemp
year
201339.16666736.433333
201445.16666736.550000
# heth.mean(axis=1,level=['year','type'])   上面两种方式组合错在哪
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

python技巧(数据分析及可视化)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值