pandas层次化索引 (隐式结构、显示结构、多层次对象的索引与切片)

本文详细介绍了pandas的层次化索引,包括如何创建多层行索引,从文件读取多层级索引数据,以及通过数组、元组、product方法显式构造多级列索引。此外,还讲解了多级索引对象的索引和切片操作,对Series和DataFrame的.loc()方法进行了深入探讨,并展示了stack()和unstack()在数据变形和切片中的应用。文章通过实例解析了聚合操作,如mean(), sum(), std()等,并提供了计算期中期末成绩平均分和最高分的实践案例。" 133577818,9342206,Python Pandas处理大数据:分块读取与Dask并行计算,"['Python', 'Pandas', '大数据', '并行计算']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

pandas层次化索引

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
  1. 创建多层行索引

从一个文件中读取一个多层级索引的表
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 = [[“上半年”,“北京”],[“上半年”,“上海”],[“上半年”,“广州”],[“下半年”,“北京”],[“下半年”,“上海”],[“下半年”,“广州”]]

  1. 隐式构造

最常见的方法是给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
  1. 显示构造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:

  1. 创建一个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
  1. 多层列索引

除了行索引index,列索引columns也能用同样的方法创建多层索引

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

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:

  1. 分析比较Series和DataFrame各种索引的方式,熟练掌握.loc()方法
  2. 假设张三再一次在期中考试的时候因为特殊原因放弃英语考试,如何实现?

============================================

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
  1. 索引的堆(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等于哪一个,哪一个就消失,出现在列里。

  1. 聚合操作

    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:

  1. 计算各个科目期中期末平均成绩
  2. 计算各科目张三李四的最高分

=================================

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值