Index 是 Pandas 的核心底层组件,Series 自带索引,DataFrame 拥有行索引 index、列索引 columns。索引不只是序号,它负责对齐、分组、切片、性能加速、多表合并。本文讲解基础索引、常用索引类型、构造、修改、切片、对齐、多级索引、索引优化、踩坑,延续整套教程风格。
前置导入
import pandas as pd
import numpy as np
一、索引是什么
Series:values+indexDataFrame:行索引df.index,列索引df.columns- Index 是不可变序列,哈希化,支持快速查找;不能直接修改单个元素
- 核心作用:数据自动对齐、标签筛选、分组、join、排序、高性能定位
s = pd.Series([10,20,30], index=["a","b","c"])
print(s.index)
df = pd.DataFrame({"x":[1,2],"y":[3,4]}, index=["p1","p2"])
print(df.index)
print(df.columns)
Index 常见子类:
RangeIndex:默认整数索引(0,1,2…),省内存Index:通用标签索引(字符串、数字)DatetimeIndex:时间索引(时序分析、股票行情高频)MultiIndex:多级索引(分组、透视表)CategoricalIndex:分类索引PeriodIndex:周期索引(年月季度)Float64Index/Int64Index:数值索引
二、创建 Index
2.1 基础构造
# 普通索引
idx = pd.Index(["apple","banana","orange"], name="fruit")
# 整数索引
idx_int = pd.Index([101,102,103])
# 时间索引
dt_idx = pd.date_range("2026-01-01", periods=5, freq="D")
# 多级索引
midx = pd.MultiIndex.from_tuples([("线上","键盘"),("线上","鼠标")], names=["渠道","商品"])
2.2 从已有数据生成索引
df = pd.DataFrame({
"商品":["键盘","鼠标","显示器"],
"金额":[178,45,1200]
})
# 设置行索引
df = df.set_index("商品")
print(df.index)
三、索引基本属性与方法
idx = pd.Index(["a","b","c","d"])
# 属性
idx.name # 索引名称
idx.values # 底层numpy数组
idx.is_unique # 是否唯一(非常重要!)
idx.is_monotonic_increasing # 是否单调递增(切片、搜索加速)
idx.has_duplicates # 是否存在重复值
# 常用方法
idx.append(pd.Index(["e"]))
idx.drop("a")
idx.unique()
idx.sort_values()
idx.get_indexer(["b","d"]) # 返回位置下标
idx.isin(["b","c"]) # 成员判断,返回布尔数组
⚠️ Index 不可变:
idx[0] = "x"直接报错,修改必须生成新索引。
四、RangeIndex(默认索引)
新建DataFrame不指定index时,默认就是 RangeIndex
df = pd.DataFrame({"a":[1,2,3]})
print(type(df.index)) # RangeIndex
特点:
- 不存储全部数字,只存 start, stop, step,内存极小
- 一旦手动赋值、reset_index,经常变成普通 Int64Index
五、DatetimeIndex 时间索引(时序重点)
dates = pd.date_range("2026-01-01", periods=10, freq="D")
s = pd.Series(range(10), index=dates)
# 强大的切片语法
s["2026-01-03"]
s["2026-01-01":"2026-01-05"]
s["2026-01"] # 取整个1月
# 按时间偏移、重采样
s.resample("3D").sum()
时间索引支持:year, month, day, weekday, hour 访问器。
六、索引定位:loc / iloc 核心区分
loc:按索引标签查找(匹配 index 的值)iloc:按位置下标查找(0,1,2…)
df = pd.DataFrame({"val":[10,20,30]}, index=["x","y","z"])
df.loc["y"]
df.iloc[1]
坑:当索引是数字时,很容易混淆 loc 和 iloc!
比如 index=[2,4,6],df.loc[2]是匹配标签2,不是第2行。
七、索引修改 set_index / reset_index
df = pd.DataFrame({
"商品":["键盘","鼠标"],
"渠道":["线上","线下"],
"金额":[178,45]
})
# 设置索引
df1 = df.set_index("商品")
# 多列设为多级索引
df2 = df.set_index(["渠道","商品"])
# 索引变回普通列
df3 = df1.reset_index()
# 重置索引并丢弃旧索引
df4 = df1.reset_index(drop=True)
八、索引对齐(Pandas最独特的机制)
两个Series/DataFrame运算时,自动按索引对齐,匹配不上的位置填充NaN
s1 = pd.Series([1,2,3], index=["a","b","c"])
s2 = pd.Series([10,20], index=["b","c"])
s = s1 + s2
print(s)
输出:a:NaN,b:12,c:23
很多新手疑惑为什么相加后出现NaN,根源就是索引对不齐。
align 手动对齐两个索引:
s1_align, s2_align = s1.align(s2, fill_value=0)
九、MultiIndex 多级索引
df = pd.DataFrame({
"数量":[2,1,3,2],
"金额":[178,45,267,90]
}, index=pd.MultiIndex.from_tuples(
[("线上","键盘"),("线上","鼠标"),("线下","键盘"),("线下","鼠标")],
names=["渠道","商品"]
))
# 取一级索引
df.loc["线上"]
# 两层精确取值
df.loc[("线上","键盘")]
# 交换层级
df.swaplevel("渠道","商品")
# 排序索引(多级索引强烈建议排序,提升loc性能)
df = df.sort_index()
多级索引如果不排序,切片
df.loc["线上":]会报错。
展平多级索引:
df = df.reset_index()
十、索引排序 sort_index
df = df.sort_index()
# 列索引排序
df = df.sort_index(axis=1)
# 降序
df = df.sort_index(ascending=False)
索引排序后:
- loc切片支持范围选取
- 查找、join、merge 速度大幅提升
十一、索引去重、唯一索引
很多高级操作(join、asof、快速loc查询)要求索引唯一:
# 检查重复
df.index.has_duplicates
# 去重,保留第一个
df = df[~df.index.duplicated(keep="first")]
duplicated 参数:keep="first"/"last"/False
十二、reindex 重建索引(补行、补时间缺口)
reindex 按照新索引序列重新排列数据,缺失位置填充NaN或指定值
s = pd.Series([10,20], index=["a","b"])
new_idx = ["a","b","c","d"]
s_new = s.reindex(new_idx, fill_value=0)
时序场景补全交易日、自然日缺口高频使用:
idx_all = pd.date_range("2026-01-01","2026-01-10", freq="D")
df = df.reindex(idx_all)
十三、索引性能优化(配合前面性能优化章节)
- 高频查询、关联字段设为索引,
locO(1),远快于布尔筛选 - 索引尽量保证唯一、单调递增
- 优先 DatetimeIndex 做时序,不要用字符串日期
- 分组键如果固定,设置为索引,groupby更快
- join 比 merge 快的前提:两边关联键都是索引
df1.join(df2) # 索引对索引连接,速度更快
- 避免频繁 reset_index / set_index,会产生副本、消耗内存
十四、列索引 columns 操作
columns 本质也是 Index 对象
df.columns.name = "指标"
# 重命名列
df = df.rename(columns={"金额":"销售金额"})
# 列索引转列表
col_list = df.columns.tolist()
十五、常见坑汇总
- 索引是数字标签时,
loc和iloc极易混淆 - 多级索引未排序,范围切片报错
- 运算出现莫名NaN:索引没有对齐
- 重复索引:
loc会返回多行,很多算法、join不支持重复索引 - DatetimeIndex 带时区和不带时区的时间索引不能对齐
- 不要在循环里频繁 set_index / reset_index,产生大量副本
- RangeIndex 一旦修改,会变成普通Int64Index,内存变大
十六、Index 速查表
| 操作 | 作用 |
|---|---|
| df.index / df.columns | 读取行、列索引 |
| set_index | 设置列为行索引 |
| reset_index | 索引变回普通列 |
| sort_index | 索引排序 |
| reindex | 按新索引重排、补缺失 |
| loc | 标签索引取值 |
| iloc | 位置下标取值 |
| MultiIndex | 多层索引 |
| is_unique / has_duplicates | 检查重复索引 |
| align | 两个对象索引对齐 |
十七、实战模板:时序标准索引流程
def set_time_index(df):
df["date"] = pd.to_datetime(df["date"])
df = df.set_index("date")
df = df.sort_index()
# 补全日历日期,空缺填充0
idx_range = pd.date_range(start=df.index.min(), end=df.index.max(), freq="D")
df = df.reindex(idx_range, fill_value=0)
return df
0 条笔记