该数据集来源于Kaggle竞赛平台,共计14999条样本和10个特征,本案例希望通过分析现有的员工离职数据,建立模型预测有可能离职的员 工。
内容概要
1 数据概览
2 数据预处理
3 数据探索及可视化
3.1 标签探索:员工离职状况概览
3.2 特征探索:员工对公司满意度与是否离职的关系
3.3 特征探索:最新考核评估与是否离职的关系
3.4 特征探索:参加项目数与是否离职的关系
3.5 特征探索:平均每月工作时长与是否离职的关系
3.6 特征探索:工作年限与是否离职的关系
3.7 特征探索:是否发生工作事故与是否离职的关系
3.8 特征探索:五年内是否晋升与是否离职的关系
3.9 特征探索:岗位与是否离职的关系
3.10 特征探索:薪资水平与是否离职的关系
4 特征工程&建立模型
4.1 编码:将文本型变量变为数值型
4.2 提取特征和标签并切分数据集
4.3 初步建模:建立benchmark
4.4 测试数据归一化对模型结果的影响
5 模型调优
1 数据概览
# 导入相应模块和包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Simhei']
plt.rcParams['axes.unicode_minus'] = False
# 导入原始数据
data = pd.read_csv("HR_comma_sep.csv")
data.head()
运行结果

# 简单描述统计(数值型特征)
data.describe().T
运行结果

从简单描述统计结果中可以看出:
员工对公司满意度:范围[0.09,1],中位数为0.64,平均值为0.61
最新考核评估:范围[0.36,1],中位数为0.72,平均值为0.716
项目数:范围[2,7],中位数为4,平均值为3.8
平均每月工作时长:范围[96,310],中位数为200,平均值为201
工作年限:范围[2,10],中位数为3,平均值为3.5 工作中出现
工作事故的占比为14.5%
已经离职的占比为23.8% 在5年内晋升的占比为2.1%
# 简单描述统计(文本型特征)
data.describe(include=['O']).T
运行结果

员工岗位一共有10种,其中人数最多的岗位是销售,一共4140人。
员工薪资水平一共有3个等级,其中最多的是低等水平,一共7316人 。
2 数据预处理
data.isnull().sum()
# 查看重复值
data.duplicated().sum()
# 绘制箱型图,查看异常值状况
plt.figure(figsize=(15,3),dpi=100)
for i in range(5):
plt.subplot(1,5,i+1)
plt.boxplot(data.iloc[:,i])
plt.xlabel(data.columns[i])
plt.xticks([])
运行结果

从箱型图结果中可以看出,除了工作年限之外,其他特征均无异常值。该异常值也反映了该公司基本上以年轻人为主,大部分是工作年限为 4年以内。
3 数据探索及可视化
3.1 标签探索:员工离职状况概览
data["left"].value_counts()
data["left"].value_counts()/data.shape[0]
v1 = data["left"].value_counts()
# 绘制饼图:在职和离职员工占比
plt.figure(figsize=(6,6))
plt.pie(v1 #饼图原始数据
,radius=1 #饼图半径
,autopct="%.2f%%" #自动添加百分比显示,可以采用格式化的方法显示
,labels=["在职","离职"] #为饼图添加标签说明,类似于图例说明
,labeldistance=1.1 #设置各扇形标签(图例)与圆心的距离
,pctdistance=0.8 #设置百分比标签与圆心的距离
,textprops={"fontsize":15} #设置饼图中文本的属性,如字体大小、颜色等
,wedgeprops={"width":0.4} #设置环的宽度
)
运行结果

3.2 特征探索:员工对公司满意度与是否离职的关系
# 绘制直方图和箱型图
import seaborn as sns
plt.figure(figsize=(10,8))
grid = plt.GridSpec(2, 2, wspace=0.2, hspace=0.3) # wspace表示左右子图间距,hspace表示上下子图间距
plt.subplot(grid[0, :])
sns.histplot(data=data, x="satisfaction_level", hue="left",kde=True)
plt.subplot(grid[1, 0])
sns.boxplot(data=data,y="satisfaction_level",color="#ff7675",width=0.3)
plt.subplot(grid[1, 1])
sns.boxplot(data=data,y="satisfaction_level",x="left",width=0.2)
运行结果

从直方图分布来看,离职员工普遍对公司满意度不高(且很大一部分离职员工的满意度在最下限),而在职员工普遍对公司比较满意,满意 度普遍在0.5以上,这个也比较符合我们的常识:如果一个员工对公司满意度非常低,那么他离离职也不远了。 从箱型图上也可以看出,在职员工对公司满意度的中位数明显比离职员工多了一大截,另外离职人员中没有满意度为1的评价。
对公司满意度极低的离职员工有哪些共性?
data["satisfaction_level"].min()
data[data["satisfaction_level"]==0.09].describe().T
运行结果

