挑出想要的数据
3 道练习题·预计 45 分钟·做对一题解锁下一段
前言
上一章,咱们把记账本这张表看清楚了:一千多行、5 列,每一列是什么类型,心里都有数了。
可是真要回答问题的时候,往往用不着整张表。比如「看病一年花了多少?」,只要医疗那几行就够了;「哪几笔花得最多?」,只要金额大的那几行;「每天的早饭吃了些什么?」,只要名称这一列里的一部分。
所以这一章,就来学怎么从一张大表里,把想要的那部分挑出来。挑法主要有三种:按列挑、按位置挑、按条件挑。为什么要专门花一章来学呢?因为这是 pandas 里用得最多的本事,后面每一章都离不开它。
学这一章之前,需要先学完 数据分析课第 2 章 。
目录
这一章会学到:
- 一、按列挑——一列、几列,以及去掉不要的列
- 二、按位置挑——
iloc和loc - 三、按条件挑——一串
True和False - 四、好几个条件——
&、|、~和isin() - 五、常见坑
- 六、自己查一次文档——用
between()挑出一个范围 - 七、小结与回看
学完这一章,脑子里冒出一个问题,你就能把回答它所需要的那部分数据,从表里干干净净地挑出来。
一、按列挑
先从最简单的按列挑说起。上一章已经见过:方括号里写一个列名,就能取出一列;写一个列名的列表,就能取出好几列。不过这里面有一个容易忽略的区别,先运行下面的代码看看:
import pandas as pd
ledger = pd.read_csv('ledger_2026.csv')
print(type(ledger['item']))
print(type(ledger[['item']]))输出的结果:
<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>同样是 item 这一列,用一层方括号,得到的是 Series;用两层方括号,得到的却是 DataFrame,也就是一张只有一列的表。
为什么要分得这么清楚呢?因为两者能做的事不一样:
- Series 是一串值,可以直接
sum()、unique()。 - DataFrame 是一张表,打印出来带着列名,还能接着挑行、挑列。
所以,只想要一串值,就用一层方括号;想要的还是一张表,就用两层。
好几列一起取的时候,还有一个小细节:列的顺序,是按你写的顺序来的。
import pandas as pd
ledger = pd.read_csv('ledger_2026.csv')
print(ledger[['cost', 'item', 'date']].head(3))输出的结果:
cost item date
0 2500.0 房租 2026-01-01
1 156.0 水电燃气 2026-01-01
2 13.0 早饭 2026-01-01cost 写在最前面,打印出来它就排在了第一列。
那要是想要的列很多,不要的只有一两列呢?一个一个地写想要的列,就太麻烦了。这时候反过来,只写不要的那几列更省事,用 drop(columns=[...]) :
import pandas as pd
ledger = pd.read_csv('ledger_2026.csv')
no_payment = ledger.drop(columns=['payment'])
print(list(no_payment.columns))
print(ledger.shape)输出的结果:
['date', 'item', 'category', 'cost']
(1354, 5)先看第一行:payment 这一列已经去掉了。再留意第二行:ledger 还是 5 列。这是因为 drop() 不会改动原来的表,而是返回一张新表。pandas 里大部分方法都是这样,所以要保留结果,就得用一个变量把它接住,比如这里的 no_payment 。
二、按位置挑
列会挑了,那行该怎么挑呢?
最直接的办法,是按位置挑,也就是说「我要第几行」。这时候用 iloc ,方括号里写位置。和列表的下标一样,位置也是从 0 开始数的:
import pandas as pd
ledger = pd.read_csv('ledger_2026.csv')
print(ledger.iloc[0])输出的结果:
date 2026-01-01
item 房租
category 居住
cost 2500.0
payment 银行卡
Name: 0, dtype: object取出一行,得到的也是一个 Series。只不过这回,是把横着的一行竖过来放:左边是列名,右边是这一行的值。最下面的 Name: 0 告诉你,这是行号为 0 的那一行。
一次只取一行,不够用怎么办?可以用切片,一次取好几行。切片的规则也和列表一样,不包括结尾:
import pandas as pd
ledger = pd.read_csv('ledger_2026.csv')
print(ledger.iloc[9:12])
print(ledger.iloc[-2:])输出的结果:
date item category cost payment
9 2026-01-02 地铁 交通 6.5 微信
10 2026-01-02 零食 餐饮 12.5 支付宝
11 2026-01-03 午饭 餐饮 27.0 支付宝
date item category cost payment
1352 2026-12-31 地铁 交通 4.0 微信
1353 2026-12-31 零食 餐饮 9.5 微信iloc[9:12] 取的是位置 9、10、11 这三行,不包括 12。iloc[-2:] 取的是最后两行,因为负数是从后往前数的,这一点也和列表一样。
除了 iloc ,还有一个 loc 。它和 iloc 有什么不同呢?loc 是按行的标签来挑,也就是最左边那一列行号。而且它还能同时用列名挑列:逗号前面写行,逗号后面写列。
import pandas as pd
ledger = pd.read_csv('ledger_2026.csv')
print(ledger.loc[0, 'item'])
print(ledger.loc[9:11, ['item', 'cost']])输出的结果:
房租
item cost
9 地铁 6.5
10 零食 12.5
11 午饭 27.0来看看这两行各取出了什么:
loc[0, 'item']是行号为 0 的那一行、item那一列,正好就是一个值:房租。loc[9:11, ...]取出了 9、10、11 这三行。注意,它包括结尾的 11,这一点和iloc不一样。
把两者放在一起,比一比:
iloc | loc | |
|---|---|---|
| 按什么挑 | 位置:第几行、第几列 | 标签:行号、列名 |
| 写法 | ledger.iloc[0] 、ledger.iloc[9:12] | ledger.loc[0, 'item'] 、ledger.loc[9:11, ['item', 'cost']] |
| 切片包不包括结尾 | 不包括,和列表一样 | 包括 |
看到这里,有的童鞋可能会觉得:行号和位置不都是 0、1、2 吗,两者好像也差不多?没错,眼下行号和位置是一回事,所以看起来差不多。可是下一节按条件挑完以后,行号就不再是 0、1、2 这样连着的了,到时候区别就出来了。
在那之前,先做一道练习:挑出几行几列,顺便留意一下切片的结尾包不包括。
读进记账本,挑出行号为 100、101、102 的这三行,只要 date 、item 、cost 三列,打印出来。用 loc 或者 iloc 都可以,留意切片的结尾包不包括。
运行后的输出应该是:
date item cost
100 2026-01-26 地铁 5.5
101 2026-01-27 早饭 7.0
102 2026-01-27 午饭 32.5推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai