索引操作 #

索引概述 #

索引是 Pandas 的核心概念之一,它提供了数据访问的标签系统。理解索引对于高效使用 Pandas 至关重要。

text
┌─────────────────────────────────────────────────────────────┐
│                       Pandas 索引                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  行索引(Index)                                            │
│  ├── 标识每一行数据                                         │
│  ├── 可以是任意可哈希类型                                   │
│  └── 支持重复值                                             │
│                                                             │
│  列索引(Columns)                                          │
│  ├── 标识每一列数据                                         │
│  ├── 通常是字符串                                           │
│  └── 唯一值                                                 │
│                                                             │
│  多层索引(MultiIndex)                                     │
│  ├── 层次化索引                                             │
│  ├── 支持多维数据                                           │
│  └── 高级数据选择                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

索引类型 #

RangeIndex #

python
import pandas as pd

# 默认索引
df = pd.DataFrame({'A': [1, 2, 3]})
print(df.index)  # RangeIndex(start=0, stop=3, step=1)

# 创建 RangeIndex
idx = pd.RangeIndex(start=0, stop=10, step=2)
print(idx)  # RangeIndex(start=0, stop=10, step=2)

Index(通用索引) #

python
# 列表创建
idx = pd.Index([1, 2, 3, 4, 5])
print(idx)  # Index([1, 2, 3, 4, 5], dtype='int64')

# 字符串索引
idx = pd.Index(['a', 'b', 'c'])
print(idx)  # Index(['a', 'b', 'c'], dtype='object')

# 日期索引
idx = pd.date_range('2024-01-01', periods=5)
print(idx)  # DatetimeIndex(['2024-01-01', ...], dtype='datetime64[ns]', freq='D')

DatetimeIndex #

python
# 创建日期索引
idx = pd.DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03'])

# 使用 date_range
idx = pd.date_range('2024-01-01', periods=5, freq='D')
idx = pd.date_range('2024-01-01', '2024-12-31', freq='M')  # 月末

# 日期属性
print(idx.year)
print(idx.month)
print(idx.day)
print(idx.dayofweek)

PeriodIndex #

python
# 创建周期索引
idx = pd.PeriodIndex(['2024-01', '2024-02', '2024-03'], freq='M')

# 使用 period_range
idx = pd.period_range('2024-01', periods=5, freq='M')

# 周期属性
print(idx.year)
print(idx.month)

TimedeltaIndex #

python
# 创建时间差索引
idx = pd.TimedeltaIndex(['1 day', '2 days', '3 days'])

# 使用 timedelta_range
idx = pd.timedelta_range(start='1 day', periods=5, freq='D')

CategoricalIndex #

python
# 创建分类索引
idx = pd.CategoricalIndex(['a', 'b', 'c', 'a', 'b'])

# 有序分类
idx = pd.CategoricalIndex(['low', 'medium', 'high'], 
                          categories=['low', 'medium', 'high'],
                          ordered=True)

索引属性 #

python
df = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])

# 索引对象
print(df.index)

# 索引值
print(df.index.values)

# 索引名称
print(df.index.name)

# 索引数据类型
print(df.index.dtype)

# 索引是否唯一
print(df.index.is_unique)

# 索引是否有重复
print(df.index.has_duplicates)

# 索引长度
print(len(df.index))

# 索引形状
print(df.index.shape)

设置索引 #

创建时设置 #

python
# 创建时指定索引
df = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])

# 从字典创建
df = pd.DataFrame({'A': [1, 2, 3]}, index=pd.Index(['a', 'b', 'c'], name='idx'))

set_index #

python
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [25, 30, 35],
    'city': ['New York', 'London', 'Tokyo']
})

# 设置单列为索引
df = df.set_index('name')

# 设置多列为索引
df = df.set_index(['city', 'name'])

# 保留原列
df = df.set_index('name', drop=False)

# 追加索引
df = df.set_index('city', append=True)

reset_index #

python
# 重置索引
df = df.reset_index()

# 不保留原索引
df = df.reset_index(drop=True)

# 重置特定层
df = df.reset_index(level=0)  # 多层索引时

索引操作 #

修改索引 #

python
df = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])

# 直接赋值
df.index = ['x', 'y', 'z']

# 修改索引名
df.index.name = 'new_index'

# rename_axis
df = df.rename_axis('rows')
df = df.rename_axis(index='rows', columns='cols')

重命名索引 #

python
# 重命名索引值
df = df.rename(index={'a': 'A', 'b': 'B'})

# 重命名列
df = df.rename(columns={'A': 'a', 'B': 'b'})

# 同时重命名
df = df.rename(index={'a': 'A'}, columns={'A': 'a'})

索引排序 #

python
# 排序索引
df = df.sort_index()
df = df.sort_index(ascending=False)

# 排序列
df = df.sort_index(axis=1)

# 按索引值排序
df = df.sort_values(by='column')

索引选择 #

python
df = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])

# 检查索引是否存在
print('a' in df.index)  # True

# 获取索引位置
print(df.index.get_loc('b'))  # 1

# 获取多个索引位置
print(df.index.get_indexer(['a', 'c']))  # [0, 2]

# 切片
print(df.index[0:2])
print(df.index[:'b'])  # 标签切片(包含结束)

多层索引(MultiIndex) #

创建多层索引 #

python
import pandas as pd

# 从数组创建
arrays = [
    ['a', 'a', 'b', 'b'],
    [1, 2, 1, 2]
]
index = pd.MultiIndex.from_arrays(arrays, names=['letter', 'number'])
df = pd.DataFrame({'A': [1, 2, 3, 4]}, index=index)

# 从元组创建
tuples = [('a', 1), ('a', 2), ('b', 1), ('b', 2)]
index = pd.MultiIndex.from_tuples(tuples, names=['letter', 'number'])

# 从产品创建
index = pd.MultiIndex.from_product([['a', 'b'], [1, 2]], names=['letter', 'number'])

# 从 DataFrame 创建
df_index = pd.DataFrame({'letter': ['a', 'a', 'b', 'b'], 'number': [1, 2, 1, 2]})
index = pd.MultiIndex.from_frame(df_index)

多层索引操作 #

python
arrays = [
    ['a', 'a', 'b', 'b'],
    [1, 2, 1, 2]
]
index = pd.MultiIndex.from_arrays(arrays, names=['letter', 'number'])
df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]}, index=index)

# 查看索引层级
print(df.index.levels)
print(df.index.names)

# 选择数据
print(df.loc['a'])           # 第一层
print(df.loc[('a', 1)])      # 多层
print(df.loc['a', 1])        # 等价

# 切片
print(df.loc['a':'b'])
print(df.loc[('a', 1):('b', 1)])

# xs 方法
print(df.xs('a', level='letter'))
print(df.xs(1, level='number'))

多层索引操作方法 #

python
# 交换层级
df = df.swaplevel('letter', 'number')

# 排序层级
df = df.sort_index(level='letter')
df = df.sort_index(level=0)

# 重置特定层
df = df.reset_index(level='letter')

# 设置新层级
df = df.set_index('A', append=True)

# 重命名层级
df = df.rename_axis(index={'letter': 'char'})

# 重命名层级值
df = df.rename(index={'a': 'A'}, level='letter')

多层列索引 #

python
# 创建多层列索引
columns = pd.MultiIndex.from_product([['A', 'B'], ['x', 'y']])
df = pd.DataFrame([[1, 2, 3, 4], [5, 6, 7, 8]], columns=columns)

# 选择列
print(df['A'])
print(df['A', 'x'])
print(df.loc[:, ('A', 'x')])

# 堆叠和展开
stacked = df.stack()
unstacked = stacked.unstack()

索引对齐 #

自动对齐 #

python
df1 = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])
df2 = pd.DataFrame({'A': [4, 5, 6]}, index=['b', 'c', 'd'])

# 自动对齐
result = df1 + df2
print(result)
#      A
# a  NaN
# b  6.0
# c  8.0
# d  NaN

reindex #

python
df = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])

# 重新索引
df = df.reindex(['a', 'b', 'c', 'd'])
# d 行会填充 NaN

# 填充缺失值
df = df.reindex(['a', 'b', 'c', 'd'], fill_value=0)

# 前向填充
df = df.reindex(['a', 'b', 'c', 'd'], method='ffill')

# 后向填充
df = df.reindex(['a', 'b', 'c', 'd'], method='bfill')

# 重索引列
df = df.reindex(columns=['A', 'B'])

align #

python
df1 = pd.DataFrame({'A': [1, 2]}, index=['a', 'b'])
df2 = pd.DataFrame({'A': [3, 4]}, index=['b', 'c'])

# 对齐两个 DataFrame
df1_aligned, df2_aligned = df1.align(df2)

# 指定填充方式
df1_aligned, df2_aligned = df1.align(df2, fill_value=0)

# 指定轴
df1_aligned, df2_aligned = df1.align(df2, axis=0)

索引性能优化 #

使用唯一索引 #

python
# 唯一索引查找更快
df = pd.DataFrame({'A': range(100000)})
df.index = df.index.astype(str)  # 字符串索引

%timeit df.loc['50000']  # 快

# 重复索引查找较慢
df.index = [str(i % 100) for i in range(100000)]
%timeit df.loc['50']  # 慢

使用排序索引 #

python
# 排序索引查找更快
df = pd.DataFrame({'A': range(100000)})
df = df.sample(frac=1)  # 打乱

%timeit df.loc[50000]  # 未排序,较慢

df = df.sort_index()
%timeit df.loc[50000]  # 排序后,更快

避免链式索引 #

python
# 不推荐:链式索引
df[df['A'] > 0]['B'] = 1  # SettingWithCopyWarning

# 推荐:loc
df.loc[df['A'] > 0, 'B'] = 1

索引实用技巧 #

检查索引 #

python
df = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])

# 检查索引是否单调
print(df.index.is_monotonic_increasing)
print(df.index.is_monotonic_decreasing)

# 检查索引是否唯一
print(df.index.is_unique)

# 检查索引是否有缺失值
print(df.index.hasnans)

索引去重 #

python
df = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'a', 'b'])

# 检查重复
print(df.index.duplicated())

# 去重
df = df[~df.index.duplicated()]
df = df[~df.index.duplicated(keep='last')]
df = df[~df.index.duplicated(keep=False)]

索引差集、交集、并集 #

python
idx1 = pd.Index([1, 2, 3, 4])
idx2 = pd.Index([3, 4, 5, 6])

# 差集
print(idx1.difference(idx2))  # Index([1, 2], dtype='int64')

# 交集
print(idx1.intersection(idx2))  # Index([3, 4], dtype='int64')

# 并集
print(idx1.union(idx2))  # Index([1, 2, 3, 4, 5, 6], dtype='int64')

# 对称差集
print(idx1.symmetric_difference(idx2))  # Index([1, 2, 5, 6], dtype='int64')

索引复制 #

python
# 复制索引
idx_copy = df.index.copy()

# 复制 DataFrame(包含索引)
df_copy = df.copy()

下一步 #

掌握了索引操作后,接下来学习 数据读写,了解如何读取和保存各种格式的数据!

最后更新:2026-04-04