乐于分享
好东西不私藏

Python 玩转 Excel 案例【第 16 期】

Python 玩转 Excel 案例【第 16 期】

Python 玩转 Excel 案例【第 16 期】

📌 案例说明

原始数据表:

员工信息表:

工号
姓名
部门
10001
张三
销售部
10002
李四
技术部
10003
王五
技术部
10004
赵六
市场部
10005
周七
人事部

工资表(匹配前):

工号
姓名
基本工资
10001
8000
10002
12000
10003
11000
10004
8500
99999
5000

这是日常数据处理中非常常见的场景:两张表需要根据共同字段(工号)进行信息匹配。工资表的姓名列为空,需要从员工信息表中把对应的姓名填充过来。

目标任务:

在 Excel 中,这类需求通常使用 VLOOKUP 函数解决。

本期案例将跟大家一起学习如何用 Python 实现类似 VLOOKUP 的功能。

核心操作:数据映射 + 数据质量核查

  • • 关键函数map()isin()tolist()
  • • 核心逻辑:用工号作为桥梁,从信息表匹配姓名,同时检查哪些工号匹配失败

📜 完整代码

"""
VLOOKUP匹配填充 - 根据工号从信息表匹配姓名
数据质量核查,输出未匹配到的工号列表
"""

import
 pandas as pd

# 读取两张表

df_info = pd.read_excel("员工信息表.xlsx")   # 工号、姓名、部门
df_salary = pd.read_excel("工资表.xlsx")     # 工号、姓名(空)、基本工资

# 根据工号匹配姓名(类似VLOOKUP)

df_salary["姓名"] = df_salary["工号"].map(df_info.set_index("工号")["姓名"])

# 数据质量核查:检查哪些工号没匹配上

unmatched = df_salary[~df_salary["工号"].isin(df_info["工号"])]["工号"].tolist()
print
(f"⚠️ 未匹配到的工号:{unmatched}" if unmatched else "✅ 全部匹配成功")

# 保存结果

df_salary.to_excel("工资表_填充后.xlsx", index=False)

运行结果:

⚠️ 未匹配到的工号:[99999]

匹配后的工资表:

工号
姓名
基本工资
10001
张三
8000
10002
李四
12000
10003
王五
11000
10004
赵六
8500
99999
NaN
5000

⚠️ 注意:工号 99999 在员工信息表中不存在,所以姓名填充为 NaN(空值),并被程序检测出来。


第一步:导入所需库

import pandas as pd

代码解释:

  • • import pandas as pd
    导入 pandas 库,这是 Python 数据处理的核心武器。它提供了 read_excel() 读取 Excel、DataFrame 数据结构、map() 数据映射、isin() 条件筛选等强大功能。

第二步:读取数据

df_info = pd.read_excel("员工信息表.xlsx")   # 工号、姓名、部门
df_salary = pd.read_excel("工资表.xlsx")     # 工号、姓名(空)、基本工资

代码解释:

  • • pd.read_excel()
    读取 Excel 文件,返回 DataFrame(数据表格)对象。
  • • df_info
    存储员工信息表,包含工号、姓名、部门三列。
  • • df_salary
    存储工资表,包含工号、姓名(空)、基本工资三列。

💡 小贴士read_excel() 默认读取第一个工作表,如果文件有多个 Sheet,可以用 sheet_name 参数指定,如

 pd.read_excel("文件.xlsx", sheet_name="Sheet2")

第三步:核心匹配(VLOOKUP)

df_salary["姓名"] = df_salary["工号"].map(df_info.set_index("工号")["姓名"])

这行代码是整期案例的灵魂,实现了类似 Excel VLOOKUP 的功能。我们来一步步拆解:

3.1 df_info.set_index("工号")

将信息表的”工号”列设为行索引。

执行前:

工号
姓名
部门
10001
张三
销售部
10002
李四
技术部
10003
王五
技术部

执行后:

