☰
大数据可视化薪酬报告:从数据清洗到行业分位值对标实践
2026/10/21 4:42:37 网站建设 项目流程

2023年做薪酬分析的时候,最头疼的不是算数,而是怎么把一大堆混杂的数据讲清楚。老板想看的是“我们公司跟市场比,到底处于什么位置”,部门负责人想看的是“我手下的人薪资有没有跑偏”,团队里的小伙伴关心的是“今年调薪之后,我处于什么档位”。一份报告要同时满足这么多需求,光靠Excel表格堆数字肯定不行。我这边整理了自己做“大数据可视化薪资报告”的一段完整过程,从数据清洗到图表落地,把踩过的坑和验证过的方法都摊开来说。

1. 拆解“薪资报告可视化”的核心思路

1.1 先搞清楚报告到底给谁看

做薪酬可视化报告,第一步不是打开绘图库,而是先回答三个问题:给谁看、看什么、看完要做什么决定。给高管看的版本,核心是公司整体薪酬竞争力、人工效能、预算执行情况;给业务负责人看的版本,关注的是各序列、各职级的薪酬分布是否合理,关键岗位有没有倒挂;给薪酬HR自己用的版本,则要细到每一个人、每一个岗位,重点是校验调薪名单和预算分配。

这三个层次需求不同,数据筛选和图表选择也完全不一样。很多人在一开始就拿着全字段明细表去画图,结果图做了一大堆,领导一眼就问“那你能直接告诉我,研发序列中级工程师的P50跟市场P50差了几个点吗?”这时候才发现,没有一个图是为这个决策角度设计的。

我的习惯是给报告设计一个“金字塔结构”:顶层一个核心看板,放最关键的4到6个指标;中层是各序列对比、各职级分位值表;底层是明细附录。这样做的好处是,无论是高管还是执行人,都能快速找到自己关心那一层,不需要从头翻到尾。

1.2 找对数据的“行业标准”参照系

标题里“行业标准”这四个字,指的是两个维度:一个维度是薪酬分位值的统计口径,另一个维度是市场数据的对标基准。内部薪资数据不直接拿去跟市场比,得先做口径统一和职位映射。

实操中有一个高频错误:把公司内部岗位名称直接拿去查市场的岗位薪资。比如公司内部叫“产品运营专员”,市场上对应的是“产品运营”“内容运营”“用户运营”,这三者薪资范围差别不小,如果映射错,你的P50对比结果就是错的。正确的做法是先建立“内部岗位—市场通用岗位—职级—薪资等级”的映射表,然后再逐一对标。

分位值的概念也要说清楚。P50是中间位,意思是有50%的人薪资低于这个值;P75是高分位,通常代表市场中较有竞争力的水平。做报告时,一般会把P10、P25、P50、P75、P90都计算出来,才能比较全面地了解分布形态。只看平均值是非常容易误导的,因为极端高薪或大批新人入职都会把平均数拉得很难看。

提示:薪酬报告中“行业标准”不是指某一套官方发布的数据,而是你所在行业、所在城市、相近规模企业的市场分位值组合。报告里最好标注清楚对标的是哪个市场、什么时间、覆盖哪些岗位,这才算得上标准。

1.3 为“大数据”设置合理的数据边界

很多中小企业做薪酬分析,总觉得数据越多越好,恨不得把近十年的记录全导出来算一遍。这里面有两个隐患:一是数据量太大但质量参差,反而拖慢计算速度;二是不同时期的业务结构、人员构成差异很大,混在一起算出来的结论,参考价值很低。

我给自己的项目定了几条筛选规则:

  • 时间范围:只取2023年全年平均薪资,不做月度环比变化,因为月度变动受绩效、调薪时点影响比较大;
  • 人员范围:剔除当年新入职不满三个月、已经离职至少一个季度的员工记录;
  • 字段范围:收入项统一包含基本工资、岗位津贴、绩效工资(取年度均值),但不包含一次性奖金、年终奖、股票期权这类长期激励;
  • 职级范围:同一职级内部再做序列拆分,比如“工程师P7”和“产品经理P7”,职级相同但市场价位完全不同,不能混在一起看。

