Pandas: Index 索引
最后更新:2026-08-26
Index 是 Pandas 最被低估、却又最强大的特性。它不仅是"行标签"——Index 是数据对齐的核心机制,是 Series 和 DataFrame 运算时自动匹配的"钥匙"。理解了 Index,你就理解了 Pandas 为什么比 NumPy 更适合数据分析。本节深入 Index 的本质、类型和对齐机制。
⚠️ 注意: 以下代码需在本地 Python 环境中运行。
1. 你将学到
- ❶ Index 的本质与类型体系
- ❷ set_index / reset_index 操作
- ❸ 索引对齐机制(Pandas 最重要的特性)
- ❹ reindex 与 align
- ❺ Index 的常用属性与方法
2. Alice 的两月销售对齐难题
(1) 痛点:数据行不对齐
Alice 的咖啡店 1 月和 2 月销售天数不同(1 月 31 天,2 月 28 天),而且有些天关门了。她需要把两月数据合并对比:
PYTHON
import pandas as pd
# January sales (some days closed)
jan = pd.Series({'Mon': 320, 'Tue': 280, 'Wed': 350, 'Thu': 410, 'Fri': 390})
# February sales (different days, Mon/Tue closed)
feb = pd.Series({'Wed': 370, 'Thu': 420, 'Fri': 400, 'Sat': 550, 'Sun': 510})
# NumPy-style: would just add position by position — WRONG!
# Pandas: auto-aligns by index label
total = jan + feb
print(total)
# Fri 790.0 ← matched!
# Mon NaN ← only in jan
# Sat NaN ← only in feb
# Sun NaN ← only in feb
# Thu 830.0 ← matched!
# Tue NaN ← only in jan
# Wed 720.0 ← matched!
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) 解法:Index 自动对齐
Pandas 运算时按 Index 标签自动对齐——相同标签的值相加,不同标签填 NaN。你不需要手动匹配数据。
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:对齐运算与 fill_value(难度⭐⭐)
PYTHON
import pandas as pd
jan = pd.Series({'Mon': 320, 'Tue': 280, 'Wed': 350, 'Thu': 410, 'Fri': 390})
feb = pd.Series({'Wed': 370, 'Thu': 420, 'Fri': 400, 'Sat': 550, 'Sun': 510})
# Fill missing with 0 for cleaner comparison
total = jan.add(feb, fill_value=0)
print(total.sort_index())
# Fri 790.0
# Mon 320.0 ← jan only, feb=0
# Sat 550.0 ← feb only, jan=0
# Sun 510.0 ← feb only, jan=0
# Thu 830.0
# Tue 280.0 ← jan only, feb=0
# Wed 720.0
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(3) 收益:Index 对齐避免隐蔽 bug
如果用 NumPy 按位置相加,jan[0] + feb[0] 就是 320 + 370 = 690——但 Mon 和 Wed 根本不是同一天!Index 对齐让你从"位置匹配"的错误中解放出来。
3. Index 的本质与类型
(1) Index 不是普通数组
Index 是一个不可变的、类似 ndarray 的对象,专门用于标签索引和对齐。它的关键特性:
- 不可变:创建后不能修改(保证数据安全)
- 可哈希:可以作为字典键、集合元素
- 支持重复:允许重复标签(但会降低性能)
- 多种子类型:RangeIndex / DatetimeIndex / CategoricalIndex 等
graph TB
IDX["Index (Base)"] --> RI["RangeIndex<br/>auto-generated 0,1,2,..."]
IDX --> DI["DatetimeIndex<br/>time-based labels"]
IDX --> CI["CategoricalIndex<br/>finite set of categories"]
IDX --> MI["MultiIndex<br/>hierarchical labels"]
IDX --> GI["General Index<br/>arbitrary labels"]
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) Index 类型对比
| 类型 | 创建方式 | 典型场景 | 特殊功能 |
|---|---|---|---|
| RangeIndex | 默认 | 未指定 index 时 | 内存高效 |
| Index | 手动指定 | 字符串/数字标签 | 通用 |
| DatetimeIndex | pd.date_range | 时间序列 | 频率/偏移/重采样 |
| CategoricalIndex | dtype='category' | 有限类别 | 有序/无序分类 |
| MultiIndex | from_tuples/from_product | 层次数据 | 分层选取 |
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:Index 类型检查(难度⭐)
PYTHON
import pandas as pd
# RangeIndex (default)
s1 = pd.Series([1, 2, 3])
print(type(s1.index)) # <class 'pandas.core.indexes.range.RangeIndex'>
# General Index (string labels)
s2 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
print(type(s2.index)) # <class 'pandas.core.indexes.base.Index'>
# DatetimeIndex
dates = pd.date_range('2026-01-01', periods=5)
s3 = pd.Series([100, 200, 150, 300, 250], index=dates)
print(type(s3.index)) # <class 'pandas.core.indexes.datetimes.DatetimeIndex'>
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
4. set_index 与 reset_index
(1) set_index:把列变为行标签
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:set_index 用法(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'product': ['Coffee', 'Tea', 'Juice'],
'price': [4.50, 3.80, 5.20],
'category': ['Hot', 'Hot', 'Cold']
})
# Set product as index
df_indexed = df.set_index('product')
print(df_indexed)
# price category
# product
# Coffee 4.50 Hot
# Tea 3.80 Hot
# Juice 5.20 Cold
print(df_indexed.loc['Coffee', 'price']) # 4.5
# Drop the column after setting (default=True)
# Keep the column: drop=False
df_keep = df.set_index('product', drop=False)
print(df_keep.columns) # still has 'product'
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) reset_index:把行标签还原为列
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:reset_index 用法(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'price': [4.50, 3.80, 5.20]
}, index=['Coffee', 'Tea', 'Juice'])
# Reset index back to column
df_reset = df.reset_index()
print(df_reset)
# index price
# 0 Coffee 4.50
# 1 Tea 3.80
# 2 Juice 5.20
# Name the new column
df_reset2 = df.reset_index(names='product')
print(df_reset2.columns) # Index(['product', 'price'])
# Drop index entirely (don't keep as column)
df_drop = df.reset_index(drop=True)
print(df_drop)
# price
# 0 4.50
# 1 3.80
# 2 5.20
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(3) set_index vs reset_index 对比
| 操作 | set_index | reset_index |
|---|---|---|
| 方向 | 列→行标签 | 行标签→列 |
| 原列 | 默认删除(drop=True) | 保留为新列 |
| 默认 index | 无(需指定列) | RangeIndex(0,1,2,...) |
| 就地修改 | 默认否(inplace=False) | 默认否 |
5. 索引对齐机制详解
(1) 对齐规则
当两个 Pandas 对象(Series 或 DataFrame)做运算时:
- 取两者 Index 的并集
- 匹配的标签做运算
- 不匹配的标签填 NaN
graph LR
A["Series A<br/>{a:1, b:2, c:3}"] --> ADD["A + B"]
B["Series B<br/>{b:20, c:30, d:40}"] --> ADD
ADD --> R["Result<br/>{a:NaN, b:22, c:33, d:NaN}"]
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:DataFrame 对齐(难度⭐⭐)
PYTHON
import pandas as pd
df1 = pd.DataFrame({'A': [1, 2, 3]}, index=['x', 'y', 'z'])
df2 = pd.DataFrame({'A': [10, 20, 30]}, index=['y', 'z', 'w'])
result = df1 + df2
print(result)
# A
# w NaN
# x NaN
# y 22.0
# z 33.0
# With fill_value
result2 = df1.add(df2, fill_value=0)
print(result2)
# A
# w 30.0
# x 1.0
# y 22.0
# z 33.0
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
💡 提示: Index 对齐不仅发生在 +、-、*、/ 运算中,也发生在 add/sub/mul/div 等方法中。
fill_value 参数只对缺失的一方生效,双方都缺失时结果仍为 NaN。
6. reindex 与 align
(1) reindex:重塑索引
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:reindex 用法(难度⭐⭐)
PYTHON
import pandas as pd
s = pd.Series([320, 280, 350], index=['Mon', 'Tue', 'Wed'])
# Reindex to include new labels (fill with NaN)
s_full = s.reindex(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])
print(s_full)
# Mon 320.0
# Tue 280.0
# Wed 350.0
# Thu NaN
# Fri NaN
# Fill missing values
s_filled = s.reindex(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], fill_value=0)
print(s_filled)
# Forward fill (use previous value)
s_ffill = s.reindex(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], method='ffill')
print(s_ffill)
# Thu gets Wed's value (350)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) align:对齐两个 Series
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:align 对齐(难度⭐⭐)
PYTHON
import pandas as pd
s1 = pd.Series({'a': 1, 'b': 2, 'c': 3})
s2 = pd.Series({'b': 20, 'c': 30, 'd': 40})
# Align both to union index
s1_aligned, s2_aligned = s1.align(s2)
print(s1_aligned)
# a 1.0
# b 2.0
# c 3.0
# d NaN
print(s2_aligned)
# a NaN
# b 20.0
# c 30.0
# d 40.0
# Align with fill_value
s1_f, s2_f = s1.align(s2, fill_value=0)
print(s1_f)
# a 1
# b 2
# c 3
# d 0
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(3) reindex vs align 对比
| 方法 | 作用 | 适用场景 |
|---|---|---|
| reindex | 按新索引重塑单个对象 | 扩展/重排索引 |
| align | 同时对齐两个对象 | 两个对象互相匹配 |
7. Index 常用属性与方法
(1) 属性速查
| 属性/方法 | 说明 | 示例结果 |
|---|---|---|
idx.is_unique |
是否唯一 | True / False |
idx.is_monotonic_increasing |
是否单调递增 | True / False |
idx.has_duplicates |
是否有重复 | True / False |
idx.nunique() |
唯一值个数 | 7 |
idx.duplicated() |
重复标记 | 布尔数组 |
idx.drop_duplicates() |
去重 | 新 Index |
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:Index 属性检查(难度⭐)
PYTHON
import pandas as pd
idx1 = pd.Index(['a', 'b', 'c', 'd'])
idx2 = pd.Index(['a', 'b', 'b', 'c'])
print(idx1.is_unique) # True
print(idx2.is_unique) # False
print(idx2.has_duplicates) # True
print(idx1.nunique()) # 4
print(idx2.duplicated()) # [False, False, True, False]
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
8. 完整示例:月度销售数据对齐与重组
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:两月销售对齐全流程(难度⭐⭐⭐)
PYTHON
import pandas as pd
import numpy as np
# ============================================
# Comprehensive example: Monthly sales data
# alignment and reorganization using Index
# ============================================
# 1. Two months of daily sales (different days)
jan = pd.Series({
'2026-01-06': 320, '2026-01-07': 280, '2026-01-08': 350,
'2026-01-09': 410, '2026-01-10': 390
}, name='jan_sales')
feb = pd.Series({
'2026-02-04': 370, '2026-02-05': 420, '2026-02-06': 400,
'2026-02-07': 550
}, name='feb_sales')
# 2. Index info
print("=== Index Analysis ===")
print(f"Jan unique: {jan.index.is_unique}") # True
print(f"Feb unique: {feb.index.is_unique}") # True
# 3. Align both months to common format
jan_a, feb_a = jan.align(feb, fill_value=0)
print(f"\n=== Aligned Data ===")
comparison = pd.DataFrame({'jan': jan_a, 'feb': feb_a})
print(comparison)
# 4. Set index on DataFrame for label-based access
df = pd.DataFrame({
'product': ['Latte', 'Cappuccino', 'Espresso', 'Mocha', 'Americano'],
'price': [5.50, 4.80, 3.50, 5.20, 3.00],
'category': ['Specialty', 'Specialty', 'Classic', 'Specialty', 'Classic']
})
print(f"\n=== Products by Category ===")
df_cat = df.set_index('category')
print(df_cat.loc['Specialty', ['product', 'price']])
# 5. Reindex to ensure all weekdays present
weekday_sales = pd.Series(
[320, 280, 350, 410, 390],
index=['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
)
full_week = weekday_sales.reindex(
['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
fill_value=0
)
print(f"\n=== Full Week Sales ===")
print(full_week)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
❓ 常见问题
Q Index 可以重复吗?
A 可以。Pandas 允许重复 Index,但访问重复标签时返回多个值(一个 Series 而非标量),且会降低性能。用
s.index.is_unique 检查唯一性。建议尽量保持 Index 唯一。Q set_index 会丢失数据吗?
A 默认 drop=True 会把列从 DataFrame 中移除变为 Index。如果需要保留列,用
df.set_index('col', drop=False)。Index 信息始终可以通过 reset_index 还原为列。Q 对齐机制什么时候触发?
A 所有二元运算(+、-、*、/、add、sub 等)自动触发 Index 对齐。比较运算(>、<、==)也会对齐。赋值操作(s1[s1 > 0] = ...)不触发对齐。DataFrame 之间的运算同时按行 Index 和列 Columns 对齐。
Q reindex 和 loc 区别?
A reindex 可以添加新标签(用 fill_value 填充),loc 只能访问已有标签(访问不存在的标签报 KeyError)。reindex 的目的是"重塑索引到指定格式",loc 的目的是"按标签选取数据"。
Q 什么时候用 CategoricalIndex?
A 当标签是有限的类别集合时(如星期、月份、州名),CategoricalIndex 能节省内存并保证标签范围。例如用 CategoricalIndex 确保 reindex 时星期一到星期日都出现。
Q Index 不可变怎么修改?
A Index 对象本身不可变,但可以用
df.index = new_index 整体替换,或用 df.rename(index=...) 重命名标签。不能对 Index 的单个元素赋值。Q reset_index 的 drop 参数有什么用?
A drop=True 时丢弃原 Index(不保留为列),得到干净的 RangeIndex。drop=False(默认)时把原 Index 还原为普通列。常见场景:groupby 后 reset_index(drop=True) 清除分组键。
📖 小节
- Index 是 Pandas 数据对齐的核心机制,运算时自动按标签匹配
- Index 不可变、可哈希、允许重复,有 5 种子类型(Range/Datetime/Categorical/Multi/General)
- set_index 把列变为行标签,reset_index 把行标签还原为列
- 对齐规则:取 Index 并集 → 匹配做运算 → 不匹配填 NaN
- reindex 重塑单个对象索引,align 同时对齐两个对象
- 常用属性:is_unique / has_duplicates / nunique() / duplicated()
- 善用 fill_value 参数避免运算时出现不必要的 NaN
📝 作业
- 基础题(难度⭐):创建一个 Series(5 个城市人口),用 set_index 和 reset_index 在 DataFrame 上做转换,观察 index 变化。
- 进阶题(难度⭐⭐):创建两个 Index 不完全相同的 Series,分别用
+运算和add(fill_value=0)做加法,对比结果差异。然后用 align 方法对齐两个 Series。 - 挑战题(难度⭐⭐⭐):用 DatetimeIndex 创建两月销售数据(1 月和 2 月,日期不同),用 reindex 补全两月所有日期(缺失填 0),计算两月同日对比的增长率。