看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gr99123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在日常数据处理中,我们经常会从业务系统(如CRM、ERP)中导出一些结构“不太友好”的数据。这些数据可能更便于人类阅读,但却不利于用Pandas进行自动化分析。一个典型的场景就是:数据表的列名本身也包含了某种维度信息(比如时间“一月”、“二月”、“三月”)。
在本篇博客中,我们将模拟一个员工KPI目标与实际完成值的场景。原始数据中,每个员工的年度目标与实际完成值被横向排列在不同的月份列下。我们的需求是计算每位员工每个月的KPI完成率。通过这个案例,你将学会如何组合使用 melt
, groupby
和 pivot_table
这三个Pandas核心方法,高效地将“宽表”重塑为“长表”,并进行复杂的聚合计算,最终得到一个清晰的分析结果。
假设我们有以下数据,它记录了三位员工在Q1季度(1-3月)的KPI目标值和实际完成值。
import pandas as pd
from io import StringIO
# 模拟的源数据字符串
data = """
员工姓名,一月目标,一月完成,二月目标,二月完成,三月目标,三月完成
张三,100,95,100,110,100,80
李四,150,140,150,160,150,150
王五,80,90,80,75,80,85
"""
# 读取数据
df = pd.read_csv(StringIO(data))
df
原始数据展示:
员工姓名 一月目标 一月完成 二月目标 二月完成 三月目标 三月完成
0 张三 100 95 100 110 100 80
1 李四 150 140 150 160 150 150
2 王五 90 90 80 75 80 85
我们希望计算每位员工在每个月的KPI完成率(完成率 = 完成值 / 目标值 * 100%),并最终形成一个以员工姓名
为索引,以月份为列,以完成率为值的清晰表格。
期望的结果样式:
员工姓名 一月 二月 三月
张三 95.00% 110.00% 80.00%
李四 93.33% 106.67% 100.00%
王五 100.00% 93.75% 106.25%
面对这个需求,我们可以分步拆解:
melt
函数的情况。我们可以将一月目标
、一月完成
等列“融化”,拆解出月份
和指标
两个新列,并将对应的数值放在值
列中。melt
后得到的复合列名(如一月目标
)中,我们需要提取出纯净的月份
和指标
。这里可以使用字符串分割的方法。pivot_table
可以非常方便地将指标
(目标、完成)展开为列,从而方便我们进行后续计算。完成率 = 完成 / 目标
。整个过程我们将采用流畅的链式调用,一气呵成。
下面是完整的解决代码,我们逐部分进行分析:
# 使用链式方法一次性解决
(
df
# 1. 使用melt将宽表转为长表,标识列为‘员工姓名’
.melt(id_vars='员工姓名',
var_name='月份指标',
value_name='数值')
# 2. 拆分‘月份指标’列:提取月份和指标类型
.assign(
# 提取前两个字符作为月份
月份=lambda x: x['月份指标'].str[:2],
# 提取剩余字符作为指标(目标/完成)
指标=lambda x: x['月份指标'].str[2:]
)
# 3. 删除不再需要的原始复合列
.drop(columns='月份指标')
# 4. 构建透视表,行是员工和月份,列是指标,值是数值
.pivot_table(index=['员工姓名', '月份'],
columns='指标',
values='数值')
.reset_index()
# 5. 计算完成率
.assign(完成率=lambda x: x['完成'] / x['目标'])
# 6. 为了最终呈现,再次构建透视表:员工为行,月份为列,完成率为值
.pivot_table(index='员工姓名',
columns='月份',
values='完成率')
# 7. 将小数格式化为百分比字符串
.map(lambda x: f"{x:.2%}")
)
代码分析:
.melt(id_vars='员工姓名', var_name='月份指标', value_name='数值')
:
id_vars
指定要保留的列(员工姓名
),其他所有列都会被“融化”。一月目标
)会进入新列月份指标
,对应的数值进入新列数值
。.assign(月份=lambda x: ... , 指标=lambda x: ...)
:
月份
和指标
。x['月份指标'].str[:2]
取出前两个汉字(如“一月”),str[2:]
取出后面的部分(如“目标”)。.pivot_table(index=['员工姓名', '月份'], columns='指标', values='数值')
:
员工姓名
和月份
为行索引,以指标
为列,对数值
进行聚合(默认是均值,但这里每个组合只有一个值,所以没问题)。目标
和完成
两列,这为我们计算完成率做好了准备。.assign(完成率=lambda x: x['完成'] / x['目标'])
:
.pivot_table(index='员工姓名', columns='月份', values='完成率')
:
pivot_table
。.map(lambda x: f"{x:.2%}")
:
map
对DataFrame中的每个元素应用函数。f"{x:.2%}"
是一个格式化字符串字面量(f-string),它将小数x
格式化为保留两位小数的百分比(例如,0.95 变为 "95.00%")。运行上述代码,你将得到与“期望结果”完全一致的输出。这个案例完美展示了Pandas链式方法在数据处理流程中的强大与优雅。
(完)
更新时间:2025-09-24 21:57:51 标签:pandas python kpi