做完这层筛选之后,剩下的记录才是真正参与计算的有效样本。如果你发现有效的样本量小于30个,那么这个岗位级别单独拿出来算分位值就没什么统计意义了,更好的做法是并入上一职级或者相近岗位组合并计算。

2. 数据清洗与统计口径的统一准备

2.1 数据字段应该长什么样

做好了筛选规则,接下来要处理的是字段结构。做薪资可视化报告之前,我把数据整理成了统一的“一行为一个员工年度薪资记录”的格式。字段包含:员工编号、部门、序列、岗位名称、岗位映射后名称、职级、薪资等级、月度基本工资、月度岗位津贴、年度绩效均值、年度总收入、折算月收入、入离职日期。

这里特别提一下折算月收入。绩效薪资的发放时点在不同公司差异非常大,有的按季度发,有的按半年发,还有的是年底统一算。为了能跟市场数据做同位对比,我统一采用“过去12个月现金性收入总和 ÷ 12”的口径来折算。这样的好处是受发放节奏影响小,坏处是如果公司绩效政策中途调整过,这个值会有延迟反应。

折算之后,再增加一个字段“数据可信度标记”:如果该员工在统计期内出现过多个月份无绩效数据、或者有多笔补发工资记录,就在这个标记位标注为“存疑”。可视化时不排除这些记录,但会在图表中用不同颜色区分。

2.2 缺失值、异常值和离群值的处理

这是整个流程里最繁琐但也最关键的一步。我遇到过几种情况:

  • 某个部门因为搬迁出现一批临时性补贴,这部分金额很高但下个月就没了,如果直接计入基本收入,会把该序列的P75直接拉高;
  • 高管的股票解禁记录被误导入现金收入,导致P90严重失真;
  • 新入职核心人才的签约奖金被拆到每个月发放,这笔钱可能持续一年,但它属于“一次性补偿”,不应该参与到市场分位值对标中。

处理原则是:能追溯原因的,按真实发生性质归类;无法追溯的,标记为“异常值”但不在主分析图中展示。用箱线图能很直观地发现离群值,把中位数上下四分之一位之外的点点标出来,人工排查一遍。跑完之后,主报告里展示的是剔除“非经常性现金补贴和长期激励”后的稳定现金性收入。

注意:剔除异常值必须留痕。我习惯在报告中加一个附录表,列出被剔除的样本编号、剔除原因、剔除前后各分位值的变化幅度。这一步一方面方便复核,另一方面也能让其他同事快速理解数据差异的来源,避免下次重新跑一遍时对不上数。

2.3 统一职级序列是可视化的地基

公司内部职级系统升级过的话,很容易出现新旧职级混用的情况。做报告前需要把历史职级映射到最新职级体系。映射规则要根据岗位价值评估结果建立,不能拍脑袋让HR一个个手动扒。

这里建议建立一张“职级映射对照表”,维护好“序列—职级—职级层级—层级范围”四列关系。举例来说,技术序列从T1到T10,T1到T3是初级,T4到T5是中级,T6到T7是高级,T8到T9是资深专家,T10是架构师。管理和专业序列的划分方式完全不同,如果混在同一套表格里看“部门薪资趋势”,就会严重失真。

做可视化时,我会先按序列分一次组,再在每个序列内部按职级排序。因为不同序列之间的薪资数量级差别很大,比如研发序列P50可能比职能序列P50高出50%以上,放在同一张柱状图里,职能序列那根柱子就只能看到一条线。分面图(Facet)在这个场景下比堆叠的柱状图好用很多,既保留差异又不会互相压缩。

3. 分位值计算与核心图表实现

3.1 用数据透视表快速计算各职级分位值

计算分位值时,有人习惯直接用Excel的PERCENTILE函数或者数据框工具的百分位函数。先别急着上代码,先把透视表拉出来跑一遍,这样做能更清楚地控制维度。

拿我常用的透视过程举例:

  • 行标签放“序列”和“职级”;
  • 值区域放“折算月收入”;
  • 值显示方式选择“按某一字段汇总”不好使,需要直接用函数计算。

如果是在传统表格工具里,手动添加计算字段,分别求P10、P25、P50、P75、P90。求P10时切忌直接套用百分比格式后再排序取头,因为单位不同会干扰排序视线。正确的方法是在计算列中先确认该职级总人数,再乘以10%得到位置,然后通过升降序取对应值。

