首页 / Pandas 入门教程 / loc 与 iloc:按标签和位置选择

Pandas 入门教程

loc 与 iloc:按标签和位置选择

本教程共 54 篇 · 第 19 篇 · 更新于 2026-08-11 · 约 8 分钟阅读

PandasPandas 入门教程lociloc切片索引

本节目标:分清 loc 和 iloc 的规则,能用它们灵活地按标签或位置选取任意行列组合。

两种索引:标签和位置

pandas 里取数据有两条路:

  • loc:按标签(label)取,也就是索引的名字
  • iloc:按位置(position)取,也就是第几行第几列,从 0 开始

先造一个索引不连续的 DataFrame,更容易看出区别:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "姓名": ["张三", "李四", "王五", "赵六"],
    "年龄": [25, 30, 28, 35],
    "城市": ["北京", "上海", "广州", "深圳"],
}, index=[1, 3, 5, 7])

print(df)

行标签是 1、3、5、7,但位置永远是 0、1、2、3。标签和位置是两套独立的坐标系统,loc 和 iloc 就是分别访问这两套系统的入口。

loc:按标签选

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "姓名": ["张三", "李四", "王五", "赵六"],
    "年龄": [25, 30, 28, 35],
    "城市": ["北京", "上海", "广州", "深圳"],
}, index=[1, 3, 5, 7])

print(df.loc[3])        # 标签为 3 的那一行(李四)
print(df.loc[[1, 5]])   # 标签 1 和 5 两行
print(df.loc[1:5])      # 标签从 1 到 5,两头都包含!

loc 的切片规则和 Python 不一样:结束标签也包含在内df.loc[1:5] 取到标签 1、3、5 三行。

标签不存在会直接抛 KeyError,这是 loc 的严格性,能帮你早发现写错的标签。

iloc:按位置选

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "姓名": ["张三", "李四", "王五", "赵六"],
    "年龄": [25, 30, 28, 35],
    "城市": ["北京", "上海", "广州", "深圳"],
})

print(df.iloc[0])        # 第 0 行
print(df.iloc[[0, 2]])   # 第 0、2 行
print(df.iloc[0:2])      # 第 0、1 行,结束位置不包含!
print(df.iloc[-1])       # 最后一行
print(df.iloc[-3:])      # 最后三行

iloc 的切片和 Python 列表一致:左闭右开,结束位置不包含。负数从末尾数,-1 是最后一行。

Warning

loc 和 iloc 的切片规则正好相反:loc 包含结束标签,iloc 不包含结束位置。这是新手最容易翻车的地方,写之前先想清楚自己在按什么取。

行列组合:两个维度一起选

loc 和 iloc 都支持 [行, 列] 的写法,逗号左边选行,右边选列:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "姓名": ["张三", "李四", "王五", "赵六"],
    "年龄": [25, 30, 28, 35],
    "城市": ["北京", "上海", "广州", "深圳"],
}, index=["a", "b", "c", "d"])

print(df.loc["b", "姓名"])                # 一个值:李四
print(df.loc["a":"c", ["姓名", "城市"]])  # 行切片 + 列列表
print(df.iloc[0:3, 0:2])                  # 位置切片
print(df.iloc[:, 0])                      # 所有行第 0 列

不写列部分等价于选所有列,df.loc["a"]df.loc["a", :] 一样。行列两边都支持切片、列表、单个标签三种写法,自由组合:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "姓名": ["张三", "李四", "王五", "赵六"],
    "年龄": [25, 30, 28, 35],
    "城市": ["北京", "上海", "广州", "深圳"],
}, index=["a", "b", "c", "d"])

print(df.loc["b":"d", "姓名":"城市"])   # 行列都是标签切片
print(df.iloc[1:4, 0:2])                # 行列都是位置切片

Series 也一样适用

Series 只有一条轴,用法更简单:

import pandas as pd
import numpy as np

s = pd.Series([10, 20, 30], index=["a", "b", "c"])

print(s.loc["a":"b"])   # 标签切片,包含 b
print(s.iloc[0:2])      # 位置切片,不含 2
print(s.iloc[-1])       # 最后一个

选列还是选行:别混

  • df["姓名"]:按列名取一列,最常用
  • df.loc[:, "姓名"]:显式”所有行 + 这一列”,更啰嗦但更明确
  • df.loc["a"]:按行标签取一行,返回 Series

列名和行标签有时长得一样(比如都是数字),用 [] 和用 loc 的结果完全不同。需要选行时一律用 loc/iloc,别用 [] 猜。