工号(索引)
姓名
部门
10001
张三
销售部
10002
李四
技术部
10003
王五
技术部

3.2 df_info.set_index("工号")["姓名"] – 构建查找表

只取出”姓名”这一列,得到一个 Series(带标签的一维数组),本质上就是一个键值对映射

键(Key)- 工号
值(Value)- 姓名
10001
张三
10002
李四
10003
王五
10004
赵六
10005
周七

为什么不能直接写 df_info["姓名"]

写法
结果
问题
df_info["姓名"]
一个姓名列表:['张三','李四','王五'...]
只有姓名,没有工号作为查找依据,无法匹配
df_info.set_index("工号")["姓名"]
工号→姓名的映射表
可以直接用工号找到对应的姓名

3.3 .map() 执行匹配

map() 是 pandas 中用于数据映射的方法,将一个 Series 中的每个值按照规则转换成另一个值。

df_salary["工号"].map(查找表)

执行过程:

工资表工号
查找表中是否存在
返回结果
10001
✅ 存在
张三
10002
✅ 存在
李四
10003
✅ 存在
王五
10004
✅ 存在
赵六
99999
❌ 不存在
NaN(空值)

3.4 赋值给姓名列

将匹配结果赋给 df_salary["姓名"],完成姓名填充。


完整流程示意图

原始 df_info:
┌─────────┬────────┬────────┬────────┐
│ 数字索引 │  工号  │  姓名  │  部门  │
├─────────┼────────┼────────┼────────┤
│    0    │ 10001  │  张三  │ 销售部 │
│    1    │ 10002  │  李四  │ 技术部 │
│    2    │ 10003  │  王五  │ 技术部 │
│    3    │ 10004  │  赵六  │ 市场部 │
│    4    │ 10005  │  周七  │ 人事部 │
└─────────┴────────┴────────┴────────┘
                    ↓
           .set_index("工号")
                    ↓
┌────────┬────────┬────────┐
│  工号  │  姓名  │  部门  │  ← 工号变成了行索引
├────────┼────────┼────────┤
│ 10001  │  张三  │ 销售部 │
│ 10002  │  李四  │ 技术部 │
│ 10003  │  王五  │ 技术部 │
│ 10004  │  赵六  │ 市场部 │
│ 10005  │  周七  │ 人事部 │
└────────┴────────┴────────┘
                    ↓
              ["姓名"]
                    ↓
┌────────┬────────┐
│  工号  │  姓名  │  ← 只保留姓名列(查找表)
├────────┼────────┤
│ 10001  │  张三  │
│ 10002  │  李四  │
│ 10003  │  王五  │
│ 10004  │  赵六  │
│ 10005  │  周七  │
└────────┴────────┘
        ↓
    map() 匹配
        ↓
工资表工号 10003 → 查找表[10003] → "王五"

对比:有查找表 vs 无查找表

# 有查找表(简洁高效)
姓名 = 查找表[10003]  # 返回 "王五"

# 无查找表(又长又慢)

姓名 = df_info[df_info["工号"] == 10003]["姓名"].values[0]  # 返回 "王五"

第四步:数据质量核查

unmatched = df_salary[~df_salary["工号"].isin(df_info["工号"])]["工号"].tolist()
print
(f"⚠️ 未匹配到的工号:{unmatched}" if unmatched else "✅ 全部匹配成功")

这行代码是数据质量核查的关键,能够自动找出哪些工号匹配失败。

逐步拆解

4.1 df_salary["工号"].isin(df_info["工号"])

判断工资表的每个工号是否在信息表的工号列表中。

工资表工号
是否存在于信息表
10001
True
10002
True
10003
True
10004
True
99999
False

4.2 ~ 取反

波浪线 ~ 是取反运算符,True 变 False,False 变 True。

原结果
取反后
True
False
True
False
True
False
True
False
False
True

4.3 df_salary[~df_salary["工号"].isin(df_info["工号"])]

