本节介绍索引的调整与重构方法,包括索引对齐、重建、过滤与类型选择。


1. reindex() / reindex_like()

reindex()

reindex() 按新索引标签重新排列数据。新索引中不存在的标签以 NaN 填充(或用 fill_value、前向/后向填充)。

s = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
 
# 重新排列索引
s.reindex(['c', 'a', 'b'])
# c    30
# a    10
# b    20
 
# 新增标签出现 NaN
s.reindex(['a', 'b', 'c', 'd'])
# a    10.0
# b    20.0
# c    30.0
# d    NaN
 
# 指定填充值
s.reindex(['a', 'b', 'c', 'd'], fill_value=0)

DataFrame reindex

df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}, index=['x', 'y', 'z'])
 
# 重对齐行索引
df.reindex(['z', 'y', 'x'])
 
# 重对齐列
df.reindex(columns=['B', 'A', 'C'])
 
# 行列同时
df.reindex(index=['z', 'y'], columns=['A', 'C'])
 
# 用 axis 参数
df.reindex(['z', 'x'], axis=0)

reindex() 参数

参数说明
labels新索引标签(数组)
index / columns指定轴的新索引
axis轴(0 / 行,1 / 列)
method填充方法:None、'ffill'、'bfill'、'nearest'
fill_value缺失位置填充值(默认 NaN)
limit填充的最大连续次数
copy是否复制数据
tolerance填充匹配的容忍度(method='nearest' 时)
# 前向填充
s2 = pd.Series([1, 2, 3], index=[0, 1, 2])
s2.reindex([0, 1, 2, 3, 4], method='ffill')
# 0    1.0
# 1    2.0
# 2    3.0
# 3    3.0
# 4    3.0
 
# 时间索引的 reindex(时间序列对齐)
dates = pd.date_range('2024-01-01', periods=3, freq='D')
s3 = pd.Series([1, 2, 3], index=dates)
new_dates = pd.date_range('2024-01-01', periods=5, freq='D')
s3.reindex(new_dates, method='ffill')

reindex_like()

reindex_like() 按另一个对象的索引对齐自身。

df1 = pd.DataFrame({'A': [1, 2]}, index=['a', 'b'])
df2 = pd.DataFrame({'B': [10, 20, 30]}, index=['a', 'b', 'c'])
 
# 使 df1 的行和列与 df2 对齐
df1.reindex_like(df2)
#      A    B
# a  1.0  NaN
# b  2.0  NaN
# c  NaN  NaN
 
# 只对齐列
df1.reindex_like(df2[['B']])

2. set_index() / reset_index()

set_index()

set_index() 将一列或多列设为索引。

df = pd.DataFrame({
    'ID': [101, 102, 103],
    '姓名': ['张三', '李四', '王五'],
    '城市': ['北京', '上海', '北京']
})
 
# 单列设索引
df.set_index('ID')
 
# 多列设为 MultiIndex
df.set_index(['城市', 'ID'])
#             姓名
# 城市   ID
# 北京   101  张三
# 上海   102  李四
# 北京   103  王五
 
# 保留原列(drop=False)
df.set_index('ID', drop=False)
 
# 追加为第二层级(append=True)
df.set_index('城市', append=True)

set_index() 参数

参数说明
keys列名或列名列表(也可为数组、Index 对象)
drop是否删除设为索引的原列(默认 True)
append是否附加到现有索引(创建 MultiIndex)
inplace是否原地修改
verify_integrity检查新索引是否唯一
# 使用 Series 或数组设置索引
df.set_index(pd.Index(['a', 'b', 'c']))
df.set_index(pd.Series([1, 2, 3], name='编号'))

reset_index()

reset_index() 将索引(一层或多层)转换为列,或完全重置为默认整数索引。

# 默认重置为 RangeIndex,原索引变为普通列
df.index.name = '旧索引'
df.reset_index()
#    旧索引  A  B
# 0    a    1  4
# 1    b    2  5
 
# 删除原索引(不保留列)
df.reset_index(drop=True)
 
# 只重置 MultiIndex 的指定层级
mi_df = df.set_index(['城市', 'ID'])
mi_df.reset_index(level='城市')
mi_df.reset_index(level=1)      # 按层级整数

reset_index() 参数

参数说明
level要重置的层级(None 表示全部,可指定名称或编号)
drop是否丢弃原索引(默认 False,转为列)
inplace是否原地修改
col_level在 MultiIndex 列中写入索引层级的位置
col_fill索引转为列时,列是 MultiIndex 时的填充名称
# 分组聚合后的常用操作
result = df.groupby('城市')['销售额'].sum()
result.reset_index()   # 将分组键转回列