Note

老教程里常见一个 df.ix 索引器,能同时按标签和位置取。它早在 0.20 版就被移除了,现在的写法是:按标签用 loc,按位置用 iloc,不要混用。

切片规则速查

写法规则例子结果
df.loc[1:5]标签,包含两端标签 1、3、5
df.iloc[0:2]位置,不包含右端第 0、1 行
df.loc[[1, 5]]标签列表标签 1、5 两行
df.iloc[[0, 2]]位置列表第 0、2 行
df.iloc[-1]负位置最后一行

什么时候用哪个

  • 索引有业务含义(日期、订单号、人名)时,用 loc,代码一看就懂
  • 索引只是默认的 0、1、2 时,两者差不多,用哪个都行
  • 要按顺序取前 N 行、循环遍历、或者对接按位置传参的库时,用 iloc
  • 索引可能变化(比如筛选后)时,用位置比用标签更稳

一个综合示例

把本节的工具串起来用:取前几行、挑列、再排序:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "姓名": ["张三", "李四", "王五", "赵六", "钱七"],
    "年龄": [25, 30, 28, 35, 22],
    "城市": ["北京", "上海", "广州", "北京", "深圳"],
    "薪资": [12000, 15000, 11000, 18000, 9000],
})

sub = df.loc[:2, ["姓名", "薪资"]]   # 前 3 行(标签 0 到 2)的两列
print(sub.sort_values("薪资", ascending=False))   # 按薪资降序

报错行为:提前知道不慌

  • loc 找不到标签:抛 KeyError
  • iloc 位置越界:抛 IndexError
  • 但切片越界不报错:df.iloc[5:100] 会静默返回空结果,跟 Python 切片行为一致

注意返回类型

取单行返回 Series,取多行返回 DataFrame,两种结果的后续操作不一样:

import pandas as pd
import numpy as np

df = pd.DataFrame({"姓名": ["张三", "李四"], "年龄": [25, 30]})

row = df.loc[0]        # 单行,Series
sub = df.loc[[0, 1]]   # 多行,DataFrame
print(type(row))       # <class 'pandas.core.series.Series'>
print(type(sub))       # <class 'pandas.core.frame.DataFrame'>

拿不准返回类型时,print(type(...)) 确认一下,比猜靠谱。

布尔数组也能用

loc 和 iloc 都接受布尔数组作为”行”的选择条件,这正好是下一节布尔索引的入口:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "姓名": ["张三", "李四", "王五", "赵六"],
    "年龄": [25, 30, 28, 35],
}, index=[1, 3, 5, 7])

print(df.loc[df["年龄"] > 28])    # 标签 + 条件
print(df.iloc[[0, 2]])            # 位置列表

布尔数组的长度必须和轴长度一致,否则会报错,这是 pandas 的自我保护。

赋值也一样

loc/iloc 不光能读,还能写:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "姓名": ["张三", "李四", "王五", "赵六"],
    "年龄": [25, 30, 28, 35],
    "城市": ["北京", "上海", "广州", "深圳"],
}, index=[1, 3, 5, 7])

df.loc[3, "年龄"] = 31        # 改一个值
df.loc[1:3, "城市"] = "杭州"   # 改一片
df.loc[:, "备注"] = "新成员"   # 新增一列,所有行同一个值
print(df)

pandas 3.0 默认开启写时复制(如 §09 所述),这种”先定位再赋值”的写法是最安全的,放心用。

顺带一提:loc 的行位置还支持 callable(可调用对象),比如 df.loc[lambda x: x["年龄"] > 28],效果和布尔数组一样。用得不多,知道有这么个能力就行。

本节的要点

loc 和 iloc 是 pandas 最基础也最重要的两个索引器,后面的布尔筛选、赋值、分组都建立在它们之上。记住三句话:标签用 loc,位置用 iloc;loc 切片含两端,iloc 不含;选行列写 [行, 列]。

选数据有个三层视角,方便记忆:

  • df["列名"]df.loc[:, "列名"]
  • df.loc["标签"]df.iloc[位置]
  • 单个值df.loc["标签", "列名"],下一节还有更快的 at/iat

切片操作在 pandas 3.0 的写时复制机制下更省心,返回的是新对象,不会悄悄改动原数据(如 §09 所述)。

Tip

df.loc[行, 列] 的”行”位置还能放布尔条件,比如 df.loc[df["年龄"] > 28, "城市"],条件筛选和列选择一步完成,下一节会用到。记住一个原则:能写进 loc 的,都能用来筛选。