八百行的表里找”华东区、销售额过万、三月份”的订单,Excel要三轮筛选加一次排序、点十几下鼠标。
pandas一行条件、一行排序,两行代码拿下——而且换个问题只要换个条件,鼠标点过的活儿再也回不来了
一、老板的”第二轮追问”
上一篇结尾留了个话头:老板问完”总销售额、销售冠军、平均单值”,果然杀了个回马枪。这次的问题是:“华东区销售额过万的订单有哪些?按销售额从高到低排出来。”
打开Excel你是这么干的:点”部门”列的筛选箭头→勾”华东”→点”销售额”列筛选→数字筛选→大于→10000→点”销售额”列头排序→降序。十几下鼠标,两分钟。这时候老板又补了一句:”那三月份的呢?””那华南区的呢?”——每换一个条件,前面的鼠标全重点一遍。
上一篇我们把数据读进了程序(忘了的话回看第31篇:df = pd.read_excel("销售明细.xlsx"),df是一张住在程序里的超级表格)。数据在程序里,”筛选”和”排序”就变成了写条件,而不是点鼠标:
华东过万 = df[(df["部门"] == "华东") & (df["销售额"] > 10000)]
结果 = 华东过万.sort_values("销售额", ascending=False)
print(结果)
两行,完事。==、>、&是什么?sort_values那个长参数是什么?别急,今天就讲透这两下。今天的唯一一个新概念是:布尔筛选——用”条件”当筛子,让表自己把不合格的行筛掉。排序只是它的”售后服务”,看一遍就会。
二、新概念:布尔筛选——给表一把”筛子”
一个条件,先看它吐出什么
先不筛任何东西,就看条件本身长什么样:
print(df["部门"] == "华东")
0 True
1 False
2 True
3 False
4 True
Name: 部门, dtype: bool
df["部门"] == "华东"逐行问了一个问题:”这一行的部门是华东吗?”答案是一列True/False——True是”是”,False是”不是”。这种只有两种值的类型叫布尔值(bool,第5篇条件判断里if吃的正是它)。这一列True/False,就是一把筛子:True的行留下,False的行滤掉。
把筛子按到表上
怎么”按”?把这一列True/False再塞回df的方括号里:
华东们 = df[df["部门"] == "华东"]
print(华东们)
姓名 部门 销售额 日期
0 小王 华东 12000 2026-01-05
2 小张 华东 15300 2026-01-07
4 小王 华东 11000 2026-01-09
对照原始表看:1号小李(华南)和3号小赵(华北)消失了,剩下的行号0、2、4还保留着原样——筛选不打乱原表,只是”摘”出符合条件的行。读法记好:df[ 条件 ] = “表里满足条件的那些行”。
这就是今天的主菜。写法上跟第31篇的df["销售额"]长得像,但含义完全不同,别混:
df["销售额"] # 方括号里是列名字符串 → 取一列(Series)
df[df["部门"] == "华东"] # 方括号里是True/False列 → 取符合条件的行(DataFrame)
一张图记住:方括号里放”名字”取列,放”条件”取行。
两个条件:且(&)、或(|)
老板要的是”华东且销售额过万”。两个条件同时满足,用&(且)连起来:
华东过万 = df[(df["部门"] == "华东") & (df["销售额"] > 10000)]
print(华东过万)
姓名 部门 销售额 日期
2 小张 华东 15300 2026-01-07
注意三个写法细节,全是血泪坑(后面坑点区还会敲黑板):
- 每个条件都要用小括号包起来——
(df["部门"] == "华东") & (df["销售额"] > 10000)。不包的话运算顺序会乱,直接报错或者算出鬼结果 - “且”用
&,”或”用|(键盘上回车键上方那个竖线)。不是英语单词and/or!pandas认符号不认单词 - 比较符号跟第5篇
if里一模一样:==等于、!=不等于、>大于、<小于、>=大于等于、<=小于等于
“或”的用法举个例子,”华东区或者华北区的订单”:
华东华北 = df[(df["部门"] == "华东") | (df["部门"] == "华北")]
条件再多也一样叠:三月份且(华东或华北)且销售额过万,就是三个括号用&、|拼起来。条件组合的本质就是第5篇if里的多条件判断,只是这次if变成了”整列的筛子”。
按区间、按名单筛
两个高频花样顺手拿下:
# 区间:销售额在5000到10000之间(含5000不含10000的写法看清楚)
中间层 = df[(df["销售额"] >= 5000) & (df["销售额"] < 10000)]
# 名单:部门是华东或华南或华北,用 isin("是否在其中")
三大区 = df[df["部门"].isin(["华东", "华南", "华北"])]
isin(列表)就是”这一行的值,在我给的名单里吗”——一个isin顶三个|,名单多长都行。
三、排序:sort_values,”服务业”登场
筛出来的华东过万还得按销售额从高到低排。排序函数是sort_values():
结果 = 华东过万.sort_values("销售额", ascending=False)
print(结果)
拆开念人话:sort_values("销售额") = “按’销售额’这一列排”,ascending=False = “降序”(ascending是”上升”的意思,False就是不往上走,那就是往下走=从大到小)。不写这个参数默认升序(从小到大)。
两个顺手的花样:
# 先按部门排、部门相同的再按销售额排(多级排序,跟Excel"主要关键字/次要关键字"一个意思)
df.sort_values(["部门", "销售额"], ascending=[True, False])
# 反转列顺序什么的都是浮云,倒着排原始表看看前3行经常有用
df.sort_values("日期").head(3) # 最早的3条订单
多级排序里,ascending传一个列表,跟排序列一一对应:[True, False] = 部门升序、销售额降序。
四、实战:老板的追问,两行一个
完整代码收拢一下,以后这类问题就是”换个条件”的事:
import pandas as pd
df = pd.read_excel("销售明细.xlsx")
# 老板问:华东区销售额过万的订单,按销售额从高到低
华东过万 = df[(df["部门"] == "华东") & (df["销售额"] > 10000)]
结果 = 华东过万.sort_values("销售额", ascending=False)
print(f"华东区过万订单共{len(结果)}条:")
print(结果)
# 追问1:三月份的呢?(假设"日期"列已读成日期格式,见坑点4)
三月 = df[df["日期"].dt.month == 3]
print(三月)
# 追问2:华南区的呢?——改个字符串而已
华南 = df[df["部门"] == "华南"]
print(华南)
# 追问3:不筛了,全表按日期排个倒序看看最近的单子
print(df.sort_values("日期", ascending=False).head(10))
输出(示例数据):
华东区过万订单共2条:
姓名 部门 销售额 日期
2 小张 华东 15300 2026-01-07
0 小王 华东 12000 2026-01-05
筛选+排序是”读进程序→看清长相→按需提问”三部曲的第三步。上一篇回答”总量类”问题,这一篇回答”哪几行”类问题。老板再追问,你的动作永远是:改条件、重跑、十秒交货。
五、四个必踩的坑(先打疫苗)
坑1:忘加小括号,条件”串味”。 写成df["部门"] == "华东" & df["销售额"] > 10000必出事——&的优先级比==、>高,Python会先算"华东" & df["销售额"]这种鬼东西,报错TypeError或者结果全错。铁律:每个条件一对小括号,宁多勿少。
坑2:用and/or写条件。 df[(...) and (...)]直接报错ValueError: The truth value of a Series is ambiguous(”一列的真假说不清”)。翻译:and是问”整个东西是真是假”,而一列里有真有假,它答不上来。pandas的规矩:且用&,或用|,非用~(取反,比如df[~(df["部门"] == "华东")]就是”不是华东的所有行”)。
坑3:筛完就改,忘了”筛选返回的是副本”。 华东们 = df[df["部门"] == "华东"]之后对华东们改数据,原表df纹丝不动——筛选是”摘抄”,不是”剪切”。想直接在筛出来的行上改、并且改的就是原表?写法是df.loc[条件, "列名"] = 新值(对,loc上一篇见过,行位置放条件也行)。但新手阶段建议:筛出来的副本随便看随便算,别急着改原表,改坏了没法恢复。
坑4:”日期”列拿来筛月份,报AttributeError。 df["日期"].dt.month报错说没有dt?因为Excel里的日期读进来可能是文本(object类型,坑4上一篇提过)。先转换再筛:
df["日期"] = pd.to_datetime(df["日期"]) # 整列转成真日期
三月 = df[df["日期"].dt.month == 3] # .dt.month 取月份,.dt.year 取年份
筛”2026年3月”就是df[(df["日期"].dt.year == 2026) & (df["日期"].dt.month == 3)]。pd.to_datetime()是pandas自带的”日期翻译官”,格式怪的(2026/3/5、5-Mar-2026)大多也能认出来。
六、跟AI协作的正确姿势(筛选排序特供)
- 用”人话条件”指挥,让AI翻译成代码。说”帮我筛出部门是华东、销售额大于10000、日期在2026年3月的行,按销售额降序”——三个条件说全,AI写出的
&组合就不会缺胳膊少腿。它最常犯的错就是漏括号和用and,拿到代码先检查这两处 - 要”中间变量版”,不要”一行流”。AI爱炫技写
print(df[(df['部门']=='华东')&(df['销售额']>10000)].sort_values('销售额',ascending=False))——能跑,但你改条件时无从下手。追加一句:”每一步赋值给一个中文变量名,分步写“ - 筛完先验货。让AI代码末尾带上
print(len(结果), 结果.head())——条数对不对、长什么样,一眼验完再拿去见老板。Excel里你筛选完好歹瞄得见,程序里不打印就是”盲盒”
高频句式:”表有这些列(贴df.dtypes的输出),我要筛出’某某条件’的行、按’某列’降序排,只取前N条。请分步写代码,每个条件单独赋变量,并在每步后面用print验货“。
七、今日小练习
练习1:十秒钟销售排行榜
筛出”销售额大于平均值”的所有订单,按销售额降序打印,并标出排名(第1名、第2名……)。(提示:平均值上一篇学过df["销售额"].mean(),直接塞进条件df["销售额"] > df["销售额"].mean()——条件右边可以是算出来的值,不用先存变量。排名不用真排序函数,筛完sort_values后用for i, (_, row) in enumerate(结果.iterrows(), 1)打印;iterrows()是”一行一行吐出来”,enumerate带序号,第8篇的老朋友。)
练习2:三区对抗赛
分别筛出华东、华南、华北三个区的订单,算出每个区的总销售额和订单数,找出总销售额最高的区。(提示:三个区三种筛法,但别复制粘贴三遍——用for 部门 in ["华东", "华南", "华北"]:循环里套df[df["部门"] == 部门],结果存进一个字典{部门: 总额},最后max(字典, key=字典.get)找冠军——第8篇字典、第22篇记账本的思路原样复用。)
练习3:智能筛选器
写一个小程序:用户依次输入”列名、比较方式(>/</==)、阈值",程序筛出符合条件的行并打印条数。(提示:比较方式是字符串,用if/elif决定套哪个条件——但三个比较式不能拼字符串硬凑(那是第10篇警告过的”注入”老坑),乖乖写三份:条件 = df[列名] > 阈值 / df[列名] < 阈值 / df[列名] == 阈值。阈值注意input()拿到的是字符串,比较数字前先看df[列名].dtype是不是数字列,是就float(阈值)转换。列名写错用if 列名 in df.columns兜底,第31篇练习1的招。)
写在后面:从”点鼠标”到”写条件”
盘点今天:布尔筛选是主菜——df[条件]按条件摘行,条件是逐行问出来的True/False列;&且、|或、~非,每个条件加小括号;isin(名单)筛”在名单里”的;sort_values排序,ascending=False降序,多级排序传列表。加上上一篇的读表、取列、统计,”读进程序→看清长相→按需提问”的动线已经完整了。
更值钱的还是思路:Excel的筛选是一次性的手工劳动,换个条件从头点;pandas的筛选是写下来的条件,改一个字重跑就行,还能存进脚本下周再用。能被随手修改、反复重跑的查询,才是真的把数据捏在了手里。
下一篇,数据开始”分组”了:”每个部门各卖了多少””每人平均几单””哪个区人均最高”——这类分组统计问题,groupby一行一个。
下篇预告
第三十三篇:数据分组统计——groupby登场:一行代码算出”各部门总销售额、订单数、平均单值”,groupby+agg组合拳,数据透视表在你手里重生。老板要看”分部门对比”,再也不是二十次手动筛选。
发表回复