3. align()

align() 将两个对象按索引对齐,返回对齐后的两个对象(支持多种连接方式)。

df1 = pd.DataFrame({'A': [1, 2]}, index=['a', 'b'])
df2 = pd.DataFrame({'B': [10, 20, 30]}, index=['a', 'b', 'c'])
 
# 外连接(默认):并集,缺失填充 NaN
left, right = df1.align(df2)
# left:
#      A    B
# a  1.0  NaN
# b  2.0  NaN
# c  NaN  NaN
 
# 内连接:交集
left_inner, right_inner = df1.align(df2, join='inner')
 
# 左连接:以左对象索引为准
left, right = df1.align(df2, join='left')
 
# 右连接:以右对象索引为准
left, right = df1.align(df2, join='right')
 
# 填充值
left, right = df1.align(df2, fill_value=0)
 
# 沿列对齐
left, right = df1.align(df2, axis=1)

align() 参数

参数说明
other要对齐的另一个对象
join'outer'(默认)、'inner'、'left'、'right'
axis对齐轴(None 表示所有轴)
levelMultiIndex 对齐层级
copy是否复制数据
fill_value对齐后缺失值填充

align 与 reindex 的区别

  • reindex:显式指定新索引
  • align:基于两个对象的索引自动对齐(返回两个对象)

4. get()

get() 是安全的标签取值方法,标签不存在时返回默认值而非抛出异常。

df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
 
df.get('A')         # 返回 A 列(Series)
df.get('X')         # None(不存在)
df.get('X', default=0)   # 0
 
# Series
s = pd.Series([10, 20], index=['a', 'b'])
s.get('a')          # 10
s.get('z')          # None
s.get('z', -1)      # -1
方法不存在时行为
df['col']抛出 KeyError
df.get('col')返回 None 或指定 default
df.loc['row']抛出 KeyError
df.reindex(...)填充 NaN

5. filter()

filter() 按索引标签进行过滤(默认对列),适合按名称模式选择列/行。

参数

参数说明
items精确标签列表:df.filter(items=['A', 'C'])
like模糊匹配:df.filter(like='sale')
regex正则匹配:df.filter(regex='^a')
axis轴:0 = 行,1 = 列(默认)
df = pd.DataFrame({
    'sales_2023': [100, 200],
    'sales_2024': [150, 250],
    'profit_2024': [30, 50]
})
 
# 精确选择
df.filter(items=['sales_2023'])
 
# 模糊匹配(包含字符串)
df.filter(like='sales')
 
# 正则匹配
df.filter(regex='^sales')
df.filter(regex='2024$')
 
# 按行过滤
df.filter(like='0', axis=0)

注意

items、like、regex 可同时指定,pandas 会合并匹配结果(取交集)。但语义容易混淆,建议一次只使用一种。

与布尔索引对比

df[df.columns[df.columns.str.contains('sale')]] 等价于 df.filter(like='sale')。filter 更简洁。


6. select_dtypes()

select_dtypes() 按数据类型选择列,常用于数据清洗阶段。

df = pd.DataFrame({
    'int_col': [1, 2, 3],
    'float_col': [1.1, 2.2, 3.3],
    'str_col': ['a', 'b', 'c'],
    'bool_col': [True, False, True],
    'date_col': pd.date_range('2024-01-01', periods=3)
})
 
# 选择数值列
df.select_dtypes(include='number')
#    int_col  float_col
 
# 选择整数列
df.select_dtypes(include='int')
 
# 排除字符串列
df.select_dtypes(exclude='object')
 
# 选择多种类型
df.select_dtypes(include=['int', 'float'])
 
# 包含时间类型
df.select_dtypes(include='datetime64')
 
# 排除数值列(保留其他)
df.select_dtypes(exclude='number')
 
# 指定 pandas 扩展类型
df2 = df.astype({'int_col': 'Int64', 'str_col': 'string'})
df2.select_dtypes(include='Int64')
df2.select_dtypes(include='string')

include / exclude 常用值

类型说明
'number'所有数值类型(int、float、complex)
'int'整数类型
'float'浮点类型
'bool'布尔类型
'object'object 类型
'datetime64'日期时间类型
'timedelta64'时间差
'category'分类类型
'string'pandas StringDtype
'Int64'可空整数扩展类型
'boolean'可空布尔扩展类型

典型用途

  • 对数值列统一做 describe() / 标准化
  • 批量将字符串列转为 category
  • 排除非数值列后计算相关性