在脚本工具中,这个步骤会显得更简洁:

import pandas as pd salary_data = pd.read_csv("salary_2023_clean.csv", encoding="utf-8-sig") # 确保折算月收入为数值类型 salary_data["monthly_pay"] = pd.to_numeric(salary_data["monthly_pay"], errors="coerce") # 按序列和职级分组,计算分位值 pivoted = salary_data.groupby(["job_family", "grade"])["monthly_pay"].quantile([0.1, 0.25, 0.5, 0.75, 0.9]).unstack() # 重命名列 pivoted.columns = ["P10", "P25", "P50", "P75", "P90"] pivoted = pivoted.reset_index()

这段代码的要点在于:先做分组,再一次性对一个数值列求多个分位值,会生成很容易直接对接后续可视化的数据框。如果数据量超过十万行,用脚本工具的groupby仍然很快,不会出现表格工具卡死的情况。

小提示:分位值表格在报告中不要只给一列P50,最理想的展示是“P10-P90区间”,每一行职级显示一个薪资范围条。这样既看得出集中趋势,也看得出离散程度。

3.2 用代码快速画“薪酬带宽图”和“内部散点图”

薪酬带宽图是薪资报告里最常用、也最好讲清楚的图。横轴是职级,纵轴是月收入,每一档职级显示一条竖立的箱线或柱状范围。箱线图和柱状范围的区别在于:箱线图展示的是内部数据分布形态,柱状范围展示的是职级薪资带宽的政策范围。

标准做法是两者结合:底层用淡色透明柱状图画政策带宽,上层用箱线图画实际薪资分布。这样做能直观看到“实际薪资分布是否跑出了政策带宽”以及“分布在带宽中的上下位置”。超出带宽的数据点单独标出来,用对比色显示,这些点很可能就是调薪时重点关注的异常值。

import matplotlib.pyplot as plt # 使用上面生成的pivoted数据 fig, ax = plt.subplots(figsize=(14, 8)) families = pivoted["job_family"].unique() colors = ["#6C8EBF", "#D18F9C", "#7FC8A9", "#E0B05C"] for i, family in enumerate(families): subset = pivoted[pivoted["job_family"] == family].sort_values("grade") ax.bar(x=range(len(subset)), height=subset["P75"] - subset["P25"], bottom=subset["P25"], width=0.6, label=family, color=colors[i % 4], alpha=0.6)

上面这段画的是四分位距区间条,相当于把每个职级的P25到P75画成一条粗色柱。如果再加一条中线标记P50,图就会变成“部分柱+中点”的组合,比单纯用箱线图更清楚。

内部薪资公平性还可以用“人员散点图”来查问题。横轴是职级(从低到高排序),纵轴是员工个人折算月工资,再叠加一条该职级P50的折线。如果某个职级出现了大量点在P50线以下或以上集中分布,说明内部存在薪资倒挂或者绝对值偏离。

3.3 报告页面的模块排布方法

做报告排布也是一门学问。我经过几次调整之后,固定了一版相对好用的结构:

  • 首页放一张“总览仪表盘”,包含公司整体与市场P50对标图、各序列人数占比饼图、年度调薪预算测算表;
  • 第二页放分位值明细表,按序列拆分若干个表格;
  • 第三页放内部公平性散点图和带宽超限情况列表;
  • 最后一页放分析结论和行动建议。

这样排布的依据是:读者根据疑问快速定位页码,高层看首页,HRBP看第二页到第三页,调薪执行人员看最后一页。薪资报告可视化不仅仅是为了让数字好看,更是为了把分析结论“嵌入”到决策路径中。

4. 可视化实操:从数据透视到成图全流程

4.1 准备一套可以直接复用的数据预览模板

很多做数据可视化的人会忽略一个环节:原始数据最终的展示格式。分位值计算完成之后,我先输出一版“宽表”,列是各职级、各分位值、人数、平均值,这样人工核对方便。然后再输出一版“长表”,列是职级、分位值类型、数值,这样绘图工具画起来方便。

宽表和长表的切换,本质上就是把列拆到行里,在绘图时用“维度”和“度量”两个角色去控制图表形态。一套数据模板可以反复服务多个汇报场景,这是为什么做数据模板值得花时间的原因。我通常把基础计算表生成到一个工作簿共用工作表,之后的画图全部引用这张表的数据源,避免每画一张图都要重新算一遍。

