loc 和 iloc 是 Pandas 中两个最常用的索引器,它们的主要区别在于索引方式不同:
核心区别
| 特性 |
loc |
iloc |
|---|
| 索引方式 |
标签索引 |
位置索引 |
| 语法 |
[行标签, 列标签] |
[行位置, 列位置] |
| 包含范围 |
包含结束位置 |
不包含结束位置 |
| 切片 |
'A':'C'(包含C) |
0:3(包含0,1,2,不包含3) |
| 索引类型 |
索引名、布尔数组 |
整数位置、布尔数组 |
代码示例
1. 基本使用
import pandas as pd
import numpy as np
# 创建示例数据
df = pd.DataFrame({
'A': [1, 2, 3, 4, 5],
'B': [10, 20, 30, 40, 50],
'C': [100, 200, 300, 400, 500]
}, index=['a', 'b', 'c', 'd', 'e'])
print("原始数据:")
print(df)
2. 单行/单列选择
# loc - 使用标签
print("\n=== loc 示例 ===")
print("df.loc['c']:") # 选择行'c'
print(df.loc['c'])
print("\ndf.loc[:, 'B']:") # 选择列'B'
print(df.loc[:, 'B'])
# iloc - 使用位置
print("\n=== iloc 示例 ===")
print("df.iloc[2]:") # 选择第2行(0-based)
print(df.iloc[2])
print("\ndf.iloc[:, 1]:") # 选择第1列
print(df.iloc[:, 1])
3. 切片操作
print("\n=== 切片比较 ===")
# loc 切片(包含结束位置)
print("df.loc['b':'d']:") # 包含'd'
print(df.loc['b':'d'])
# iloc 切片(不包含结束位置)
print("\ndf.iloc[1:4]:") # 位置1,2,3(不包含4)
print(df.iloc[1:4])
# 行列组合切片
print("\ndf.loc['b':'d', 'A':'B']:")
print(df.loc['b':'d', 'A':'B'])
print("\ndf.iloc[1:4, 0:2]:")
print(df.iloc[1:4, 0:2])
4. 布尔索引
print("\n=== 布尔索引 ===")
# 两者都支持布尔数组
mask = df['A'] > 2
print("df.loc[mask]:")
print(df.loc[mask])
print("\ndf.iloc[mask.values]:")
print(df.iloc[mask.values])
5. 混合选择
print("\n=== 混合选择 ===")
# 选择特定行和列
print("df.loc[['a', 'c', 'e'], ['A', 'C']]:")
print(df.loc[['a', 'c', 'e'], ['A', 'C']])
print("\ndf.iloc[[0, 2, 4], [0, 2]]:")
print(df.iloc[[0, 2, 4], [0, 2]])
6. 赋值操作
print("\n=== 赋值操作 ===")
# 复制一份数据用于修改
df_copy = df.copy()
# 使用 loc 赋值
df_copy.loc['b':'d', 'A'] = [99, 99, 99]
print("使用 loc 赋值后:")
print(df_copy)
# 使用 iloc 赋值
df_copy.iloc[1:4, 0] = [88, 88, 88]
print("\n使用 iloc 赋值后:")
print(df_copy)
7. 实际应用场景
print("\n=== 实际应用场景 ===")
# 场景1:处理时间序列数据(适合用 loc)
dates = pd.date_range('2023-01-01', periods=5, freq='D')
df_time = pd.DataFrame({
'price': [100, 102, 101, 105, 103],
'volume': [1000, 1200, 900, 1500, 1100]
}, index=dates)
print("时间序列数据:")
print(df_time)
print("\n选择特定日期范围:")
print(df_time.loc['2023-01-02':'2023-01-04'])
# 场景2:处理有序整数索引(适合用 iloc)
print("\n=== 有序数据 ===")
print("获取前3行:")
print(df.iloc[:3])
print("\n获取最后2行:")
print(df.iloc[-2:])
8. 常见错误
print("\n=== 常见错误 ===")
# 错误1:使用整数标签时混淆
df_int_index = pd.DataFrame({'A': [1, 2, 3]}, index=[10, 20, 30])
try:
# 这可能会引起混淆
print(df_int_index.loc[1]) # 错误!会尝试找标签1,而不是位置1
except KeyError as e:
print(f"错误: {e}")
# 正确做法
print("\n正确做法:")
print("df_int_index.iloc[1]:") # 使用位置索引
print(df_int_index.iloc[1])
print("\ndf_int_index.loc[20]:") # 使用标签索引
print(df_int_index.loc[20])
# 错误2:切片范围理解错误
print("\n=== 切片范围理解 ===")
print("loc['a':'c'] 包含 'a', 'b', 'c'")
print("iloc[0:3] 包含 0, 1, 2(不包含3)")
最佳实践建议
选择依据:
- 当索引有明确的业务含义(如日期、名称)时,使用
loc
- 当只需要按位置选择时,使用
iloc
性能考虑:
- 对于大数据集,
iloc 通常比 loc 稍快
- 但可读性和意图明确更重要
代码清晰:
# 清晰明确的代码
df.loc[df['score'] > 90, ['name', 'grade']]
# 使用 iloc 实现相同的选择(但不推荐,可读性差)
mask = df['score'] > 90
col_indices = [df.columns.get_loc('name'), df.columns.get_loc('grade')]
df.iloc[mask.values, col_indices]
避免混用:
# 不推荐:混合使用可能造成混淆
# df.loc[0:5] # 如果索引是整数,这可能会按标签选择,而不是位置
# 明确区分
df.iloc[0:5] # 按位置选择
df.loc['2023-01-01':'2023-01-05'] # 按标签选择
总结表格
| 场景 |
推荐使用 |
原因 |
|---|
| 按行/列名选择 |
loc |
语义明确,可读性好 |
| 按位置选择 |
iloc |
简单直接 |
| 布尔索引 |
两者均可 |
根据具体情况选择 |
| 时间序列数据 |
loc |
方便按日期范围选择 |
| 连续范围选择 |
根据索引类型选择 |
整数索引时注意区分 |
记住:loc 是基于标签的,iloc 是基于位置的。选择哪个取决于你是想通过"名字"还是"位置"来访问数据。