Pandas MultiIndex 高级操作:复杂数据层次化处理与切片 (讲座模式)
大家好!欢迎来到今天的 Pandas MultiIndex 高级操作讲座。今天我们要聊聊 Pandas 中一个非常强大的功能,叫做 MultiIndex,中文可以理解为“多层索引”或者“分层索引”。如果你觉得你的数据长得像俄罗斯套娃,一层又一层,那么 MultiIndex 就是你的救星!
为什么要用 MultiIndex?
想象一下,你有一个关于全球各地不同城市的气象数据,数据维度可能包括:国家、城市、年份、月份、温度、湿度等等。 如果把所有这些信息都挤在一列索引里,那简直是一场灾难!
使用 MultiIndex,你可以把国家、城市、年份、月份都变成索引,这样你的数据就变得更有结构,更易于理解和操作。就像图书馆里的图书分类一样,方便我们快速找到想要的信息。
MultiIndex 的基础:从创建开始
Pandas 提供了多种方式来创建 MultiIndex。我们先从最简单的开始:
-
使用
from_tuples
创建如果你已经有一组元组,每个元组代表一个索引的组合,那么
from_tuples
是一个不错的选择。import pandas as pd tuples = [ ('中国', '北京'), ('中国', '上海'), ('美国', '纽约'), ('美国', '洛杉矶') ] index = pd.MultiIndex.from_tuples(tuples, names=['国家', '城市']) print(index)
输出:
MultiIndex([('中国', '北京'), ('中国', '上海'), ('美国', '纽约'), ('美国', '洛杉矶')], names=['国家', '城市'])
这个例子中,我们创建了一个包含国家和城市两层索引的 MultiIndex。
names
参数可以给每一层索引命名,方便我们后续操作。 -
使用
from_arrays
创建如果你有多个列表或者数组,每个列表代表一层的索引值,那么
from_arrays
就能派上用场。countries = ['中国', '中国', '美国', '美国'] cities = ['北京', '上海', '纽约', '洛杉矶'] index = pd.MultiIndex.from_arrays([countries, cities], names=['国家', '城市']) print(index)
输出和上面的例子一样。
-
使用
from_product
创建如果你想生成所有可能的索引组合,
from_product
是最方便的。它会计算多个列表的笛卡尔积。countries = ['中国', '美国'] cities = ['北京', '上海', '纽约', '洛杉矶'] index = pd.MultiIndex.from_product([countries, cities], names=['国家', '城市']) print(index)
输出:
MultiIndex([('中国', '北京'), ('中国', '上海'), ('中国', '纽约'), ('中国', '洛杉矶'), ('美国', '北京'), ('美国', '上海'), ('美国', '纽约'), ('美国', '洛杉矶')], names=['国家', '城市'])
可以看到,
from_product
帮我们生成了所有国家和城市的组合。 -
直接在 DataFrame 中创建
当然,你也可以在创建 DataFrame 的时候直接指定 MultiIndex。
data = { '温度': [25, 28, 30, 32], '湿度': [60, 70, 65, 75] } index = pd.MultiIndex.from_tuples([('中国', '北京'), ('中国', '上海'), ('美国', '纽约'), ('美国', '洛杉矶')], names=['国家', '城市']) df = pd.DataFrame(data, index=index) print(df)
输出:
温度 湿度 国家 中国 北京 25 60 上海 28 70 美国 纽约 30 65 洛杉矶 32 75
现在,我们的 DataFrame 就有了 MultiIndex,看起来更清晰了吧?
MultiIndex 的核心:切片和选择
有了 MultiIndex 之后,最重要的就是如何利用它来切片和选择数据。 这部分是 MultiIndex 的精华所在,也是最容易让人头疼的地方。
-
基本切片
最基本的切片方式就是直接使用
loc
或者iloc
。loc
使用索引标签,iloc
使用整数位置。# 选择中国的数据 print(df.loc['中国']) # 选择中国北京的数据 print(df.loc[('中国', '北京')]) # 选择第一行数据 print(df.iloc[0])
输出:
温度 湿度 城市 北京 25 60 上海 28 70 温度 25 湿度 60 Name: (中国, 北京), dtype: int64 温度 25 湿度 60 Name: (中国, 北京), dtype: int64
注意,当选择多层索引时,你需要用元组来指定索引值。
-
使用
pd.IndexSlice
进行高级切片pd.IndexSlice
是 MultiIndex 切片的利器,它可以让你更灵活地选择数据。idx = pd.IndexSlice # 选择所有国家的北京的数据 print(df.loc[idx[:, '北京'], :]) # 选择中国的所有数据,以及美国的纽约的数据 print(df.loc[idx[['中国', ('美国', '纽约')], :], :])
输出:
温度 湿度 国家 中国 北京 25 60 美国 北京 30 65 温度 湿度 国家 中国 北京 25 60 上海 28 70 美国 纽约 30 65
idx[:, '北京']
的意思是选择所有国家,但是只选择城市为北京的数据。idx[['中国', ('美国', '纽约')], :]
的意思是选择中国的所有数据,以及美国的纽约的数据。pd.IndexSlice
的强大之处在于它可以处理各种复杂的切片需求。 -
使用
xs
方法进行交叉选择xs
方法可以让你选择特定层级的索引值。# 选择所有城市的温度数据 print(df.xs('温度', axis=1)) # 选择中国的数据 print(df.xs('中国')) # 选择城市为北京的数据 print(df.xs('北京', level='城市'))
输出:
国家 城市 中国 北京 25 上海 28 美国 纽约 30 洛杉矶 32 Name: 温度, dtype: int64 温度 湿度 城市 北京 25 60 上海 28 70 温度 湿度 国家 中国 25 60 美国 30 65
xs('北京', level='城市')
的意思是选择城市这一层索引值为北京的数据。xs
方法非常适合在特定层级上进行选择。
MultiIndex 的进阶:数据重塑和聚合
MultiIndex 不仅可以帮助你更好地组织数据,还可以让你更方便地进行数据重塑和聚合。
-
stack
和unstack
:数据堆叠和展开stack
和unstack
是 MultiIndex 中非常重要的两个方法,它们可以让你在不同的索引层级之间进行转换。# 将城市这一层索引展开到列 print(df.unstack(level='城市')) # 将温度和湿度这两列堆叠到索引 print(df.stack())
输出:
温度 湿度 城市 北京 上海 纽约 洛杉矶 北京 上海 纽约 洛杉矶 国家 中国 25 28 NaN NaN 60 70 NaN NaN 美国 NaN NaN 30 32 NaN NaN 65 75 国家 城市 中国 北京 温度 25 湿度 60 上海 温度 28 湿度 70 美国 纽约 温度 30 湿度 65 洛杉矶 温度 32 湿度 75 dtype: int64
unstack
将指定的索引层级展开到列,stack
将列堆叠到索引。 这两个方法可以让你轻松地进行数据透视。 -
groupby
:分组聚合MultiIndex 和
groupby
简直是天生一对! 你可以根据 MultiIndex 的不同层级进行分组聚合。# 按照国家进行分组,计算平均温度 print(df.groupby(level='国家')['温度'].mean()) # 按照城市进行分组,计算平均温度 print(df.groupby(level='城市')['温度'].mean())
输出:
国家 中国 26.5 美国 31.0 Name: 温度, dtype: float64 城市 北京 25 上海 28 纽约 30 洛杉矶 32 Name: 温度, dtype: int64
groupby(level='国家')
的意思是按照国家这一层索引进行分组。 -
pivot_table
:数据透视表pivot_table
也是一个强大的数据透视工具,它可以让你更灵活地进行数据聚合。# 创建一个更复杂的 DataFrame data = { '温度': [25, 28, 30, 32, 26, 29, 31, 33], '湿度': [60, 70, 65, 75, 62, 72, 67, 77], '年份': [2022, 2022, 2022, 2022, 2023, 2023, 2023, 2023] } index = pd.MultiIndex.from_product([['中国', '美国'], ['北京', '上海', '纽约', '洛杉矶']], names=['国家', '城市']) df = pd.DataFrame(data, index=index) # 使用 pivot_table 创建数据透视表,按照国家和年份计算平均温度 print(pd.pivot_table(df, values='温度', index='国家', columns='年份', aggfunc='mean'))
输出:
年份 2022 2023 国家 中国 26.5 27.5 美国 31.0 32.0
pivot_table
可以让你指定哪些列作为索引,哪些列作为值,以及使用什么聚合函数。
MultiIndex 的最佳实践:一些建议
-
给索引命名!
一定要给 MultiIndex 的每一层索引命名,这样可以提高代码的可读性,并且方便后续的操作。
-
保持索引的顺序一致
在创建 MultiIndex 时,要确保索引的顺序和数据的顺序一致,否则会导致数据错位。
-
谨慎使用
set_index
和reset_index
set_index
可以将 DataFrame 的列设置为索引,reset_index
可以将索引重置为列。 这两个方法在处理 MultiIndex 时要小心,因为它们可能会改变数据的结构。 -
多练习!
MultiIndex 的学习曲线比较陡峭,需要多练习才能掌握。 可以尝试用 MultiIndex 来处理一些实际的数据集,例如气象数据、股票数据、销售数据等等。
MultiIndex 的实际案例:股票数据分析
我们来看一个使用 MultiIndex 进行股票数据分析的例子。
假设我们有以下股票数据:
股票代码 日期 开盘价 收盘价 成交量
AAPL 2023-01-01 130 132 10000
AAPL 2023-01-02 133 135 12000
MSFT 2023-01-01 250 252 8000
MSFT 2023-01-02 253 255 9000
我们可以使用 MultiIndex 来组织这些数据,并进行一些简单的分析。
import pandas as pd
data = {
'股票代码': ['AAPL', 'AAPL', 'MSFT', 'MSFT'],
'日期': ['2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02'],
'开盘价': [130, 133, 250, 253],
'收盘价': [132, 135, 252, 255],
'成交量': [10000, 12000, 8000, 9000]
}
df = pd.DataFrame(data)
# 将股票代码和日期设置为 MultiIndex
df = df.set_index(['股票代码', '日期'])
print(df)
# 计算每个股票的平均成交量
print(df.groupby(level='股票代码')['成交量'].mean())
# 选择 AAPL 的所有数据
print(df.loc['AAPL'])
输出:
开盘价 收盘价 成交量
股票代码 日期
AAPL 2023-01-01 130 132 10000
2023-01-02 133 135 12000
MSFT 2023-01-01 250 252 8000
2023-01-02 253 255 9000
股票代码
AAPL 11000.0
MSFT 8500.0
Name: 成交量, dtype: float64
开盘价 收盘价 成交量
日期
2023-01-01 130 132 10000
2023-01-02 133 135 12000
这个例子展示了如何使用 MultiIndex 来组织股票数据,并进行一些简单的分析,例如计算平均成交量和选择特定股票的数据。
总结
MultiIndex 是 Pandas 中一个非常强大的功能,它可以让你更好地组织和处理复杂的数据。 虽然学习曲线比较陡峭,但是一旦掌握了它,你就可以更高效地进行数据分析和处理。
希望今天的讲座能帮助你更好地理解和使用 Pandas MultiIndex。 记住,多练习,多实践,你就能成为 MultiIndex 大师!
谢谢大家!