目录
一. 引言
- 背景介绍:该数据为一家互联网科技公司的职工信息表(数据共14999条),新入职的人力资源负责人想对该份数据进行探索性分析,以便快速了解公司员工情况。
- Python数据挖掘的价值:解释Python在数据挖掘中的优势,如易用性、丰富的库(pandas, matplotlib等),以及如何用于人力资源决策支持。
- 主要目标:本文旨在通过Python对人力资源数据进行深入分析,从两个主要维度展开研究:
- 从人力资源结构角度:
- 人员岗位分布
- 管理人员比例
- 教育情况分布
- 人员年龄结构
- 从人力资源运作角度:
- 员工离职率
- 内部变动率
相关资料参考:
关键指标定义:
二. 数据加载及预处理
1.引入库
import pandas as pd
from matplotlib import pyplot as plt
#忽略警告提醒
import warnings
warnings.filterwarnings('ignore')
#中文友好显示
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 设置字体
mpl.rcParams['axes.unicode_minus'] = False # 防止出现负号乱码
2.读取数据
data=pd.read_excel('./HR_comma_sep.xlsx',sheet_name='数据集')
#查看数据前几行
data.head()
示例输出结果:
#查看数据情况
data.info()
示例输出结果:
## 计算描述性统计
data.describle
示例输出结果:
3.数据清洗
#判断员工是否变动部门,返回结果是布尔值
data['是否变动部门']=data['现就职部门']==data['原就职部门']
#将布尔值转换为中文
data['是否变动部门']=data['是否变动部门'].apply(lambda x:'否' if x else '是')
第一步:比较两列是否相同
-
逻辑:
-
比较
现就职部门
和原就职部门
是否相同。 -
如果相同,返回
True
(表示未变动部门);如果不同,返回False
(表示变动部门)。
-
-
结果:
-
新列
是否变动部门
的值是布尔型(True
/False
)。
-
第二步:将布尔值转换为中文
-
逻辑:
-
使用
apply()
方法对是否变动部门
列中的每个值进行转换。 -
lambda x: '否' if x else '是'
表示:-
如果
x
是True
(未变动),返回'否'
。 -
如果
x
是False
(变动),返回'是'
。
-
-
-
结果:
-
新列
是否变动部门
的值变为中文'是'
(变动)或'否'
(未变动)。
-
示例输出结果:
筛选出在职员工的数据:
data_zaizhi=data[data['是否离职']=='在职']
#查看数据维度
data_zaizhi.shape
输出结果:
(11292, 9)
第一步:筛选在职员工
-
逻辑:
-
data['是否离职'] == '在职'
:对是否离职
列进行条件判断,返回一个布尔值(True
/False
)的 Series。-
如果值为
'在职'
,对应行为True
(保留该行)。 -
如果值为其他(如
'离职'
),对应行为False
(排除该行)。
-
-
data[布尔Series]
:根据布尔值筛选数据,仅保留True
的行。
-
第二步:查看数据维度
-
作用:
-
shape
是 Pandas DataFrame 的属性,返回一个元组(行数, 列数)
。
-
同理筛选出离职员工的数据:
data_lizhi=data[data['是否离职']=='离职']
data_lizhi.shape
输出结果:
(3707, 9)
三. 数据分析与挖掘
1.人力资源结构角度
分析1:人员岗位分布
统计每个部门的在职员工人数及占比,并按人数从高到低排序
#按部门分组统计人数
df1=data_zaizhi.groupby(by='现就职部门',as_index=False)['工号'].count()
# 重命名列
df1.columns=['现就职部门','人数']
#3. 计算占比
df1['占比']=df1['人数']/df1['人数'].sum()
#按人数降序排序
df1.sort_values(by='人数',ascending=False,inplace=True)
df1.head()
输出结果示例:
分析情况:
1. 按部门分组统计人数
groupby('现就职部门')
:按 现就职部门
列分组。
as_index=False
:让分组列 现就职部门
保留为普通列(而非索引)。
['工号'].count()
:统计每个部门的 工号
数量(即人数)。
2.按人数降序排序
inplace=True
:直接修改 df1
,不创建新对象。
ascending=False
:降序排列(从高到低)。
by='人数'
:按 人数
列排序。
结果可视化:
使用 Matplotlib 绘制了一个 双Y轴组合图表,左侧Y轴显示各部门的 在职人数(柱状图),右侧Y轴显示各部门的 人数占比(折线图),并在折线图上添加了数据标签。
plt.figure(figsize=(20,8),dpi=80)#设置画布
#绘制柱状图(左侧Y轴)
plt.bar(df1['现就职部门'],df1['人数'])
plt.xlabel('现就职部门')
plt.ylabel('人数')
plt.title('人员岗位分布图')
#创建次坐标轴
plt.twinx()
#绘制折线图(右侧Y轴):
plt.plot(df1['现就职部门'],df1['占比'],'ro-')#设置折线颜色
plt.ylabel('人数占比')
#添加数据标签
for x,y in zip(df1['现就职部门'],df1['占比']):
plt.text(x,y,'%.2f%%' %(y*100),ha='center',va='bottom',fontsize=16)
plt.show()
1. 设置画布
-
figsize=(20, 8)
:设置画布大小为宽20英寸、高8英寸。 -
dpi=80
:调整分辨率(像素密度),确保图像清晰。
2. 绘制柱状图(左侧Y轴)
-
功能:
-
plt.bar()
:绘制柱状图,X轴为部门名称,Y轴为人数。 -
xlabel
/ylabel
/title
:设置坐标轴标签和标题。
-
3. 创建次坐标轴(右侧Y轴)
-
作用:
新增一个Y轴(右侧),与左侧Y轴共享X轴,用于绘制占比数据。
4. 绘制折线图(右侧Y轴)
-
参数说明:
-
'ro-'
:红色(r
)、圆点标记(o
)、实线(-
)。 -
ylabel
:设置右侧Y轴标签。
-
5. 添加数据标签
-
遍历每个部门,在折线图的数据点上添加占比标签(如
25.00%
)。 -
ha='center'
:水平居中显示。 -
va='bottom'
:垂直方向位于数据点上方。 -
fontsize=16:设置字体大小。
6. 显示图表
输出结果:
结论:公司的在职人员中销售部门人数最多,占比26.48%;其次是技术部门,占比20.58%。
-
分析2:管理人员比例
统计不同级别(如职级、岗位级别)的在职员工人数,并按人数从高到低排序
df2=data_zaizhi.groupby(by='级别',as_index=False)['工号'].count() df2.columns=['级别','人数'] df2.sort_values(by='人数',ascending=False,inplace=True) df2
输出结果示例:
1. 按部门分组统计人数
groupby('现就职部门')
:按现就职部门
列分组。as_index=False
:让分组列现就职部门
保留为普通列(而非索引)。['工号'].count()
:统计每个部门的工号
数量(即人数)。2.按人数降序排序
inplace=True
:直接修改df1
,不创建新对象。ascending=False
:降序排列(从高到低)。by='人数'
:按人数
列排序。结果可视化:
使用 Matplotlib 绘制了一个 饼图,用于直观展示不同级别(如职级)的管理人员在整体中的比例分布,并突出显示某一个级别(通过偏移效果)。
#设置画布大小 plt.figure(figsize=(6,6),dpi=80) #保证长宽相等 plt.axis('equal') #绘制饼图 plt.pie(df2['人数'],label=df2['级别'],autopct='%.2f%%',explode=[0,0,0,0,0.1]) plt.title('管理人员比例分布图') plt.show()
分析情况:
1. 设置画布
-
figsize=(6, 6)
:创建6英寸×6英寸的正方形画布。 -
dpi=80
:设置分辨率(像素密度)。 -
axis('equal')
:确保饼图是正圆形(而非椭圆形)。
2. 绘制饼图
-
参数说明:
-
df2['人数']
:饼图各扇区的数值(人数)。 -
labels
:对应每个扇区的标签(级别名称)。 -
autopct
:自动标注百分比格式(如25.00%
)。 -
explode
:控制扇区偏移(0
表示不偏移,0.1
表示第5个扇区向外偏移10%半径)。
-
输出结果示例:
-
结论:
-
1.百度AI中显示,互联网公司中的管理人员比例在10%到15%之间是比较常见的。所以该公司管理层(M1)的人数占比为9.72%,管理人员偏少,可以考虑从基层再提拔部分管理人员上来。
-
2.根据LinkedIn 2023科技行业报告,理想金字塔比例为P1 : P2 : P3 : P4 = 15% : 30% : 40% : 15%。
-
P1严重不足(10.07% vs 15%):人才储备断层(建议将P1占比提升至15%(校招计划));
-
P2人员占比合理(29.60% vs 30%);
-
P3占比合理(40.21%≈40%):主力层稳定;
-
P4占比偏低(10.41% vs 15%):技术深度不足(内部晋升+P5通道建立)。
-
分析3:教育情况分布
统计在职员工的学历分布情况,并按人数从高到低排序
df3=data_zaizhi.groupby(by='学历',as_index=False)['工号'].count() df3.columns=['学历','人数'] df3.sort_values(by='人数',ascending=False,inplace=True) df3
输出结果示例:
-
-
结果可视化:
使用Matplotlib库绘制了一个饼图,用于直观展示在职员工的学历分布情况。
plt.figure(figsize=(6,6),dpi=80) plt.axis('equal')# 保证长宽相等 plt.pie(df3['人数'],labels=df3['学历'],autopct='%.2f%%') plt.title('学历情况分布图') plt.show()
输出结果:
-
结论:公司以本科学历为主,占53.85%; 其次是专科学历,占29.60%; 硕士学历只占了9.61%; 高中学历占比是最低的,占了6.94%.
深度分析:“硕士”和“高中”的岗位分布情况
高中及以下:
筛选出学历为“高中及以下”的员工
data_senoir=data_zaizhi[data_zaizhi['学历']=='高中及以下']
data_senoir.shape
统计高中及以下人群各部门高中及以下学历员工的人数分布,并按人数降序排列。
#数据分组统计
df3_senoir=data_senoir.groupby(by='现就职部门',as_index=False)['工号'].count()
#列名重命名
df3_senoir.columns=['现就职部门','高中及以下学历人数']
#排序处理
df3_senoir.sort_values(by='高中及以下学历人数',ascending=False,inplace=True)
#输出结果
df3_senoir
输出结果示例:
硕士
筛选出学历为“硕士”的员工
data_master=data_zaizhi[data_zaizhi['学历']=='硕士']
data_master.shape
统计每个“现就职部门”中拥有“硕士学历”的员工人数,并按人数从高到低进行排序。
df3_master=data_master.groupby(by='现就职部门',as_index=False)['工号'].count()
df3_master.columns=['现就职部门','硕士学历人数']
df3_master.sort_values(by='硕士学历人数',ascending=False,inplace=True)
df3_master
输出结果示例:
将两个包含不同学历统计信息的数据表(df3_senoir
和 df3_master
)按照部门”进行合并,并对合并后产生的缺失值进行处理,最后确保数据类型的一致性。
# 拼接数据
df3_1=pd.merge(df3_senoir,df3_master,on='现就职部门',how='outer')
df3_1.fillna(0,inplace=True)
df3_1['高中及以下学历人数']=df3_1['高中及以下学历人数'].astype(int)
df3_1
输出结果示例:
df3_1.plot.bar(figsize=(20,8),stacked=True)#启用堆叠模式
#自定义 X 轴的刻度标签。
plt.xticks(range(len(df3_1)),df3_1['现就职部门'])
plt.xlabel('现就职部门')
plt.ylabel('学历人数')
plt.title('高中及以下VS硕士 各学历人员岗位分布图')
plt.show()
len(df3_1)
返回df3_1
表的行数,也就是部门的数量。range(...)
会生成一个从 0 开始到行数-1
的整数序列,例如[0, 1, 2, 3, ...]
。- 这个序列告诉 Matplotlib,应该在 X 轴的 0, 1, 2, 3… 这些位置上放置刻度标签。这正好与 Pandas 默认的行索引位置对齐。
df3_1['现就职部门']:
这是第二个参数,用于设置刻度的标签。
输出结果:
结论:硕士学历分布在各个岗位,并没有对某一岗位有特殊偏好; 高中学历,主要分布在销售、生产、运营和市场,这些岗位对于学历相对要求较低的岗位。
继续深入挖掘:各个部门离职率(交叉组合)
-
分析4:人员年龄结构
统计原始数据
data_zaizhi
中每个年龄对应的员工人数,并按照年龄从小到大进行排序df4=data_zaizhi.groupby(by='年龄',as_index=False)['工号'].count() df4.columns=['年龄','人数'] df4.sort_values(by='年龄',ascending=True,inplace=True) df4
输出结果示例:
-
结果可视化:
plt.figure(figsize=(20,8),dpi=80) plt.plot(df4['年龄'],df4['人数'],'o-') plt.xlabel('年龄') plt.ylabel('人数') plt.title('人员年龄结构分布图') for x,y in zip(df4['年龄'],df4['人数']): plt.text(x,y,y,ha='center',va='bottom',fontsize=16) plt.xticks(range(20,36)) plt.show()
输出结果:
统计24-25岁人数占比:
sum((data_zaizhi['年龄']==24)|(data_zaizhi['年龄']==25))/len(data_zaizhi)
输出结果:0.5325008855827135
统计大于30岁人数占比:
sum(data_zaizhi['年龄']>=30)/len(data_zaizhi)
输出结果:0.03808005667729366
结论:公司人员的年龄主要集中在24-25岁,占比高达53.25%。整体偏年轻化。30+以上的人员,较少,占比为3.8%。
深入挖掘:30+的员工主要是集中在什么岗位(交叉组合)
df4_30=data_zaizhi[data_zaizhi['年龄']>=30] df4_30
输出结果示例:
df4_1=df4_30.groupby(by='现就职部门',as_index=False)['工号'].count() df4_1.columns=['现就职部门','人数'] df4_1['占比']=df4_1['人数']/df4_1['人数'].sum() df4_1.sort_values(by='人数',ascending=False,inplace=True) df4_1
输出结果:
结果可视化:
plt.figure(figsize=(20,8),dpi=80) #绘制柱状图(左侧Y轴) plt.bar(df4_1['现就职部门'],df4_1['人数']) plt.xlabel('现就职部门') plt.ylabel('人数') plt.title('30+人员岗位分布图') #创建次坐标轴 plt.twinx() #绘制折线图(右侧Y轴): plt.plot(df4_1['现就职部门'],df4_1['占比'],'ro-') plt.ylabel('占比') #添加数据标签 for x,y in zip(df4_1['现就职部门'],df4_1['占比']): plt.text(x,y,'%.2f%%' %(y*100),ha='center',va='bottom',fontsize=16) plt.show()
输出结果:
结论:30+人员岗位分布在各个岗位,无明显偏好;其中销售部门占比最高,占28.14%。