第1节 openpyxl基础
欢迎来到 openpyxl 的世界,这是一个能让你一边喝咖啡,一边看着 Python 像勤劳的小蜜蜂一样帮你填表的库。
为了不让你睡着,我们设定一个场景:我们要管理一家名为“宇宙无敌皮皮虾进出口公司”的账本。
1. 安装:开工前的仪式感
首先,你得把这个“翻译官”请进你的电脑。
pip install openpyxl
2. 创建与保存:从无到有
想象你在生一个娃,给它起个名,然后把它塞进硬盘里。
from openpyxl import Workbook
# 1. 实例化:像变魔术一样变出一个新工作簿
wb = Workbook()
# 2. 激活:默认自带一个叫 "Sheet" 的表,我们要抓住它
sheet = wb.active
sheet.title = "皮皮虾业绩表" # 给这张纸改个霸气的名字
# 3. 保存:一定要保存!不保存就像写了情书没寄出去,白忙活
wb.save("宇宙无敌账本.xlsx")
print("报告老板:新账本已就位,甚至有点烫手。")
3. 打开与读取:偷看商业机密
假设你已经有一个账本了,现在我们要去“视察工作”。
from openpyxl import load_workbook
# 加载现有的工作簿
wb = load_workbook("宇宙无敌账本.xlsx")
# 选一张表
sheet = wb["皮皮虾业绩表"]
# 读取单元格:两种姿势
val1 = sheet['A1'].value # 坐标式:直观,像打狙击
val2 = sheet.cell(row=1, column=1).value # 坐标轴式:适合写循环
print(f"A1里的秘密是:{val1}")
4. 写入数据:指点江山
写数据也有两种套路:一个是“精准打击”,一个是“顺流而下”。
# 方法一:精准打击 sheet['A1'] = "员工姓名" sheet['B1'] = "摸鱼时长(小时)" # 方法二:批量添加(追加到最后一行的下面) # 像在火锅店排队一样,一个接一个 data = [ ["张大炮", 8],
["李二狗", 0.5], # 这个员工很勤奋,建议开除(开个玩笑)
["王富贵", 12]
]
for row in data:
sheet.append(row)
wb.save("宇宙无敌账本.xlsx")
5. 样式魔法:让表格不再“素颜”
默认的 Excel 丑得像没洗脸。我们要给它涂口红、画眼影。
字体、对齐与颜色
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side # 1. 字体:给“张大炮”加个金光闪闪的特效 bold_red_font = Font(name='微软雅黑', size=14, bold=True, color="FF0000") # 颜色是16进制RGB sheet['A2'].font = bold_red_font # 2. 对齐:让“摸鱼时长”居中,别歪歪斜斜的 center_align = Alignment(horizontal='center', vertical='center') sheet['B1'].alignment = center_align # 3. 填充颜色:给表头上个色,免得老板看不清 # PatternFill 的 start_color 就是背景色 yellow_fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid") sheet['A1'].fill = yellow_fill sheet['B1'].fill = yellow_fill # 4. 边框:给单元格穿上“铁丝网” thin_side = Side(border_style="thin", color="000000") border = Border(top=thin_side, left=thin_side, right=thin_side, bottom=thin_side) sheet['A2'].border = border
6. 批量操作:效率起飞的绝招
如果你有 1000 行数据要改,手动改会死人的。这时候就要用到循环。
# 批量修改第二行到第四行的字体
for row in sheet.iter_rows(min_row=2, max_row=4, min_col=1, max_col=2):
for cell in row:
cell.font = Font(italic=True) # 全部变斜体,显得比较忧郁
cell.alignment = Alignment(horizontal='right')
# 自动调整列宽(这是一个小技巧,openpyxl没有一键自动调整,得自己算)
column_widths = [15, 20] # 假设第一列宽15,第二列宽20
for i, width in enumerate(column_widths, start=1):
column_letter = sheet.cell(row=1, column=i).column_letter
sheet.column_dimensions[column_letter].width = width
7. 总结:你的避坑指南
忘记保存: 所有的操作都在内存里,不调用 wb.save(),你就当刚才在做白日梦吧。
文件没关: 如果你一边用 Excel 打开着这个文件,一边运行 Python 代码,它会报错 PermissionError。Excel 是个醋坛子,它不允许别人同时碰它的文件。
索引从 1 开始: 在 openpyxl 里,行和列的索引是从 1 开始的,不是 Python 惯用的 0。记住,Excel 是给会计看的,不是给程序员看的。
恭喜你!你现在已经掌握了操作 Excel 的“降龙十八掌”前三式。去吧,去用 Python 把那些枯燥的报表折磨个遍!
第2节 pandas入门
这个强大的库想象成一个超级无敌自动化的 Excel 缝合怪。
Pandas 的核心就是让你不用手动点鼠标,也能把表格玩得转。准备好你的 Python 环境,我们要开始对 Excel “下手”了。
1. DataFrame:这就是你的“电子后宫”
在 Pandas 里,最核心的概念就是 DataFrame。你可以把它想象成一张 Excel 表格,有行(Index)有列(Columns)。
比喻: 如果 Series 是一个孤零零的单身狗(一列数据),那么 DataFrame 就是一整个联谊会(多列数据拼在一起)。
import pandas as pd
# 手动创建一个 DataFrame
# 想象我们在管理一个“程序员脱单进度表”
data = {
"姓名": ["张三", "李四", "王五"],
"发量": ["浓密", "稀疏", "反光"],
"相亲次数": [0, 5, 99],
"成功概率": [0.1, 0.01, 0.00001]
}
df = pd.DataFrame(data)
print("--- 程序员脱单现状 ---")
print(df)
# 核心属性(摸清它的底细)
print(f"列名有哪些:{df.columns.tolist()}")
print(f"数据长啥样(维度):{df.shape}") # (行数, 列数)
2. read_excel():把表格“抓”进 Python
别再用 Ctrl+C/V 了,read_excel 才是优雅的选择。但在读取之前,请确保你安装了引擎:pip install openpyxl。
情况 A:基础读取(最常用)
# 默认读取第一张 Sheet
df = pd.read_excel("你的秘密名单.xlsx")
情况 B:指定读取哪一张 Sheet
# 通过名字读:我想看“前任名单”那一页
df = pd.read_excel("你的秘密名单.xlsx", sheet_name="前任名单")
# 通过索引读:读取第二张表(程序员从0开始计数,所以是1)
df = pd.read_excel("你的秘密名单.xlsx", sheet_name=1)
情况 C:跳过废话(跳行)
有时候 Excel 抬头有两行废话(比如“XX公司机密”),我们不需要它。
# 跳过前两行,直接从第三行开始读
df = pd.read_excel("你的秘密名单.xlsx", skiprows=2)
情况 D:只读取特定的列
# 只要“姓名”和“发量”,别的我不关心
df = pd.read_excel("你的秘密名单.xlsx", usecols=["姓名", "发量"])
3. to_excel():把结果“吐”回 Excel
把处理好的数据存回去,通常直接用 df.to_excel("结果.xlsx")。但如果你想在一个文件里写多张 Sheet,那就得请出 ExcelWriter 这个“大总管”了。
绝招:一鱼多吃(一个文件存多张表)
如果你直接写两次 to_excel,后一个会把前一个直接覆盖掉。为了同时保存,必须用 with 语句:
# 准备两份数据
df_bad_hair = df[df["发量"] == "反光"]
df_normal = df[df["发量"] != "反光"]
# 开始表演:创建一个 ExcelWriter 对象
with pd.ExcelWriter("程序员分类大赏.xlsx") as writer:
# 把“强者”存入 Sheet1
df_bad_hair.to_excel(writer, sheet_name="资深专家级", index=False)
# 把“普通人”存入 Sheet2
df_normal.to_excel(writer, sheet_name="初出茅庐级", index=False)
print("报告老板,多张 Sheet 已分类存好,请查收!")
4. 汇总:read_excel 常用参数全家桶
| 参数 | 说明 | 搞笑翻译 |
|---|---|---|
| sheet_name | 指定 Sheet | “你要翻哪张牌子?” |
| header | 指定哪一行作为列名 | “谁才是带头的?” |
| usecols | 只取某些列 | “只看颜值,不看内涵” |
| nrows | 只读前几行 | “试看前5行,好用再买” |
| index_col | 把某一列设为索引 | “把身份证号当成行号” |
| na_values | 哪些字符算作空值 | “看到‘查无此人’就当它是空气” |
别忘保存: 在 with pd.ExcelWriter 模式下,代码运行完会自动保存。
拒绝乱码: 如果遇到老古董 .xls 文件,可能需要 pip install xlrd。
Index 烦恼: 导出时如果不想看到第一列多出来的 0, 1, 2 序号,记得加上 index=False。
学会了这几招,你就可以在办公室里一边喝咖啡,一边看着 Python 疯狂操作 Excel,深藏功与名。
第3节 数据清洗
嘿!欢迎来到 Python 数据清洗的“家政服务中心”。处理原始数据就像是刚去完泥地打滚回来的哈士奇,看着挺可爱,实际上满身泥巴(空值)、还总想分身(重复值)、甚至偶尔还觉得自己是一只猫(格式异常)。
为了提升数据的“颜值”和“准确率”,咱们得动用 Pandas 这个强力去污剂。
1. 批量处理空值(NaN):别让“虚无”毁了你的报表
空值就像是派对里那些拿了邀请函却没露面的人。你得决定是等他们、换人,还是直接划掉。
情况 A:惹不起还躲不起吗?(直接删除)
如果某行数据空得连它妈都不认识了,直接删掉。
import pandas as pd
import numpy as np
# 模拟一个“相亲对象”数据集
df = pd.DataFrame({
'姓名': ['张三', '李四', '王五', '赵六'],
'存款': [100000, np.nan, 500, np.nan],
'性格': ['温柔', '暴躁', np.nan, np.nan]
})
# 只要有空值就删(太绝情了)
df_cleaned = df.dropna()
# 只有当整行全是空值时才删(给点机会)
df_soft_cleaned = df.dropna(how='all')
print("洗完后的相亲名单:
", df_cleaned)
情况 B:用爱感化(填充默认值)
如果没有存款,我们就假设他有“梦想”。
# 把所有空值填充为 0
df['存款'] = df['存款'].fillna(0)
# 甚至可以用平均值填充(强行让大家进小康)
df['存款'] = df['存款'].fillna(df['存款'].mean())
# 针对不同列,给不同的“安慰奖”
df.fillna({'存款': 0, '性格': '神秘'}, inplace=True)
2. 处理重复值:禁止“影分身术”
有些数据特别自恋,喜欢在表里出现好几次。
情况 A:发现并消灭
# 模拟一个“渣男”打卡记录
df_repetitive = pd.DataFrame({
'姓名': ['小帅', '小帅', '小美', '小帅'],
'表白对象': ['小红', '小红', '小刚', '小红']
})
# 看看谁在搞分身
print(df_repetitive.duplicated())
# 只保留第一次出现的,其余原地毁灭
df_unique = df_repetitive.drop_duplicates()
# 也可以根据特定列去重:只要“姓名”重复,管你表白谁,都给我走
df_unique_name = df_repetitive.drop_duplicates(subset=['姓名'], keep='last') # 保留最后一次
3. 异常格式处理:纠正那些“不合群”的家伙
数据录入时,总有人喜欢整点花活,比如在数字里加空格,或者日期乱写。
情况 A:去掉烦人的空格(缩骨功)
“ 100 ” 和 “100” 在 Python 眼里可不是一个东西。
df_messy = pd.DataFrame({'工资': [' 5000', '6000 ', ' 7000 ', '8000']})
# 批量去掉左右两边的空格
df_messy['工资'] = df_messy['工资'].str.strip().astype(int)
情况 B:统一日期格式(认祖归宗)
有人写 2023-01-01,有人写 01/01/2023,系统会疯的。
df_date = pd.DataFrame({'纪念日': ['2023-05-20', '2023/05/21', '2023.05.22']})
# 万能转化法,不管你怎么写的,统统变成标准 YYYY-MM-DD
df_date['纪念日'] = pd.to_datetime(df_date['纪念日'])
情况 C:替换非法字符(驱逐出境)
如果“身高”列里突然混进了一个“姚明”,计算平均值时就会报错。
df_height = pd.DataFrame({'身高': ['175', '180', '姚明', '165']})
# 把非数字的东西强行变成 NaN,然后再处理
df_height['身高'] = pd.to_numeric(df_height['身高'], errors='coerce')
# 再次用我们学过的 fillna 补上
df_height['身高'] = df_height['身高'].fillna(df_height['身高'].mean())
4. 终极一招:apply 与 map 的魔法变换
当以上方法都搞不定那些奇葩数据时,就得自定义逻辑了。
# 模拟一个性别混乱的数据
df_gender = pd.DataFrame({'性别': ['男', 'female', 'M', '1', '0', '女']})
# 定义一个“性别修正器”
def fix_gender(x):
x = str(x).lower()
if x in ['男', 'm', '1']:
return '男性'
elif x in ['女', 'female', '0']:
return '女性'
else:
return '未知'
df_gender['性别'] = df_gender['性别'].apply(fix_gender)
总结:你的数据清洗清单
检查: df.info() 和 df.describe() 先看看病得有多重。
去重: drop_duplicates() 砍掉分身。
填坑: fillna() 或 dropna() 处理空值。
整形: str.strip()、pd.to_datetime() 统一格式。
精修: apply() 处理各种奇志异端。
洗完之后,你的数据就像剥了壳的鸡蛋,无论是做机器学习还是画报表,都丝滑得不得了!
你现在手里是有什么具体的“陈年老数”需要清洗吗?
第4节 数据排序筛选
面对成千上万行数据,如果不学会筛选、排序和汇总,那你面对的就不是资产,而是堆积如山的“数字垃圾”。
我们要请出 Python 界的“瑞士军刀”:Pandas。为了让例子通俗易懂,我们假设你开了一家“超级英雄相亲角”,手里有一份相亲名单。
1. 数据准备:我们的相亲嘉宾
首先,得有数据。我们创建一个 DataFrame,包含英雄的姓名、性别、年龄、战斗力以及所属阵营。
import pandas as pd
# 英雄相亲名单
data = {
'姓名': ['灭霸', '美队', '钢铁侠', '雷神', '黑寡妇', '绿巨人', '死侍', '蜘蛛侠'],
'性别': ['男', '男', '男', '男', '女', '男', '男', '男'],
'年龄': [1000, 105, 48, 1500, 35, 45, 38, 18],
'战力值': [99, 85, 90, 95, 75, 98, 88, 80],
'阵营': ['反派', '复仇者', '复仇者', '复仇者', '复仇者', '复仇者', '雇佣兵', '复仇者']
}
df = pd.DataFrame(data)
print("--- 原始相亲名单 ---")
print(df)
2. 数据筛选:拒绝“普信男”,只要“高质量”
数据筛选就像是你在相亲平台上划动手指,只看你想看的人。
A. 单条件过滤
只要战力值大于 90 的“猛男/猛女”:
# 筛选战力超过 90 的大佬 strong_heros = df[df['战力值'] > 90]
B. 多条件过滤 (AND / OR)
注意: 在 Pandas 中,and 要写成 &,or 要写成 |,而且每个条件都要用小括号包起来(这很重要,不然 Python 会跟你闹脾气)。
且(&): 想要年纪大(30岁以上)且战力强(85以上)的。
或(|): 或者是复仇者,或者是死侍那种雇佣兵。
# 1. 既成熟(>30)又耐打(>85) high_quality = df[(df['年龄'] > 30) & (df['战力值'] > 85)] # 2. 只要复仇者阵营或者死侍 team_filter = df[(df['阵营'] == '复仇者') | (df['姓名'] == '死侍')]
C. 成员过滤 (isin)
如果你有一张“心动名单”,想看看他们在不在:
# 看看蜘蛛侠和灭霸在不在 fav_list = ['蜘蛛侠', '灭霸'] in_list = df[df['姓名'].isin(fav_list)]
3. 数据排序:谁是相亲角的一哥?
排序能让你一眼看出谁最老、谁最能打。
A. 单列排序
按年龄从小到大排列(看看谁是小鲜肉):
# ascending=True 是升序(默认),False 是降序 youngest = df.sort_values(by='年龄', ascending=True)
B. 多列排序(重点!)
如果我们想先按“阵营”排,同一个阵营里的再按“战力值”从高到低排:
# 阵营升序,战力值降序 # 就像先分部门,部门内部再按年终奖排序 sorted_df = df.sort_values(by=['阵营', '战力值'], ascending=[True, False])
4. Groupby 分组汇总:大数据相亲报告
这是 Pandas 的灵魂。它可以把数据按某列“切开”,然后对每一块进行计算。
A. 基础分组汇总
我想看看不同阵营的平均年龄和平均战力:
# 按阵营分组,计算平均值
report = df.groupby('阵营').mean(numeric_only=True)
B. 多指标汇总 (agg)
如果你想在一个表里看到:每个阵营有多少人、战力最高是多少、年龄平均是多少。
# agg 函数可以让你“点菜”
summary = df.groupby('阵营').agg({
'姓名': 'count', # 人数
'战力值': 'max', # 最高战力
'年龄': 'mean' # 平均年龄
}).rename(columns={'姓名': '人数'}) # 改个名字好听点
C. 多列分组
先按“性别”分,再按“阵营”分:
# 看看不同性别在不同阵营的分布情况 multi_group = df.groupby(['性别', '阵营'])['战力值'].mean()
总结:你的“避坑”锦囊
| 场景 | 核心代码示例 | 备注 |
|---|---|---|
| 多条件筛选 | df[(条件A) & (条件B)] | 别忘了括弧 ()! |
| 模糊匹配 | df[df['姓名'].str.contains('侠')] | 寻找所有名字带“侠”的人 |
| 多重排序 | df.sort_values(['列1', '列2'], ascending=[T, F]) | 数组长度要对应 |
| 分组大招 | df.groupby('列').agg(['mean', 'max']) | agg 是最高级用法 |
现在你已经是“数据相亲角”的顶级红娘了。不管是想找战斗力爆表的灭霸,还是想找年轻有为的蜘蛛侠,只要代码敲得快,没有英雄找不着!你想试试对这份名单做点什么奇葩的筛选吗?
第5节 多表合并
想必你已经受够了在 Excel 里疯狂按 Ctrl+C/V,或者面对那个动不动就 #N/A 的 VLOOKUP 报错想砸电脑了吧?
欢迎来到 Pandas 的世界。在这里,我们管“表合并”叫撩妹/撩汉指南。只要逻辑通,没有合不上的表。
1. Merge:精准匹配(真正的 VLOOKUP 替代者)
merge 就像是相亲。你必须指定一个或多个“共同话题”(Key),只有对上了,两张表才能坐到一张桌子上。
情况 A:基础款(1对1 匹配)
这是最像 VLOOKUP 的情况。比如一张是“前任名单”,一张是“前任渣男/女语录”。
import pandas as pd
# 表1:前任基本信息
ex_list = pd.DataFrame({
'姓名': ['张三', '李四', '王五'],
'恋爱时长': ['3个月', '2年', '5天']
})
# 表2:分手理由(语录)
excuses = pd.DataFrame({
'姓名': ['张三', '李四', '王五'],
'经典语录': ['你太好了我配不上你', '我妈不让', '我当时喝多了']
})
# 自动化实现 VLOOKUP
# how='left' 保证左表(前任表)的人都在,右表查不到的就填 NaN
result = pd.merge(ex_list, excuses, on='姓名', how='left')
print(result)
情况 B:左右不平衡(Left/Right/Inner/Outer Join)
这是 Excel 用户最头疼的逻辑,但 Pandas 搞得清清楚楚:
Left Join (左连接): 闺蜜聚会。哪怕你男朋友没来(右表没数据),你也得占个座,旁边空着(NaN)。
Inner Join (内连接): 只有双向奔赴的爱情才配出现在结果里。
Outer Join (全连接): 前任现任大乱斗。不管对没对上,通通拉进来。
# 假设王五在理由表里失踪了,而理由表里多了一个“赵六” result = pd.merge(ex_list, excuses, on='姓名', how='outer') # 结果:王五语录是空,赵六恋爱时长是空,但大家都整整齐齐在表里
情况 C:列名对不上(left_on / right_on)
如果你的左表叫“姓名”,右表叫“犯罪嫌疑人”,怎么办?
result = pd.merge(ex_list, excuses, left_on='姓名', right_on='犯罪嫌疑人')
2. Concat:简单粗暴的“堆叠”
如果说 merge 是相亲,那 concat 就是叠罗汉或者排排坐。它不看内容,只看位置。
情况 D:纵向堆叠(Axis=0)
比如你把上半年的开销存了一个表,下半年的存了一个表,现在要把它们接起来。
jan_bills = pd.DataFrame({'项目': ['奶茶', '植发'], '金额': [100, 5000]})
july_bills = pd.DataFrame({'项目': ['火锅', '买药'], '金额': [300, 200]})
# 咔嚓一下,拼成一整年
annual_bills = pd.concat([jan_bills, july_bills], axis=0, ignore_index=True)
print("这一年你一共经历了:
", annual_bills)
情况 E:横向硬拼(Axis=1)
这就比较危险了。它是直接把两张表左右贴在一起。如果行数对不上,那简直是灾难。
# 想象一下:左边是人名,右边是随机抽取的监狱编号
names = pd.DataFrame({'人名': ['小明', '小红']})
ids = pd.DataFrame({'编号': ['9527', '89757']})
prison_record = pd.concat([names, ids], axis=1)
3. 各种情况的“防坑”终极总结表
| 需求场景 | 推荐方法 | 搞笑理解 |
|---|---|---|
| 像 Excel 的 VLOOKUP | pd.merge(left, right, on='ID', how='left') | 按照工号查工资,没工号的工资领空气。 |
| 合并两个月的账单 | pd.concat([m1, m2]) | 既然都是账单,那就一并堆在墙角。 |
| 列名不一样但内容一样 | pd.merge(..., left_on='A', right_on='B') | 哪怕你叫“大黄”,它叫“狗狗”,只要是同一只就行。 |
| 只想保留两表重合的部分 | pd.merge(..., how='inner') | 只有双方都承认的关系才叫恋爱。 |
| 只要见过面的都记录下来 | pd.merge(..., how='outer') | 渣男鱼塘管理,宁可错杀,不可放过。 |
数据类型坑:合并前一定要确认 on 的那一列类型一致。如果左边是数字 123,右边是字符串 "123",Pandas 会觉得它们是陌生人,然后给你一堆 NaN。
去重:如果右表有重复值,merge 出来的行数会爆炸(笛卡尔积)。合并前建议先给右表去重:df.drop_duplicates('ID')。
现在,你可以优雅地关掉 Excel,在代码里写下:
df_final = pd.merge(my_life, dream, on='effort', how='inner')
祝你的 effort 足够多,早日 merge 到 dream!
💎 动手实战
太棒了!要把散落在各个部门、各个表格里的“私房钱”(销售数据)一键抓回来,这绝对是财务和数据分析师的“脱发救星”。
在 Python 的世界里,处理这种事儿基本就是 Pandas 的主场。我们可以把这个过程想象成“各路诸侯进京面圣”,不管他们怎么来的,最后都得整整齐齐地码在你的报表里。
🛠️ 准备工作:各部门的“烂摊子”
假设你有三个部门的 Excel 文件:研发部.xlsx、市场部.xlsx 和 销售部.xlsx。
它们可能长这样:
研发部:只卖出去了几台“永动机原型机”。
市场部:卖了一堆“空气净化器”。
销售部:疯狂推销“防脱发洗发水”。
情况一:纵向硬刚(Concat)
场景: 大家的表格列名都一样,只是人不同。这就是最简单的“排排坐”。
import pandas as pd
import glob
# 1. 模拟抓取所有部门的Excel文件(假设都在当前文件夹)
files = ['研发部.xlsx', '市场部.xlsx', '销售部.xlsx']
# 2. 这里的逻辑是:把所有Excel读进来,塞进一个列表里
# 就像把各部门的员工拉进一个群聊
all_data = []
for file in files:
df = pd.read_excel(file)
# 给他们贴个标签,免得以后分不清谁是谁
df['所属部门'] = file.replace('.xlsx', '')
all_data.append(df)
# 3. 暴力合并!ignore_index=True 是为了防止索引打架
# 就像把三叠扑克牌摞在一起,重新数数
combined_report = pd.concat(all_data, ignore_index=True)
print("--- 汇报老板:全军集结完毕 ---")
print(combined_report.head())
情况二:横向勾兑(Merge / Join)
场景: 你有一份“员工名单”,还有一份“提成系数表”。你需要根据“员工ID”把提成算出来。
比喻: 就像是“相亲”,只有两边的 ID(身份证号)对上了,这门亲事(合并)才算成。
# 销售数据表
df_sales = pd.DataFrame({
'员工姓名': ['大壮', '翠花', '小王'],
'销售额': [50000, 80000, 20] # 小王在摸鱼
})
# 提成等级表
df_bonus = pd.DataFrame({
'员工姓名': ['大壮', '翠花', '小王', '老李'],
'提成比例': [0.1, 0.15, 0.01, 0.2]
})
# 使用 merge 进行“精准相亲”
# how='left' 表示以销售表为主,哪怕老李没卖货,我们也不管他
final_table = pd.merge(df_sales, df_bonus, on='员工姓名', how='left')
# 顺手把奖金算了
final_table['奖金'] = final_table['销售额'] * final_table['提成比例']
print("--- 奖金算好了,小王看后想离职 ---")
print(final_table)
情况三:乱世枭雄(处理列名不统一)
场景: 研发部叫“Product”,销售部叫“商品名称”。Pandas 表示:只要你告诉我它们是一个东西,我也能合!
df_a = pd.DataFrame({'Product': ['洗发水'], 'Price': [99]})
df_b = pd.DataFrame({'商品名称': ['洗发水'], '销量': [100]})
# 强制匹配:左表的 Product 对应 右表的 商品名称
weird_merge = pd.merge(df_a, df_b, left_on='Product', right_on='商品名称')
print("--- 跨语种交流成功 ---")
print(weird_merge)
情况四:终极杀招——批量自动化生成报表
场景: 文件夹里有 100 个 Excel,你不想一个一个写名字。
import os
# 自动化获取该目录下所有xlsx文件
path = './各部门数据/'
all_files = [f for f in os.listdir(path) if f.endswith('.xlsx')]
# 这一行代码就能搞定所有读取合并(列表推导式,优雅!)
df_total = pd.concat([pd.read_excel(os.path.join(path, f)) for f in all_files])
# 最后一键生成汇总报表,甚至可以按部门求和
summary = df_total.groupby('部门')['销售额'].sum().reset_index()
# 导出给老板,从此走上人生巅峰
summary.to_excel('2023年度躺平汇总报表.xlsx', index=False)
print("--- 叮!报表已发送,可以下班了 ---")
索引冲突:合并时如果不加 ignore_index=True,你的行索引可能会出现好几个“0”,电脑会像遇到鬼打墙一样不知所措。
数据类型坑:如果研发部的 ID 是数字 123,销售部的 ID 是字符串 '123',merge 的时候它们会像异极磁铁一样死活碰不到一起。记得先用 astype(str) 统一口径。
空值警告:合并后如果出现 NaN,说明有人“落单”了(比如有销售额但没提成比例),记得用 .fillna(0) 帮他们把漏洞补上。
有了这几招,不管公司有多少个部门,只要他们还用 Excel,你就是公司最不可或缺的“表哥/表姐”!