☰
Pandas中iloc[]和loc[]的实现示例
2026/10/8 10:37:06 网站建设 项目流程

前言


loc和iloc是 pandas 里最核心的两个索引器(indexer), 但它们的区别常常被一句"一个按标签、一个按位置"带过,真用起来还是踩坑。 这篇把两者的行为差异逐条拆开,配可直接推演的示例。


它们的定位很明确:.loc[]是基于标签的索引器,写5会被当作索引里名为 5 的 标签,而不是第 5 个位置;.iloc[]是纯位置索引器,接受 0 到len-1的整数位置。官方文档里对两者都还有补充:它们都能接受布尔数组, 也都能接受一个可调用对象(callable);.loc的切片两端都含,.iloc的切片含头不含尾。这几条正是误用的重灾区。


前提说明:pandas 是第三方库,本机没有 Python 解释器也没有 pandas, 示例无法运行验证,只能逐行人工推演。行为细节以 Pandas 官方文档为准。


一、用同一张表对比


# pandas 1.0+
import pandas as pd

df = pd.DataFrame(
{"name": ["A", "B", "C"], "age": [25, 30, 28]},
index=["r1", "r2", "r3"],
)

现在行索引是字符串r1..r3,列是name/age。下面逐项对比:




操作.loc.iloc



取一行df.loc["r1"]df.iloc[0]

取一列df.loc[:, "name"]df.iloc[:, 0]

取一格df.loc["r1", "age"]df.iloc[0, 1]

切片df.loc["r1":"r2"](含两端)df.iloc[0:2](不含尾)

列表df.loc[["r1", "r3"]]df.iloc[[0, 2]]



看出来了吗?df.loc["r1":"r2"]会取到r1和r2两行, 而df.iloc[0:1]只取到位置 0 的那一行。切片端点是否包含,是二者最反直觉的差别。


另外要留意元组定位:df.loc[行, 列]和df.iloc[行, 列]里的两个分量, 分别对应"行轴"和"列轴",各自遵循自己的标签/位置规则。写df.loc[0, 1]并不会自动把1当成列位置,而是当成"名为 1 的列标签"。


二、为什么loc里的数字不是位置


如果行索引是整数(比如默认的RangeIndex),写法看起来一样,语义却不同:


# pandas 1.0+
df2 = pd.DataFrame({"v": [10, 20, 30, 40]}) # 索引 0,1,2,3
print(df2.loc[2]) # 标签为 2 的那一行 -> 30
print(df2.iloc[2]) # 位置为 2 的那一行 -> 30

这里两者碰巧一样,因为标签恰好等于位置。但只要索引有偏移,差别立刻显现:


# pandas 1.0+
df3 = df2.copy()
df3.index = [10, 20, 30, 40]
print(df3.loc[30]) # 标签 30 -> 值 30
print(df3.iloc[2]) # 位置 2 -> 也是 30(此处巧合)
print(df3.iloc[30]) # 位置 30 越界,抛 IndexError

关键结论:df.loc[30]找的是"索引名为 30"的行,df.iloc[30]找的是"第 31 行"。当索引进过set_index或筛选后不连续时, 两者绝不能互换。


三、布尔数组与可调用对象


两者都支持布尔数组:


# pandas 1.0+
print(df.loc[df["age"] > 26, "name"]) # 布尔 Series 筛行
print(df.iloc[[False, True, True], 0]) # 显式布尔列表

.loc更常和条件表达式搭配,.iloc则偶尔用它做位置掩码。 注意布尔数组长度必须与对应轴一致,否则报错。


两者也都能接一个可调用对象,这一点在"链式调用"里很有用:


# pandas 1.0+
print(df.loc[lambda x: x["age"] > 26])

传进 callable 时,参数是当前被索引的对象本身(Series或DataFrame), 返回的应是可索引的东西(布尔序列、标签列表等)。


四、单值与整行的取舍


# pandas 1.0+
row = df.loc["r1"] # 返回 Series
val = df.loc["r1", "age"] # 返回标量 25
cols = df.loc[:, ["name"]] # 返回 DataFrame

要特别注意"返回的是Series还是标量":多给一个维度就降一级。 如果只想取一个标量且追求更快,可用df.at["r1", "age"]; 位置版对应df.iat[0, 1]。它们的语义就是loc/iloc的单点访问器。


五、切片可以越界吗


官方文档指出:iloc的切片索引器允许越界(符合 Python/NumPy 的切片语义), 但单个整数索引器越界会报错。也就是说:


# pandas 1.0+
print(df.iloc[0:100]) # 允许,最多取到表尾,不报错
print(df.iloc[100]) # 越界,抛 IndexError

而loc的切片是按标签走的,端点标签必须存在,否则会KeyError。 这一点常被写成"iloc更宽容",准确说法是"只有切片的越界被允许"。


六、赋值时为什么要坚持用loc


loc除了取值,更是赋值的正确入口。原因在于 pandas 对"视图还是副本" 的处理:当你先切出一块、再往切出来的东西上写,写动的可能是一份临时副本, 原表没变;在旧版这会触发SettingWithCopyWarning。


# pandas 1.0+
df.loc[df["age"] > 26, "name"] = "X" # 一次定位、一次赋值

从 pandas 3.0 起,写时复制(Copy-on-Write)成为默认行为,SettingWithCopyWarning这个警告本身被移除,语义统一为 "任何切片都是逻辑副本,改切片不影响原对象"。所以正确的姿势是:在原对象上一次说清楚"改哪些行、哪一列",然后赋值,而不是df[...][...] = ...。iloc同样可以赋值,位置和标签的规则与取值时一致。


七、完整示例


# pandas 1.0+
import pandas as pd


def demo() -> None:
df = pd.DataFrame(
{"name": ["A", "B", "C"], "age": [25, 30, 28]},
index=["r1", "r2", "r3"],
)
# 标签定位
print(df.loc["r1", "name"]) # A
print(df.loc["r1":"r2", "age"]) # r1、r2 两行
# 位置定位
print(df.iloc[0, 1]) # 25
print(df.iloc[0:1, 1]) # 只有位置 0 一行
# 布尔与可调用
print(df.loc[df["age"] > 26, "name"])
print(df.iloc[lambda x: [True, False, True]])
# 单点访问器
print(df.at["r3", "age"], df.iat[2, 1])


if __name__ == "__main__":
demo()

常见坑点



  1. 把loc里的数字当成位置


❌ 索引是[10, 20, 30]时写df.loc[2],以为取第 3 行 ✅df.loc[2]找的是"名为 2"的标签;按位置要用df.iloc[2]



  1. loc和iloc的切片端点规则记反


❌ 以为df.loc["a":"c"]不含c✅loc切片两端都含,iloc切片含头不含尾



  1. 单列取出来当成 DataFrame


❌df.loc["r1", "name"]得到标量,却去调.columns✅ 返回Series还是标量取决于给了一个还是两个维度



  1. 用iloc做越界的单点访问


❌df.iloc[100]想"取不到就返回空" ✅ 单个位置越界会IndexError;只有切片允许越界



  1. 布尔数组长度对不上


❌df.loc[[True, False], :]而表有 3 行,报长度不匹配 ✅ 布尔数组长度必须等于被索引轴的长度



  1. loc用不存在的标签做切片


❌df.loc["a":"zzz"]以为会截断到表尾 ✅loc端点标签必须存在,否则KeyError



  1. 链式赋值


❌df.loc[df["age"] > 26]["name"] = "X",旧版报警告、新版可能无效 ✅ 一次定位一次赋值:df.loc[df["age"] > 26, "name"] = "X"



  1. 把两者混在同一行里


❌df.loc[0, 1]以为"第 0 行第 1 列",其实两个参数都按标签解释 ✅ 位置一律iloc,标签一律loc,一行里别混用


总结




维度.loc.iloc



依据标签(label)整数位置(position)

数字当作标签当作位置

切片两端都含含头不含尾

越界切片标签须存在允许越界

布尔/可调用支持支持

单点版.at.iat



判断该用哪个,只需问自己一句:"我手上的是标签还是序号?" 标签用loc,序号用iloc,永不互换。再记住"loc切片两端都含、iloc切片含头不含尾"这一条,绝大多数索引困惑就能当场解开。





需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询