Python 自动化 Excel 按条件筛选数据


Python 自动化 Excel 按条件筛选数据

Python 自动化 Excel 按条件筛选数据详细教程

在数据处理工作中,按条件筛选是最常用的操作之一。无论是从大量数据中找出符合条件的记录,还是提取特定时间段、特定类别的数据,Python都能高效完成。本文将详细介绍各种筛选场景的实现方法,包含完整代码示例和最佳实践,批量处理效率远超手动操作。


一、环境准备

1.1 安装依赖库

bash
pip install openpyxl pandas numpy

1.2 适用场景

按条件筛选数据广泛应用于各种工作场景:

  • 从销售数据中筛选出销售额大于10000的记录
  • 提取某个时间段内的订单、报表、流水数据
  • 筛选出特定部门、特定人员、特定产品的相关数据
  • 找出异常值、空值、重复值等需要清理的数据
  • 从大量数据中提取符合条件的样本做进一步分析
  • 按条件拆分数据,生成不同的报表

  • 二、基础筛选操作

    2.1 使用pandas简单筛选

    pandas是筛选数据最简单高效的工具,几行代码就能完成复杂筛选。

    示例数据:

    我们用员工信息表做演示,包含字段:姓名、部门、入职日期、工资、绩效、是否在职。

    python
    import pandas as pd
    
    # 读取Excel
    df = pd.read_excel("员工信息.xlsx")
    print("原始数据:")
    print(df.head())
    

    2.2 单条件筛选

    python
    # 筛选部门为"技术部"的员工
    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 多条件组合筛选

    使用逻辑运算符组合多个条件:

  • `&`:逻辑与(and),多个条件同时满足
  • `|`:逻辑或(or),满足任意一个条件即可
  • `~`:逻辑非(not),不满足该条件
  • python
    # 筛选技术部且工资大于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 筛选后保存结果

    python
    # 筛选技术部员工并保存为新文件
    df_tech = df[df["部门"] == "技术部"]
    df_tech.to_excel("技术部员工名单.xlsx", index=False)
    print("✅ 技术部员工名单已保存")
    

    三、高级筛选技巧

    3.1 按列表筛选(IN查询)

    筛选字段值在指定列表中的记录:

    python
    # 筛选技术部、产品部、设计部的员工
    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 模糊筛选(包含特定内容)

    筛选包含特定关键词的记录:

    python
    # 筛选姓名包含"张"的员工
    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 空值/非空值筛选

    python
    # 筛选绩效为空的员工
    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 数值范围筛选

    python
    # 筛选工资在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 日期筛选

    python
    # 确保日期列是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 去重筛选

    python
    # 查看有哪些部门
    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方法语法更简洁,适合复杂条件:

    python
    # 单条件
    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 自定义函数筛选

    对于复杂的筛选逻辑,可以写自定义函数:

    python
    # 筛选工资大于同部门平均工资的员工
    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 分组后筛选组内数据

    先分组再筛选组内符合条件的记录:

    python
    # 筛选每个部门工资最高的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 筛选后修改数据

    筛选出符合条件的记录后直接修改对应字段:

    python
    # 给绩效为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筛选:

    python
    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 筛选结果统计

    python
    # 统计各部门人数
    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 筛选结果排序

    python
    # 按工资降序排序
    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文件:

    python
    # 获取所有部门
    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 筛选结果保存到不同工作表

    python
    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文件,筛选符合条件的数据合并:

    python
    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["销售 金额"]`
    query方法用反引号包裹:`df.query("`销售 金额` > 10000")`
    最好先把列名重命名为英文或不带特殊字符的名称:
    python
    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 日期筛选不生效

    问题:按日期筛选不到数据

    解决方案

    先转换为日期格式:`df["日期"] = pd.to_datetime(df["日期"], errors="coerce")`
    日期字符串用标准格式:`"2026-03-31"`,不要用`"2026/3/31"`等格式
    检查是否有空值或转换失败的日期:`print(df[df["日期"].isna()])`

    8.4 筛选后索引错乱

    问题:筛选后行号不连续,导致后续操作报错

    解决方案

    筛选后重置索引:`df_filtered = df_filtered.reset_index(drop=True)`

    8.5 大文件筛选慢

    问题:几十万行的数据筛选很慢

    解决方案

    提前转换好数据类型,尤其是日期、数值类型
    只读取需要的列:`df = pd.read_excel("文件.xlsx", usecols=["部门", "工资", "绩效"])`
    优先用向量运算,避免用apply自定义函数,速度慢很多
    数据量超百万建议用numpy或者数据库处理

    九、最佳实践

    1. 先看数据再筛选:筛选前先查看数据结构、列名、数据类型,避免筛选逻辑错误

    2. 条件从简到繁:先测试单个条件,再组合多个条件,方便排查问题

    3. 验证结果:筛选后统计数量,和预期结果对比,避免漏筛、错筛

    4. 保留原数据:不要直接修改原文件,筛选结果保存为新文件

    5. 复杂条件注释:多条件组合时添加注释,方便后续维护

    6. 空值处理:注意处理空值,避免筛选结果包含空值或者遗漏数据

    7. 性能优化:大文件优先用pandas的内置筛选方法,少用apply自定义函数

    8. 异常处理:批量处理时添加异常捕获,避免单个文件错误导致整个流程中断

    按条件筛选数据是Python数据处理的核心技能之一,熟练掌握这些方法可以让你在处理各种Excel数据时得心应手,大幅提升工作效率。无论是简单的单条件筛选还是复杂的自定义规则筛选,pandas都能轻松应对。

    © 版权声明

    相关文章

    暂无评论

    none
    暂无评论...