4.2 可视化全流程的代码段示例

下面这段可以完整跑一遍“原始表 → 透视分位值 → 画图”的流程,采用常见的脚本语言和绘图库。

import pandas as pd import matplotlib.pyplot as plt # 读取清洗后的数据 df = pd.read_csv("salary_2023_clean.csv", encoding="utf-8-sig") # 剔除用于对标的一次性补贴字段 df = df[df["income_category"] != "one_time_bonus"] # 分组计算分位值,并保留样本量 perc = df.groupby(["job_family", "grade"])["monthly_pay"] p10 = perc.quantile(0.10) p25 = perc.quantile(0.25) p50 = perc.quantile(0.50) p75 = perc.quantile(0.75) p90 = perc.quantile(0.90) cnt = perc.count() summary = pd.DataFrame({ "P10": p10, "P25": p25, "P50": p50, "P75": p75, "P90": p90, "count": cnt }).reset_index() # 抽样模拟展示前看看结构 print(summary.head(10))

接下来画“分面柱状图”:

fig, axes = plt.subplots(1, 3, figsize=(18, 6), sharey=False) families = summary["job_family"].unique()[:3] for ax, family in zip(axes, families): subset = summary[summary["job_family"] == family].sort_values("grade") ax.errorbar(subset["grade"], subset["P50"], yerr=[subset["P50"] - subset["P25"], subset["P75"] - subset["P50"]], fmt="o", capsize=5, color="#2A5A8C") ax.set_title(f"序列: {family}") ax.set_xlabel("职级") ax.set_ylabel("折算月收入") ax.grid(axis="y", linestyle="--", alpha=0.3) plt.tight_layout() plt.show()

这个图看的是:不同序列、不同职级下薪资中位数的位置以及P25到P75的离散程度。如果某个职级的误差条特别长,说明这一级内部薪资差异很大。这时候就需要进一步去看,是新人老员工的差异,还是同职级里不同岗位导致的价格差。

4.3 图表颜色、字体和标注细节

报告呈现环节,70%的功夫在做减法。我见过不少图表,颜色太多、标签太密、网格线太深,最后谁都没读懂。色彩建议限制在3到4个主色系内,重点数据用一个高亮色,其他数据用弱化色,突出分析结论而不是让观众去猜哪根柱子重要。

字体建议统一,数值保留两位小数,金额单位在图表角落统一标注就行。标题要写清楚“谁、什么时间、什么指标”,比如“2023年各职级P50月收入对比”,而不是光写“薪资对比”。

每张图还要配一个“读图要点”文本框,控制在两到三行,比如“技术序列T4的P50超出市场水平6%,建议暂缓调薪,观察留任风险。”这样才算可视化完成,否则图只是装饰。

5. 行业对标与报告演进的进阶思考

5.1 如何把内部数据与市场基准放在同一框架

我这里说的市场基准,是采购或合作获取的行业薪酬数据库,或者是人力资源咨询公司提供的分位值报告。拿到这类数据后,首要动作不是直接画对标图,而是先做“岗位匹配度校准”。检查内部职位说明书与市场标准职位定义的相似度,匹配度低于一定阈值的岗位,需要删除或者单独标注。

对标图通常采用“内部P50与市场P50差值百分比”来呈现。差值百分比的计算方式是:

(内部P50 - 市场P50) / 市场P50 × 100%

这个值在-10%到10%之间通常可以接受,超过20%说明有薪酬优势或成本风险。可视化呈现时,用水平条形图,左侧是低于市场,右侧是高于市场,一眼就能看出哪些岗位需要重点关注,跟“温度计”的视觉逻辑类似。

5.2 用“职位与薪酬矩阵图”找出调薪重点

矩阵图是一种很实用的分析工具。横轴是岗位的市场紧缺度,纵轴是企业内部薪酬竞争力(对标中位差额),将岗位放入四个象限:

  • 高紧缺 + 高竞争力:保持现状,减少额外激励;
  • 高紧缺 + 低竞争力:加薪或重点激励,防止人员流失;
  • 低紧缺 + 高竞争力:适当控制成本,调整增长速度;
  • 低紧缺 + 低竞争力:可维持,暂缓调薪。