可以看出,对公司满意度极低的离职员工,普遍负责的项目数量比较多(6个左右),比全部员工的平均项目数多2个;这部分员工的每月工 作时长基本上在275分钟,这意味着每月22个工作日平均每个工作日他们工作了12.5个小时,存在着严重的加班现象;并且他们在工作任务 大、加班严重的情况下,最近5年内还没有晋升。现在,我们应该非常清楚这部分人对公司的满意度极低并且离职的原因了。
对公司满意度极低但是仍然在职的员工有哪些共性?
从上面的直方图中,我们发现有一部分在职员工对公司满意度也非常低,接下来我们一起探索一下,这部分员工有什么共性。
Ls = data.loc[(data["satisfaction_level"]<0.13)&(data["left"]==0),:]
Ls.describe().T
运行结果

从对这部分员工的描述统计中可以看出,这部分员工也是5年内没有晋升,并且还有一半以上的人存在着加班严重的状况。
3.3 特征探索:最新考核评估与是否离职的关系
plt.figure(figsize=(10,8))
plt.subplot(211)
sns.histplot(data=data, x="last_evaluation", hue="left",kde=True)
plt.subplot(212)
sns.boxplot(data=data,y="last_evaluation",x="left",width=0.2)
运行结果

从图中可以看出,离职人员的最新考核评估相对来说比较高,但是存在着两极分化的现象,即一部分人考核相对偏低,另一部分人考核相对 比较高,而处在中间状态的人比较少。根据这些信息,我们可以猜测,离职的这部分员工中,一部分人很优秀,但是被严重的加班状况给劝 退了。
3.4 特征探索:参加项目数与是否离职的关系
colors = plt.get_cmap('Set3')(np.linspace(0.2, 0.7, len(v2)))
plt.figure(figsize=(12,4),dpi=100)
# 绘制参与不同项目数的人员离职数量
plt.subplot(131)
sns.histplot(data=data,y="number_project",hue="left"
,multiple='stack' # 堆叠
,shrink=0.8 # 缩放比例
,discrete=True
,alpha=0.7)
# 色彩饱和度
# 绘制所参加项目与是否离职的关系
plt.subplot(132)
plt.barh(y=v2_rate.index,width=v2_rate[1],color="#ff7f0e",alpha=0.7)
plt.barh(y=v2_rate.index,width=v2_rate[0],left=v2_rate[1],color="#1f77b4",alpha=0.7)
# 绘制各项目数所占百分比环形图
plt.subplot(133)
plt.pie(v2,autopct="%.2f%%",radius=1,pctdistance=0.8,labels=v2.index,colors=colors,wedgeprops={"width":0.4});
运行结果

从上述图表中可以看出,离职人员所占比例随着项目数的增多而增大(项目数为2的离职比例是个特例),此外,离职人员所占比例较高的 项目数2、6、7在项目总数上占比相对较少,可以推测: 项目数为2的这部分人有可能是工作能力不被认可,其离职人数也相对较多;
项目数为6和7的这部分员工,可能工作能力较强,跳槽相对比较容易,自然离职比例也相对比较高。
4 特征工程&建立模型
4.1 编码:将文本型变量变为数值型
from sklearn.preprocessing import OrdinalEncoder
d1 = OrdinalEncoder().fit_transform(data.iloc[:,-2:])
d1 = pd.DataFrame(d1,columns=data.iloc[:,-2:].columns)
df = pd.concat([data.iloc[:,:-2],d1],axis=1)
df.head()
运行结果

4.2 提取特征和标签并切分数据集
X = df.loc[:,df.columns!="left"]
y = df.loc[:,"left"]
from sklearn.model_selection import train_test_split
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=0)
4.3 初步建模:建立benchmark
from sklearn.linear_model import LogisticRegression as LR
from sklearn.metrics import confusion_matrix,classification_report
from sklearn.metrics import roc_auc_score,roc_curve,auc
clf = LR(max_iter=1000)
clf = clf.fit(Xtrain,Ytrain)
print("训练集上的预测准确率为:",clf.score(Xtrain,Ytrain))
print("测试集上的预测准确率为:",clf.score(Xtest,Ytest))
confusion_matrix(Ytrain,clf.predict(Xtrain))
roc_auc_score(Ytrain,clf.predict(Xtrain))
print(classification_report(Ytrain,clf.predict(Xtrain)))
运行结果


3870

被折叠的 条评论
为什么被折叠?



