head 和 tail 看头尾,是最常用的两个动作,读完数据第一件事就干这个。 iloc 按位置数,loc 按标签找。两个都好用,混用就是取错行。 切片含不含尾这件事两边不一样:iloc 不含尾,loc 含尾。
前两篇解决「怎么读进来」,从这篇开始解决「怎么挑出来」。 挑行有三种手法:掐头去尾、按位置、按标签。这一篇讲完这三种。
一、看头看尾:head 和 tail
head(3) 给前 3 行,tail(2) 给后 2 行,括号里不写数字默认 5。
| 姓名 | 班级 | 语文 |
|---|---|---|
| 张伟 | 一班 | 88 |
| 王芳 | 一班 | 92 |
| 李娜 | 一班 | 75 |
tail(2) 给的是最后两行:周涛 83、吴霞 79。
读任何一份数据,第一件事都是 head 加 tail。头尾都对,中间大多也对。
只 head 不 tail 会漏掉一类问题:文件末尾常有合计行、空行、备注行。
二、按位置抽:iloc
iloc 的 i 就是 integer,全部按「第几行第几列」数,从 0 起。
d.iloc[0] 取第一行,返回的是 Series,标签是列名。
打成一行看:姓名=张伟,语文=88,数学=92。
d.iloc[2:5] 取第 3 到第 5 行,一共 3 行——第 5 行不含。
| 姓名 | 语文 |
|---|---|
| 李娜 | 75 |
| 刘洋 | 85 |
| 陈静 | 90 |
要行列一起给,中间逗号:d.iloc[0, 1] 是第 1 行第 2 列。只给一个数就是行。
三、按标签抽:loc
先 set_index('姓名') 把行标签换成姓名,loc 就能按名字取。
| 姓名 | 语文 | 数学 |
|---|---|---|
| 张伟 | 88 | 92 |
| 李娜 | 75 | 68 |
| 赵敏 | 95 | 91 |
一次取多行要给列表:d.loc[ ['张伟', '李娜', '赵敏']]。
切片也认:d.loc['张伟':'李娜'] 取张伟、王芳、李娜三行,两头都含。
这一条和 iloc 正好相反,写在下面单独一段。
四、含不含尾:一条必须背下来的差别
| 写法 | 取到几行 | 末端 |
|---|---|---|
| d.iloc[0:3] | 3 行(0、1、2) | 不含 3 |
| d.loc['张伟':'李娜'] | 3 行(含李娜) | 含李娜 |
原因不神秘:iloc 照 Python 切片的老规矩(含头不含尾),loc 是「按标签圈范围」。 筛选数据时用 loc 更符合直觉——说「张伟到李娜」就是把这两个人圈进来。 而按位置数的时候用 iloc,含头不含尾能少算一次加减,也是老规矩。
五、两个最容易踩的坑
第一个坑:行标签被改成姓名之后,d.loc[0] 直接报 KeyError,不是返回第一行。
因为标签里没有 0 这个值了。想要第一行只能用 d.iloc[0]。
第二个坑:d[0] 在 pandas 3 里也是按标签找,不再按位置。
报 KeyError 就是标签没对上,换 iloc;报 IndexError 就是位置超了,先看 shape。
六、动手 Demo:抽取行:head、tail、loc、iloc
造一张 10 行的成绩表,先把姓名设成行标签,再看四种取法各自返回什么。 重点看 iloc 切片和 loc 切片差的那一行。
import pandas as pd
DF = pd.DataFrame({
"姓名": ["张伟", "王芳", "李娜", "刘洋", "陈静"],
"语文": [88, 92, 75, 85, 90],
"数学": [92, 95, 68, 88, 91],
})
print(DF.head(2).to_string(index=False))
print("iloc[2:4] 行数 %d" % len(DF.iloc[2:4]))
D = DF.set_index("姓名")
print("loc 切片 %s" % list(D.loc["张伟":"李娜"].index))
print("iloc 切片 %s" % list(D.iloc[0:3].index))
try:
D.loc[0]
except KeyError:
print("loc[0] 报 KeyError")
实跑输出:
--------------------------------------------------------------------
抽取行:head、tail、loc、iloc
--------------------------------------------------------------------
① 看头看尾
--------------------------------------------------------------------
| 行 | 姓名 | 班级 | 语文 |
|---|---:|---:|---:|
| 0 | 张伟 | 一班 | 88 |
| 1 | 王芳 | 一班 | 92 |
| 2 | 李娜 | 一班 | 75 |
head(3) 给前 3 行,tail(2) 给后 2 行。括号里不写数字,默认 5。
| 行 | 姓名 | 语文 |
|---|---:|---:|
| 8 | 周涛 | 83 |
| 9 | 吴霞 | 79 |
! 读任何一份数据,第一件事都是 head 加 tail:头尾都对,中间大多也对。
② 按行号抽:iloc
--------------------------------------------------------------------
iloc[0] 取第一行,返回的是一个 Series,标签是列名。
姓名=张伟,语文=88,数学=92。
iloc[2:5] 取第 3 到第 5 行(含头不含尾),一共 3 行。
| 行 | 姓名 | 语文 |
|---|---:|---:|
| 2 | 李娜 | 75 |
| 3 | 刘洋 | 85 |
| 4 | 陈静 | 90 |
! iloc 用方括号,两个参数写法是 iloc[行, 列]。只给一个就是行。
③ 按标签抽:loc
--------------------------------------------------------------------
| 姓名 | 语文 | 数学 |
|---|---:|---:|
| 张伟 | 88 | 92 |
| 李娜 | 75 | 68 |
| 赵敏 | 95 | 91 |
行标签换成姓名之后,loc 就能按名字取。一次取多行要给一个列表。
切片也行:d.loc['张伟':'李娜'] 取张伟、王芳、李娜三行,两头都含。
! loc 的切片含尾,iloc 的切片不含尾。这一条要背下来。
④ 两种写法怎么区分
--------------------------------------------------------------------
| 想干什么 | 写法 | 注意 |
|---|---|---|
| 前 5 行 | df.head() | 最省事 |
| 第 3 到 5 行 | df.iloc[2:5] | 不含第 5 行 |
| 姓名是张伟那行 | df.loc['张伟'] | 要先 set_index |
| 第 1 行第 2 列 | df.iloc[0, 1] | 逗号分开行列 |
混用的后果是取错行:标签被改成姓名之后,df.loc[0] 会报 KeyError,而不是返回第一行。
! 排错口诀:报 KeyError 说明用 loc 找了一个不存在的标签,改成 iloc 就好。
loc 切片两头都含,所以 loc['张伟':'李娜'] 是 3 行;iloc 切 0:3 也是 3 行,但含义完全不同。
同一个结果、两种写法,靠的是标签和位置各算各的账。换成别的数据,两个数就不等了。
30 秒实验
- 把 iloc[2:4] 改成 loc 写法,取同样三行,看要多写什么。
- 给表加一行「合计」,再用 tail(1) 看它长什么样。
- 想一想:行标签是姓名,那
d.loc['张伟':'李娜']是按拼音顺序圈还是按行顺序圈?
常见误区
- 行标签变了还用 loc[0]:报 KeyError,以为数据坏了。
- 以为 loc 切片也不含尾:多取一行,算平均时多带了一个人。
- 只 head 不 tail:漏掉文件末尾的合计行和空行。
- 把 iloc 的两个参数顺序记反:iloc[列, 行] 是错的,永远先写行。
自测三问(点开对答案)
1. loc 和 iloc 最本质的区别是什么? —— loc 认标签,iloc 认位置。行标签被换过之后,两者结果就不一样了。 2. 为什么 loc['张伟':'李娜'] 是 3 行,iloc[0:3] 也是 3 行,但不是巧合? —— loc 的切片两头都含,iloc 的不含尾。在这次的数据里,两者刚好都覆盖 3 行,换套数据就未必。 3. 报 KeyError 一般是什么原因? —— 用 loc 找了一个不存在的标签,比如行标签已换成姓名却写 loc[0]。行会抽了,接下来抽列,还有更常用的条件筛选——「数学高于 88 的有谁」。
- ☐ (本篇完,下一篇 3.9 抽取列与按条件筛选)