画法上也很简单:散点图,点的大小代表该岗位人数,颜色代表序列。加上两条中线,一句话说明每个象限行动措施。这种图信息密度很高,高管层最喜欢,因为既能看全局又直接给行动依据。

5.3 大语言模型时代的报告自动化

2023年这个节点,我已经开始尝试把重复性的计算报告流程做成半自动工具。步骤是:把清洗后的数据放进标准输入的表格,脚本自动输出分位值表、带宽图、对标图,最后把结论装配进一份标准格式的文档草稿。

人力资源专业的人员不用自己改代码,只需要定期维护映射表和筛选规则。这样每次做季度或年度报告,节省的时间非常可观。要注意的是,自动化流程只负责“标准化呈现”,真正对公司业务的理解和调薪建议还是需要人工判断。工具替代的是劳动力,替代不了判断力。

6. 常见问题与排查心得

6.1 分位值算出来跟感觉不符怎么办

这种情况我遇到过很多次。先说结论,大概率是数据口径或分位值计算函数使用出了问题。检查顺序是:

  • 数据中是否混入了离职员工或实习生的记录;
  • 月度收入是否把13薪、年终奖都算进去了;
  • 职级字段是否含旧版职级而未做映射;
  • 分组键是否有空值,空值会被分开统计;
  • 百分位函数是否被当成“排位百分比”来用。

其中最容易忽视的是空值分组。如果某个员工没有填入职级,很多工具会默认把这一组归为一个单独的分组,这样算出来的“未知职级”分位值会混在报告里。排查时先做一份分组缺失值检查,把所有关键维度空值列出来。

6.2 图表中离职高薪员工影响了整体怎么办

除了剔除异常值之外,更好的处理方式是增加两个视角:一个视角是“在职人员全口径”,另一个视角是“稳定在职人员口径”。两个口径算出的分位值并列展示,让观众自己看到差异。这样既符合客观事实,也避免“为了好看而刻意删数据”的嫌疑。

实践中,稳定在职人员的定义是:当年全年在职、且月出勤天数满足常规标准的员工。这种人数的数据更干净,但覆盖的岗位范围窄一点。两个口径互为补充,报告说服力更强。

6.3 报告做完以后没人仔细看怎么办

最常见的反馈是“数字是对的,但不知道跟我们有啥关系”。所以报告页首的“核心结论”一定要用业务语言写,少用HR术语。比如不写“P50超过市场水平”,而是写“技术序列中位薪资超出市场约12%,这部分岗位不需要再跟市场抢人,可以把资源倾斜到紧缺的算法岗位”。数字变成了资源和行动的指引,报告才有了价值。

我自己的习惯是最后再做一次“读图演练”:请不同角色的同事只看图表,不看文字,复述他们读到的结论。如果5分钟之内说不清楚图和文字的核心信息,说明这页图表还需要改。

6.4 常见问题速查表

问题现象可能原因排查方式解决方案
分位值偏高或偏低异常混入了一次性奖金查看收入明细字段排除一次性收入后重算
同职级薪资差距过大新旧职级混用检查职级映射表统一映射后再分组
图表中大量点超出带宽数据中包括了离职前后补发核对入离职字段剔除不在职月份记录
对标市场值差异巨大内部岗位和市场映射不准抽查10个岗位的匹配度重建岗位映射表
透视表求和而非求分位值值字段设置错误检查计算函数改为数值型分位函数

7. 我在实操中保留的经验与建议

每一次做薪资可视化报告,我最大的体会就是:不要在数据清理上省时间。数据干净程度决定了整个报告的分析上限。就算画图工具再熟练,脏数据里的噪声也会把真实信号淹没掉。

另外,报告不是一次性交付物。按季度更新时,只需要维护好映射表和分位值公式,新增员工记录会自动进入计算流程。前期的数据模板建设看着慢,但三个月后就能节约不少时间。

如果只能给一条建议,那就是把“分位值”和“带宽”这两个概念彻底吃透。掌握了它们,你才真正具备用数据讲清楚薪资故事的能力。裸看全公司平均薪资,或者只看一个中位数,都很难支撑起2023年这个复杂人才市场的决策需求。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询