用布尔值筛选行,只保留为 True 的行(即匹配失败的行)。

结果:

工号
姓名
基本工资
99999
NaN
5000

4.4 ["工号"] 和 .tolist()

取出工号列,并转换为 Python 列表。

最终结果:unmatched = [99999]

输出效果

  • • 有未匹配的工号⚠️ 未匹配到的工号:[99999]
  • • 全部匹配成功✅ 全部匹配成功

💡 小贴士:这个数据质量检查环节非常重要!在实际工作中,匹配失败通常意味着:信息表漏了某位员工、工资表工号录入错误、或者工号格式不一致(如文本型数字 vs 数值型数字)。及早发现这些问题,可以避免后续数据错误。


第五步:保存结果

df_salary.to_excel("工资表_填充后.xlsx", index=False)

print
("✅ VLOOKUP匹配完成")

代码解释:

  • • to_excel()
    将 DataFrame 保存为 Excel 文件。
  • • "工资表_填充后.xlsx"
    输出文件名。使用新文件名可以保留原始数据,方便对比验证。
  • • index=False
    不保存行索引。pandas 默认会给每行加一个数字索引(0,1,2…),通常我们不需要它出现在 Excel 中。

⚠️ 注意:这里保存为新文件,原始 工资表.xlsx 不会被修改。如果需要覆盖原文件,可以改成 df_salary.to_excel("工资表.xlsx", index=False),但建议保留原始数据。


📚 本期核心知识点

📍 知识点 1:map() 数据映射

df_salary["姓名"] = df_salary["工号"].map(查找表)
  • • 作用:将一个 Series 中的每个值,按照规则转换成另一个值
  • • 支持:字典映射、Series 映射、函数映射
  • • 特点:匹配失败返回 NaN

其他用法示例:

# 字典映射
df["性别代码"] = df["性别"].map({"男": 1, "女": 0})

# 函数映射

df["工号前缀"] = df["工号"].map(lambda x: f"EMP-{x}")

📍 知识点 2:isin() + ~ 查找不存在的值

unmatched = df_salary[~df_salary["工号"].isin(df_info["工号"])]["工号"].tolist()

记忆口诀:取反筛选不存在,取出列值转列表

符号
含义
作用
.isin()
判断是否在集合中
返回布尔值
~
取反运算符
True↔False 互换
df[布尔值]
布尔索引
筛选行
.tolist()
转列表
Series → list

📍 知识点 3:set_index() 设置行索引

df_info.set_index("工号")["姓名"]
  • • 作用:将指定列设置为行索引,方便快速查找
  • • 链式操作:设置索引后可以立即用 [列名] 取出需要的列

📍 知识点 4:to_excel() 保存文件

df.to_excel("输出文件.xlsx", index=False)
参数
含义
常用值
index
是否保存行索引
True

(默认)/ False
sheet_name
工作表名称
默认为 "Sheet1"
columns
指定输出哪些列
默认为全部列

🔄 本案例核心流程

① 读取两张表 → ② 构建查找表 → ③ map 匹配姓名 → ④ 数据质量核查 → ⑤ 保存结果

读取员工信息表 (df_info)              读取工资表 (df_salary)
        ↓                                      ↓
set_index("工号")["姓名"]                    工号列
        ↓                                      ↓
    查找表 ←─────────────────────────────────┘
        ↓
    map() 匹配
        ↓
df_salary["姓名"] = 匹配结果
        ↓
    数据质量核查(isin + ~ + tolist)
        ↓
   保存到新Excel (to_excel)

📦 资源获取提示

关注「码农自习室」,后台回复关键词 PythonExcel案例,即可获取本文完整代码及配套练习数据集,一起动手掌握高效数据操作的核心技巧!


❤️ 支持我们

如果本文对你有帮助,欢迎点赞 + 关注 + 点亮小红心,你的支持就是我们持续创作的最大动力~