Pandas 多层索引(MultiIndex)
多层索引(MultiIndex)是 Pandas 中强大的索引功能,允许在行或列上创建多级层次结构。这在处理高维数据、分组统计和面板数据时特别有用。
创建 MultiIndex
从列表创建
实例
import pandas as pd
# 方法1:使用数组创建
arrays = [
["A", "A", "B", "B", "C", "C"],
[1, 2, 1, 2, 1, 2]
]
# 使用 pd.MultiIndex.from_arrays
index = pd.MultiIndex.from_arrays(arrays, names=["类别", "编号"])
print("从数组创建:")
print(index)
print()
# 方法2:使用元组列表
tuples = [
("A", 1), ("A", 2), ("B", 1), ("B", 2), ("C", 1), ("C", 2)
]
index = pd.MultiIndex.from_tuples(tuples, names=["类别", "编号"])
print("从元组创建:")
print(index)
print()
# 方法3:使用 product
index = pd.MultiIndex.from_product(
[["A", "B", "C"], [1, 2, 3]],
names=["类别", "编号"]
)
print("从 product 创建:")
print(index)
# 方法1:使用数组创建
arrays = [
["A", "A", "B", "B", "C", "C"],
[1, 2, 1, 2, 1, 2]
]
# 使用 pd.MultiIndex.from_arrays
index = pd.MultiIndex.from_arrays(arrays, names=["类别", "编号"])
print("从数组创建:")
print(index)
print()
# 方法2:使用元组列表
tuples = [
("A", 1), ("A", 2), ("B", 1), ("B", 2), ("C", 1), ("C", 2)
]
index = pd.MultiIndex.from_tuples(tuples, names=["类别", "编号"])
print("从元组创建:")
print(index)
print()
# 方法3:使用 product
index = pd.MultiIndex.from_product(
[["A", "B", "C"], [1, 2, 3]],
names=["类别", "编号"]
)
print("从 product 创建:")
print(index)
创建带 MultiIndex 的 DataFrame
实例
import pandas as pd
import numpy as np
# 创建带多层索引的 DataFrame
df = pd.DataFrame(
np.random.randn(6, 4),
index=pd.MultiIndex.from_tuples(
[("2024", "Q1"), ("2024", "Q2"), ("2024", "Q3"),
("2025", "Q1"), ("2025", "Q2"), ("2025", "Q3")]
),
columns=["北京", "上海", "广州", "深圳"]
)
df.index.names = ["年份", "季度"]
print("带多层索引的 DataFrame:")
print(df)
import numpy as np
# 创建带多层索引的 DataFrame
df = pd.DataFrame(
np.random.randn(6, 4),
index=pd.MultiIndex.from_tuples(
[("2024", "Q1"), ("2024", "Q2"), ("2024", "Q3"),
("2025", "Q1"), ("2025", "Q2"), ("2025", "Q3")]
),
columns=["北京", "上海", "广州", "深圳"]
)
df.index.names = ["年份", "季度"]
print("带多层索引的 DataFrame:")
print(df)
多层索引的访问
使用 loc/iloc 访问
实例
import pandas as pd
# 创建示例数据
df = pd.DataFrame({
"语文": [85, 92, 78, 88],
"数学": [90, 88, 95, 82]
}, index=pd.MultiIndex.from_tuples(
[("高一", "A班"), ("高一", "B班"), ("高二", "A班"), ("高二", "B班")],
names=["年级", "班级"]
))
print("原始数据:")
print(df)
print()
# 外层索引访问
print("访问所有高一年级:")
print(df.loc["高一"])
print()
# 内层索引访问
print("访问 A 班:")
print(df.loc[:, "A班"])
print()
# 多层索引访问
print("访问高一的 A 班:")
print(df.loc[("高一", "A班")])
# 创建示例数据
df = pd.DataFrame({
"语文": [85, 92, 78, 88],
"数学": [90, 88, 95, 82]
}, index=pd.MultiIndex.from_tuples(
[("高一", "A班"), ("高一", "B班"), ("高二", "A班"), ("高二", "B班")],
names=["年级", "班级"]
))
print("原始数据:")
print(df)
print()
# 外层索引访问
print("访问所有高一年级:")
print(df.loc["高一"])
print()
# 内层索引访问
print("访问 A 班:")
print(df.loc[:, "A班"])
print()
# 多层索引访问
print("访问高一的 A 班:")
print(df.loc[("高一", "A班")])
使用 xs 访问
实例
import pandas as pd
# 创建示例数据
df = pd.DataFrame({
"语文": [85, 92, 78, 88],
"数学": [90, 88, 95, 82]
}, index=pd.MultiIndex.from_tuples(
[("高一", "A班"), ("高一", "B班"), ("高二", "A班"), ("高二", "B班")],
names=["年级", "班级"]
))
# 使用 xs 访问特定层级的值
print("使用 xs 访问高一年级:")
print(df.xs("高一", level="年级"))
print()
print("使用 xs 访问 A 班:")
print(df.xs("A班", level="班级"))
# 创建示例数据
df = pd.DataFrame({
"语文": [85, 92, 78, 88],
"数学": [90, 88, 95, 82]
}, index=pd.MultiIndex.from_tuples(
[("高一", "A班"), ("高一", "B班"), ("高二", "A班"), ("高二", "B班")],
names=["年级", "班级"]
))
# 使用 xs 访问特定层级的值
print("使用 xs 访问高一年级:")
print(df.xs("高一", level="年级"))
print()
print("使用 xs 访问 A 班:")
print(df.xs("A班", level="班级"))
多层索引的转换
堆叠与展开
实例
import pandas as pd
import numpy as np
# 创建宽格式 DataFrame
df = pd.DataFrame(
np.arange(12).reshape(3, 4),
index=pd.MultiIndex.from_tuples(
[("北京", "2024"), ("上海", "2024"), ("广州", "2024")]
),
columns=pd.MultiIndex.from_tuples(
[("Q1", "营收"), ("Q1", "利润"), ("Q2", "营收"), ("Q2", "利润")]
)
)
print("原始数据(嵌套列):")
print(df)
print()
# unstack:将内层索引转为列
df_unstacked = df.unstack()
print("unstack 后:")
print(df_unstacked)
print()
# stack:将列转为内层索引
df_stacked = df_unstacked.stack()
print("stack 后:")
print(df_stacked)
import numpy as np
# 创建宽格式 DataFrame
df = pd.DataFrame(
np.arange(12).reshape(3, 4),
index=pd.MultiIndex.from_tuples(
[("北京", "2024"), ("上海", "2024"), ("广州", "2024")]
),
columns=pd.MultiIndex.from_tuples(
[("Q1", "营收"), ("Q1", "利润"), ("Q2", "营收"), ("Q2", "利润")]
)
)
print("原始数据(嵌套列):")
print(df)
print()
# unstack:将内层索引转为列
df_unstacked = df.unstack()
print("unstack 后:")
print(df_unstacked)
print()
# stack:将列转为内层索引
df_stacked = df_unstacked.stack()
print("stack 后:")
print(df_stacked)
多层索引的排序
实例
import pandas as pd
# 创建带乱序索引的 DataFrame
df = pd.DataFrame({
"值": [1, 2, 3, 4, 5, 6]
}, index=pd.MultiIndex.from_tuples(
[("C", 2), ("A", 1), ("B", 2), ("A", 2), ("C", 1), ("B", 1)],
names=["字母", "数字"]
))
print("乱序数据:")
print(df)
print()
# 按外层排序
df_sorted1 = df.sort_index()
print("按外层排序后:")
print(df_sorted1)
print()
# 按内层排序
df_sorted2 = df.sort_index(level=1)
print("按内层排序后:")
print(df_sorted2)
print()
# 多层排序
df_sorted3 = df.sort_index(level=[0, 1])
print("按多层排序后:")
print(df_sorted3)
# 创建带乱序索引的 DataFrame
df = pd.DataFrame({
"值": [1, 2, 3, 4, 5, 6]
}, index=pd.MultiIndex.from_tuples(
[("C", 2), ("A", 1), ("B", 2), ("A", 2), ("C", 1), ("B", 1)],
names=["字母", "数字"]
))
print("乱序数据:")
print(df)
print()
# 按外层排序
df_sorted1 = df.sort_index()
print("按外层排序后:")
print(df_sorted1)
print()
# 按内层排序
df_sorted2 = df.sort_index(level=1)
print("按内层排序后:")
print(df_sorted2)
print()
# 多层排序
df_sorted3 = df.sort_index(level=[0, 1])
print("按多层排序后:")
print(df_sorted3)
实战:分组统计
多层索引非常适合进行分组统计和透视分析。
实例
import pandas as pd
import numpy as np
# 创建销售数据
np.random.seed(42)
df = pd.DataFrame({
"年份": ["2023"] * 6 + ["2024"] * 6,
"季度": ["Q1", "Q2", "Q3", "Q4"] * 3,
"产品": ["手机", "手机", "电脑", "电脑"] * 3,
"区域": ["华东", "华南", "华北"] * 4,
"销售额": np.random.randint(100, 500, 12)
})
print("原始销售数据:")
print(df)
print()
# 设置多层索引后进行分组统计
df_grouped = df.set_index(["年份", "季度", "产品", "区域"])
print("按年份、季度、产品、区域分组:")
print(df_grouped)
# 按年份汇总
yearly = df_grouped.groupby(level="年份").sum()
print("\n年度销售额:")
print(yearly)
# 按年份和季度汇总
quarterly = df_grouped.groupby(level=["年份", "季度"]).sum()
print("\n季度销售额:")
print(quarterly)
import numpy as np
# 创建销售数据
np.random.seed(42)
df = pd.DataFrame({
"年份": ["2023"] * 6 + ["2024"] * 6,
"季度": ["Q1", "Q2", "Q3", "Q4"] * 3,
"产品": ["手机", "手机", "电脑", "电脑"] * 3,
"区域": ["华东", "华南", "华北"] * 4,
"销售额": np.random.randint(100, 500, 12)
})
print("原始销售数据:")
print(df)
print()
# 设置多层索引后进行分组统计
df_grouped = df.set_index(["年份", "季度", "产品", "区域"])
print("按年份、季度、产品、区域分组:")
print(df_grouped)
# 按年份汇总
yearly = df_grouped.groupby(level="年份").sum()
print("\n年度销售额:")
print(yearly)
# 按年份和季度汇总
quarterly = df_grouped.groupby(level=["年份", "季度"]).sum()
print("\n季度销售额:")
print(quarterly)
常见问题与注意事项
1、索引层次混乱
操作数据时要小心,避免层次错乱。建议在操作前后检查 df.index.names。
2、索引访问错误
loc 使用标签访问,iloc 使用位置访问,两者不要混用。
3、concat 时索引重复
使用 concat 合并数据时,若有重复索引可能导致意外结果,可使用 ignore_index=True 重置。
多层索引是 Pandas 处理高维数据的核心功能。合理使用多层索引可以让数据组织更清晰,统计更便捷。
