Python 自动化 Excel 按条件筛选数据详细教程
在数据处理工作中,按条件筛选是最常用的操作之一。无论是从大量数据中找出符合条件的记录,还是提取特定时间段、特定类别的数据,Python都能高效完成。本文将详细介绍各种筛选场景的实现方法,包含完整代码示例和最佳实践,批量处理效率远超手动操作。
一、环境准备
1.1 安装依赖库
pip install openpyxl pandas numpy
1.2 适用场景
按条件筛选数据广泛应用于各种工作场景:
二、基础筛选操作
2.1 使用pandas简单筛选
pandas是筛选数据最简单高效的工具,几行代码就能完成复杂筛选。
示例数据:
我们用员工信息表做演示,包含字段:姓名、部门、入职日期、工资、绩效、是否在职。
import pandas as pd
# 读取Excel
df = pd.read_excel("员工信息.xlsx")
print("原始数据:")
print(df.head())
2.2 单条件筛选
# 筛选部门为"技术部"的员工
df_tech = df[df["部门"] == "技术部"]
print("技术部员工:")
print(df_tech)
# 筛选工资大于15000的员工
df_high_salary = df[df["工资"] > 15000]
print("\n工资大于15000的员工:")
print(df_high_salary)
# 筛选入职日期在2023年之前的员工
df["入职日期"] = pd.to_datetime(df["入职日期"]) # 先转换成日期格式
df_old = df[df["入职日期"] < "2023-01-01"]
print("\n2023年前入职的员工:")
print(df_old)
# 筛选绩效为A的在职员工
df_excellent = df[(df["绩效"] == "A") & (df["是否在职"] == "是")]
print("\n绩效为A的在职员工:")
print(df_excellent)
2.3 多条件组合筛选
使用逻辑运算符组合多个条件:
# 筛选技术部且工资大于15000的员工
df1 = df[(df["部门"] == "技术部") & (df["工资"] > 15000)]
print("技术部且工资>15000:", len(df1), "人")
# 筛选绩效为A或者工资大于20000的员工
df2 = df[(df["绩效"] == "A") | (df["工资"] > 20000)]
print("绩效A或工资>20000:", len(df2), "人")
# 筛选不是人事部且在职的员工
df3 = df[(df["部门"] != "人事部") & (df["是否在职"] == "是")]
print("非人事部在职员工:", len(df3), "人")
# 筛选入职在2022-2023年之间的员工
df4 = df[(df["入职日期"] >= "2022-01-01") & (df["入职日期"] <= "2023-12-31")]
print("2022-2023年入职:", len(df4), "人")
2.4 筛选后保存结果
# 筛选技术部员工并保存为新文件
df_tech = df[df["部门"] == "技术部"]
df_tech.to_excel("技术部员工名单.xlsx", index=False)
print("✅ 技术部员工名单已保存")
三、高级筛选技巧
3.1 按列表筛选(IN查询)
筛选字段值在指定列表中的记录:
# 筛选技术部、产品部、设计部的员工
departments = ["技术部", "产品部", "设计部"]
df_selected = df[df["部门"].isin(departments)]
print("技术/产品/设计部员工:", len(df_selected), "人")
# 筛选不在列表中的员工
df_other = df[~df["部门"].isin(departments)]
print("其他部门员工:", len(df_other), "人")
# 筛选姓名在指定列表中的员工
names = ["张三", "李四", "王五"]
df_names = df[df["姓名"].isin(names)]
print("指定姓名员工:")
print(df_names)
3.2 模糊筛选(包含特定内容)
筛选包含特定关键词的记录:
# 筛选姓名包含"张"的员工
df_zhang = df[df["姓名"].str.contains("张", na=False)]
print("姓张的员工:", len(df_zhang), "人")
# 筛选部门名称包含"销售"的员工
df_sales = df[df["部门"].str.contains("销售", na=False)]
print("销售相关部门员工:", len(df_sales), "人")
# 筛选以"李"开头的员工
df_li = df[df["姓名"].str.startswith("李", na=False)]
print("姓李的员工:", len(df_li), "人")
# 筛选以"师"结尾的职位
df_teacher = df[df["职位"].str.endswith("师", na=False)]
print("职位以师结尾:", len(df_teacher), "人")
# 忽略大小写匹配
df_tech = df[df["部门"].str.contains("TECH", case=False, na=False)]
print("技术部(忽略大小写):", len(df_tech), "人")
3.3 空值/非空值筛选
# 筛选绩效为空的员工
df_no_perf = df[df["绩效"].isna()]
print("绩效为空的员工:", len(df_no_perf), "人")
# 筛选备注不为空的员工
df_has_remark = df[df["备注"].notna()]
print("有备注的员工:", len(df_has_remark), "人")
# 删除空值记录
df_clean = df.dropna(subset=["绩效", "工资"]) # 删除绩效或工资为空的记录
print("删除空值后剩余:", len(df_clean), "人")
3.4 数值范围筛选
# 筛选工资在10000-20000之间的员工
df_mid_salary = df[(df["工资"] >= 10000) & (df["工资"] <= 20000)]
print("工资10k-20k:", len(df_mid_salary), "人")
# 更简单的写法:between
df_mid_salary = df[df["工资"].between(10000, 20000)]
print("工资10k-20k:", len(df_mid_salary), "人")
# 筛选年龄在25-35岁之间
df_age = df[df["年龄"].between(25, 35)]
print("年龄25-35岁:", len(df_age), "人")
3.5 日期筛选
# 确保日期列是datetime格式
df["入职日期"] = pd.to_datetime(df["入职日期"])
# 筛选2023年入职的员工
df_2023 = df[df["入职日期"].dt.year == 2023]
print("2023年入职:", len(df_2023), "人")
# 筛选3月份入职的员工
df_march = df[df["入职日期"].dt.month == 3]
print("3月份入职:", len(df_march), "人")
# 筛选周一入职的员工
df_monday = df[df["入职日期"].dt.weekday == 0] # weekday=0是周一
print("周一入职:", len(df_monday), "人")
# 筛选最近30天入职的员工
from datetime import datetime, timedelta
thirty_days_ago = datetime.now() - timedelta(days=30)
df_new = df[df["入职日期"] >= thirty_days_ago]
print("最近30天入职:", len(df_new), "人")
# 筛选日期区间
df_date_range = df[df["入职日期"].between("2022-01-01", "2023-12-31")]
print("2022-2023年入职:", len(df_date_range), "人")
3.6 去重筛选
# 查看有哪些部门
print("所有部门:", df["部门"].unique())
# 去除重复记录,保留第一个
df_unique = df.drop_duplicates(subset=["姓名", "部门"], keep="first")
print("去重后:", len(df_unique), "人")
# 找出重复记录
df_duplicates = df[df.duplicated(subset=["姓名", "部门"], keep=False)]
print("重复记录:", len(df_duplicates), "人")
四、复杂筛选场景
4.1 使用query方法筛选
query方法语法更简洁,适合复杂条件:
# 单条件
df_tech = df.query("部门 == '技术部'")
# 多条件
df_filtered = df.query("部门 == '技术部' and 工资 > 15000 and 绩效 == 'A'")
# 引用外部变量
min_salary = 15000
df_high = df.query("工资 > @min_salary")
# 日期筛选
df_2023 = df.query("入职日期 >= '2023-01-01' and 入职日期 < '2024-01-01'")
# 包含判断
departments = ["技术部", "产品部"]
df_selected = df.query("部门 in @departments")
print("query筛选结果:", len(df_filtered), "人")
4.2 自定义函数筛选
对于复杂的筛选逻辑,可以写自定义函数:
# 筛选工资大于同部门平均工资的员工
def higher_than_avg(row):
dept_avg = df[df["部门"] == row["部门"]]["工资"].mean()
return row["工资"] > dept_avg
# 使用apply应用函数
df_high_than_avg = df[df.apply(higher_than_avg, axis=1)]
print("工资高于部门平均:", len(df_high_than_avg), "人")
# 更复杂的条件:入职满3年且绩效为A,或者入职满5年且绩效为B
def good_employee(row):
work_years = (pd.Timestamp.now() - row["入职日期"]).days / 365
return (work_years >= 3 and row["绩效"] == "A") or (work_years >=5 and row["绩效"] == "B")
df_good = df[df.apply(good_employee, axis=1)]
print("优秀员工:", len(df_good), "人")
4.3 分组后筛选组内数据
先分组再筛选组内符合条件的记录:
# 筛选每个部门工资最高的3个人
df_top3 = df.groupby("部门", group_keys=False).apply(
lambda x: x.nlargest(3, "工资")
).reset_index(drop=True)
print("各部门工资前3:")
print(df_top3[["部门", "姓名", "工资"]])
# 筛选部门平均工资大于15000的所有员工
dept_avg = df.groupby("部门")["工资"].mean().reset_index()
high_depts = dept_avg[dept_avg["工资"] > 15000]["部门"].tolist()
df_high_dept = df[df["部门"].isin(high_depts)]
print("平均工资>15k的部门员工:", len(df_high_dept), "人")
4.4 筛选后修改数据
筛选出符合条件的记录后直接修改对应字段:
# 给绩效为A的员工工资上涨10%
df.loc[df["绩效"] == "A", "工资"] = df.loc[df["绩效"] == "A", "工资"] * 1.1
# 给入职满3年的员工添加"老员工"标签
df["标签"] = ""
df.loc[df["入职日期"] < "2023-01-01", "标签"] = "老员工"
# 将工资低于10000的绩效为C的员工标记为"待提升"
df.loc[(df["工资"] < 10000) & (df["绩效"] == "C"), "标签"] = "待提升"
print("✅ 数据修改完成")
五、openpyxl筛选(保留原格式)
如果需要保留原Excel的格式、公式等,可以用openpyxl筛选:
from openpyxl import load_workbook
from openpyxl import Workbook
wb = load_workbook("员工信息.xlsx")
ws = wb.active
# 创建新工作簿保存筛选结果
new_wb = Workbook()
new_ws = new_wb.active
# 复制表头
for col in range(1, ws.max_column + 1):
new_ws.cell(row=1, column=col, value=ws.cell(row=1, column=col).value)
# 复制样式
if ws.cell(row=1, column=col).has_style:
new_ws.cell(row=1, column=col).font = ws.cell(row=1, column=col).font.copy()
new_ws.cell(row=1, column=col).fill = ws.cell(row=1, column=col).fill.copy()
# 筛选技术部员工
new_row = 2
for row in range(2, ws.max_row + 1):
department = ws.cell(row=row, column=2).value # B列是部门
if department == "技术部":
# 复制整行
for col in range(1, ws.max_column + 1):
source_cell = ws.cell(row=row, column=col)
target_cell = new_ws.cell(row=new_row, column=col, value=source_cell.value)
# 复制样式
if source_cell.has_style:
target_cell.font = source_cell.font.copy()
target_cell.border = source_cell.border.copy()
target_cell.fill = source_cell.fill.copy()
target_cell.number_format = source_cell.number_format
new_row += 1
# 调整列宽
for col in range(1, ws.max_column + 1):
new_ws.column_dimensions[chr(64 + col)].width = ws.column_dimensions[chr(64 + col)].width
new_wb.save("技术部员工_带格式.xlsx")
print("✅ 带格式筛选完成,共找到", new_row-2, "条记录")
六、筛选结果处理
6.1 筛选结果统计
# 统计各部门人数
dept_count = df["部门"].value_counts()
print("各部门人数:")
print(dept_count)
# 统计绩效分布
perf_stats = df["绩效"].value_counts()
print("\n绩效分布:")
print(perf_stats)
# 计算筛选结果的统计量
df_tech = df[df["部门"] == "技术部"]
print("\n技术部工资统计:")
print(f"平均工资:{df_tech['工资'].mean():.2f}")
print(f"最高工资:{df_tech['工资'].max()}")
print(f"最低工资:{df_tech['工资'].min()}")
print(f"工资中位数:{df_tech['工资'].median()}")
6.2 筛选结果排序
# 按工资降序排序
df_sorted = df[df["部门"] == "技术部"].sort_values(by="工资", ascending=False)
print("技术部员工按工资降序:")
print(df_sorted[["姓名", "工资"]])
# 多列排序:先按部门升序,再按工资降序
df_multi_sort = df.sort_values(by=["部门", "工资"], ascending=[True, False])
6.3 按筛选结果拆分文件
按部门拆分成不同的Excel文件:
# 获取所有部门
departments = df["部门"].unique()
for dept in departments:
df_dept = df[df["部门"] == dept]
filename = f"{dept}员工名单.xlsx"
df_dept.to_excel(filename, index=False)
print(f"✅ 已生成:{filename},共{len(df_dept)}人")
6.4 筛选结果保存到不同工作表
with pd.ExcelWriter("各部门员工数据.xlsx") as writer:
for dept in departments:
df_dept = df[df["部门"] == dept]
df_dept.to_excel(writer, sheet_name=dept, index=False)
print("✅ 各部门数据已保存到不同工作表")
七、批量筛选多个文件
批量处理文件夹下所有Excel文件,筛选符合条件的数据合并:
import os
import pandas as pd
folder_path = "月度销售数据/"
all_filtered = []
for file in os.listdir(folder_path):
if file.endswith((".xlsx", ".xls")) and not file.startswith("~$"):
file_path = os.path.join(folder_path, file)
print(f"正在处理:{file}")
df = pd.read_excel(file_path)
# 筛选销售额大于10000的记录
df_filtered = df[df["销售额"] > 10000]
df_filtered["来源文件"] = file
all_filtered.append(df_filtered)
# 合并所有筛选结果
if all_filtered:
merged_df = pd.concat(all_filtered, ignore_index=True)
merged_df.to_excel("销售额大于10000的记录.xlsx", index=False)
print(f"\n✅ 处理完成,共找到{len(merged_df)}条符合条件的记录")
else:
print("\n❌ 没有符合条件的记录")
八、常见问题与解决方案
8.1 中文列名/特殊字符筛选报错
问题:列名有中文、空格、特殊字符时筛选报错
解决方案:
df = df.rename(columns={"销售 金额": "销售额", "用户 姓名": "姓名"})
8.2 字符串匹配不生效
问题:str.contains匹配不到内容
原因排查:
1. 检查是否有空格、不可见字符:`df["姓名"] = df["姓名"].str.strip()`
2. 确保是字符串类型:`df["姓名"] = df["姓名"].astype(str)`
3. 特殊字符需要转义,比如点号、星号等:`df["内容"].str.contains("\.", regex=True)`
4. 加na=False参数,避免空值报错:`str.contains("关键词", na=False)`
8.3 日期筛选不生效
问题:按日期筛选不到数据
解决方案:
8.4 筛选后索引错乱
问题:筛选后行号不连续,导致后续操作报错
解决方案:
8.5 大文件筛选慢
问题:几十万行的数据筛选很慢
解决方案:
九、最佳实践
1. 先看数据再筛选:筛选前先查看数据结构、列名、数据类型,避免筛选逻辑错误
2. 条件从简到繁:先测试单个条件,再组合多个条件,方便排查问题
3. 验证结果:筛选后统计数量,和预期结果对比,避免漏筛、错筛
4. 保留原数据:不要直接修改原文件,筛选结果保存为新文件
5. 复杂条件注释:多条件组合时添加注释,方便后续维护
6. 空值处理:注意处理空值,避免筛选结果包含空值或者遗漏数据
7. 性能优化:大文件优先用pandas的内置筛选方法,少用apply自定义函数
8. 异常处理:批量处理时添加异常捕获,避免单个文件错误导致整个流程中断
按条件筛选数据是Python数据处理的核心技能之一,熟练掌握这些方法可以让你在处理各种Excel数据时得心应手,大幅提升工作效率。无论是简单的单条件筛选还是复杂的自定义规则筛选,pandas都能轻松应对。