pandas 提供了多套相互独立又互补的索引系统。本节涵盖最基础的索引方式。
1. 方括号 []
Series 的方括号索引
Series 的方括号行为取决于索引类型:
- 整数索引下
s[0]按位置取值 - 标签索引下
s['a']按标签取值 - 混合情况可能产生歧义
import pandas as pd
s_label = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
s_label['a'] # 10(标签取值)
s_label[0] # 10(位置取值)
s_int = pd.Series([10, 20, 30], index=[1, 2, 3])
s_int[1] # 10(索引为 1 的标签值?还是位置 0?)注意事项
当 Series 索引为整型时,
s[1]按标签解释而非位置。建议明确使用.loc/.iloc。
Series 方括号支持:
- 单值:
s['a'] - 标签列表:
s[['a', 'c']] - 位置切片:
s[0:2](不包含端点) - 布尔数组:
s[[True, False, True]]
DataFrame 的方括号索引
DataFrame 的方括号主要用于列选择:
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]})
df['A'] # 选择单列,返回 Series
df[['A', 'C']] # 选择多列,返回 DataFrameDataFrame 方括号也支持行切片(位置语义):
df[0:1] # 选择第一行(位置切片,不含端点)
df[::2] # 隔行选择
df[df['A'] > 1] # 布尔索引行过滤不要使用
df['A', 'B']逗号括号在 DataFrame 中会产生错误,需要传递列表:
df[['A', 'B']]。
2. 属性访问 .
df = pd.DataFrame({'name': ['张三', '李四'], 'age': [25, 30]})
df.name # 等效于 df['name'],返回 Series
df.age # 等效于 df['age']属性访问的限制
- 列名必须以 Python 标识符规范命名(字母/下划线开头,不含空格)
- 列名可能与 DataFrame 方法/属性冲突(如
df.columns、df.index、df.shape)- pandas 2.x 起,若属性与 DataFrame 方法同名,会抛出警告
- 建议仅在交互式探索时使用属性访问,正式代码使用
df['col']
# 列名为非标识符或与内置属性冲突时必须使用方括号
df['first name'] # 必须使用方括号
df['columns'] # 不能使用 df.columns(这是属性)3. 标签索引 .loc 与 .at
.loc 语法
.loc[] 按标签(或标签列表、标签切片、布尔数组)选择数据,切片的结束标签包含在内。
df = pd.DataFrame(
{'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]},
index=['w', 'x', 'y', 'z']
)| 语法 | 结果 |
|---|---|
df.loc['x'] | 选择标签为 'x' 的行(Series) |
df.loc[['x', 'z']] | 按标签列表选行 |
df.loc['x':'y'] | 标签切片(包含 'y') |
df.loc['x', 'B'] | 单个元素(标量) |
df.loc['x':'z', 'A'] | 行切片 + 单列 |
df.loc[:, 'B'] | 所有行 + B 列 |
df.loc[['x', 'z'], ['A', 'B']] | 行列均为标签列表 |
df.loc[df['A'] > 2] | 布尔条件筛选行 |
df.loc[df['A'] > 2, 'B'] | 布尔条件 + 指定列 |
# Series 的 .loc
s = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
s.loc['b'] # 20
s.loc['a':'b'] # a 10
# b 20(含端点)
s.loc[['a', 'c']] # 标签列表无匹配项处理
- 标签不存在:抛出
KeyError- 使用
reindex()可容忍不存在的标签
.at 语法
.at 定位单个标量(按标签),比 .loc 更快:
df.at['x', 'B'] # 6
df.at[df.index[0], 'A'] # 1
# 赋值
df.at['x', 'B'] = 100.at 的限制
- 只能访问单个元素,不能用于切片或列表
- 标签不存在时抛出
KeyError- 在 MultiIndex 上需传入完整元组
4. 位置索引 .iloc 与 .iat
.iloc 语法
.iloc[] 按整数位置选择(从 0 开始),切片不包含结束位置。
df = pd.DataFrame(
{'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]},
index=['w', 'x', 'y', 'z']
)| 语法 | 结果 |
|---|---|
df.iloc[0] | 第一行(Series) |
df.iloc[1:3] | 第 1~2 行(不含 3) |
df.iloc[0, 1] | 第一行第二列(标量) |
df.iloc[:, 0] | 所有行第一列 |
df.iloc[[0, 2], :] | 按位置列表选行 |
df.iloc[-1] | 最后一行(负数从末尾计数) |
df.iloc[::2] | 隔行选择 |
# Series 的 .iloc
s = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
s.iloc[0] # 10
s.iloc[1:3] # b 20
# c 30
s.iloc[[0, 2]] # 位置列表.iat 语法
.iat 通过整数位置快速访问标量:
df.iat[0, 1] # 5
df.iat[2, 0] # 3
# 赋值
df.iat[1, 1] = 50性能对比
- 对于单个标量,
at/iat比loc/iloc更快- 但差距通常很小,优先选择语义清晰的
.loc/.iloc
5. 布尔索引
基本用法
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
mask = df['A'] > 1
df[mask] # 过滤 A > 1 的行
df[df['B'] < 6] # 直接表达式
df.loc[df['A'] > 1] # 推荐写法复合条件
# 使用 &(与)、|(或)、~(非)
df[(df['A'] > 1) & (df['B'] < 6)] # 两个条件都满足
df[(df['A'] > 1) | (df['B'] == 4)] # 任一条件满足
df[~(df['A'] > 1)] # 取反运算符优先级
- 必须使用
&、|、~,而不是 Python 的and、or、not- 每个布尔条件必须用括号包裹:
(df['A'] > 1) & (df['B'] < 6)and/or会抛出ValueError: The truth value of a Series is ambiguous
常用布尔条件构造
| 方法 | 说明 |
|---|---|
df['col'] == value | 等于某个值 |
df['col'] != value | 不等于 |
df['col'].isin(values) | 在指定集合中 |
~df['col'].isin(values) | 不在集合中 |
df['col'].between(a, b) | 在闭区间 [a, b] 内 |
df['col'].isna() | 缺失值 |
df['col'].notna() | 非缺失值 |
df['str'].str.contains(...) | 字符串包含 |
df['str'].str.startswith(...) | 字符串开头 |
mask = (
(df['城市'].isin(['北京', '上海'])) &
(df['年龄'].between(18, 35)) &
(df['姓名'].str.startswith('张'))
)
df.loc[mask]布尔索引与 .loc 的区别
# df[boolean] 与 df.loc[boolean] 在筛选行时基本等效
df[mask] # 行过滤
df.loc[mask] # 行过滤
df.loc[df['A'] > 1, 'B'] # 同时过滤行并选择列
# 不要使用这种写法(错误)
# df[df['A'] > 1, 'B']6. 切片
Series 切片
s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
# 位置切片(不包含结束位置)
s[0:2] # a 10
# b 20
# 标签切片(包含结束位置)
s['a':'c'] # a 10
# b 20
# c 30
# 步长切片
s[::2] # a 10
# c 30DataFrame 切片
df = pd.DataFrame({'A': range(6), 'B': range(100, 106)})
# 位置切片(行)
df[1:4] # 第 1~3 行(不含第 4)
# 步长
df[::2] # 偶数行
# .loc 标签切片(行,含端点)
df.loc[1:4] # 索引 1~4 全部包含
# .iloc 位置切片(不含端点)
df.iloc[1:4] # 第 1~3 行切片关键区别
| 方式 | 端点语义 | 示例 |
|---|---|---|
df[1:4] | 不含端点(位置) | 行 1~3 |
df.loc[1:4] | 包含端点(标签) | 行 1~4 |
df.iloc[1:4] | 不含端点(位置) | 行 1~3 |
s['a':'c'] | 包含端点(标签) | 标签 a~c |
s[0:2] | 不含端点(位置) | 位置 0~1 |
警告
- 当 DataFrame 索引不是顺序整数时,
df[start:stop]使用位置语义,容易混淆。- 如需标签语义切片,始终使用
.loc。
小结
- 方括号
[]:最基础的列选择与位置切片- 属性访问
.:快速上手但不适合正式代码.loc/.at:标签定位,.at为单标量快速访问.iloc/.iat:位置定位,.iat为单标量快速访问- 布尔索引:
&、|、~组合条件,需要括号包裹- 切片:
.loc含端点、.iloc不含端点