员工一言不合就离职怎么办?我用Python写了个员工流失预测模型

 


 CDA数据分析师 出品  

【导读】

今天教大家如何用Python写一个员工流失预测模型。

获取数据代码:

扫描下方公众号

CDA数据分析师

回复关键字“离职”

说道离职的原因,可谓多种多样。人们归总了两点:

1. 钱没给到位

2. 心受委屈了

有人离职是因为“世界那么大,我想去看看”,也有人觉得“怀有绝技在身,不怕天下无路”。

 

另一方面,员工离职对于企业而言有什么影响呢?

要知道,企业培养人才需要大量的成本,为了防止人才再次流失,员工流失分析就显得十分重要了。这不仅仅是公司评估员工流动率的过程,通过找到导致员工流失的主要因素,预测未来的员工离职状况,从而进一步减少员工流失。

 

那么,哪些因素最容易导致员工离职呢?

这次我们用数据说话,

教你如何用Python写一个员工流失预测模型。

01

数据理解

我们分析了kaggle平台分享的员工离职相关的数据集,共有10个字段14999条记录。数据主要包括影响员工离职的各种因素(员工满意度、绩效考核、参与项目数、平均每月工作时长、工作年限、是否发生过工作差错、5年内是否升职、部门、薪资)以及员工是否已经离职的对应记录。字段说明如下:

回复关键字“离职” 

获取本期详细数据和代码

02

读入数据

# 导入包
import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt 
import seaborn as sns 

from pyecharts.charts import Bar, Pie, Page
from pyecharts import options as opts 
from pyecharts.globals import SymbolType, WarningType
WarningType.ShowWarning = False
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

03

探索性分析

描述性统计

1

df.describe().T

从上述描述性分析结果可以看出:

 

  • 员工满意度:范围0.09~1, 中位数0.640, 均值0.613, 总体来说员工对公司比较满意;

  • 绩效考核:范围0.36~1, 中位数0.72, 均值0.716, 员工平均考核水平在中等偏上;

  • 参与项目数:范围2~7, 中位数4, 均值3.8, 平均参加项目数约4个;

  • 平均每月工作时长:范围96~310小时, 中位数200, 均值201。

  • 工作年限:范围2~10年, 中位数3, 均值3.5。

 

离职人数占比

2

整理数据后发现,总共有14999人,其中红色部分代表离职人群,用数字1表示,蓝色为未离职人群,用数字0表示。离职人数为3571,占总人数的23.8%。


员工满意度

3

从直方图可以看出,离职员工的满意度评分明显偏低,平均值为0.44。满意度低于0.126分的离职率为97.2%。可见提升员工满意度可以有效防止人员流失。

df.groupby('left')['satisfaction_level'].describe() 

def draw_numeric_graph(x_series, y_series, title):
    # 产生数据
    sat_cut = pd.cut(x_series, bins=25) 
    cross_table = round(pd.crosstab(sat_cut, y_series, normalize='index'),4)*100
    x_data = cross_table.index.astype('str').tolist()
    y_data1 = cross_table[cross_table.columns[1]].values.tolist()
    y_data2 = cross_table[cross_table.columns[0]].values.tolist() 

    # 条形图
    bar = Bar(init_opts=opts.InitOpts(width='1350px', height='750px'))
    bar.add_xaxis(x_data)
    bar.add_yaxis(str(cross_table.columns[1]), y_data1, stack='stack1', category_gap='0%')
    bar.add_yaxis(str(cross_table.columns[0]), y_data2, stack='stack1', category_gap='0%')
    bar.set_global_opts(title_opts=opts.TitleOpts(title), 
                        xaxis_opts=opts.AxisOpts(name=x_series.name, name_location='middle', name_gap=30),
                        yaxis_opts=opts.AxisOpts(name='百分比', name_location='middle', name_gap=30, min_=0, max_=100),
                        legend_opts=opts.LegendOpts(orient='vertical', pos_top='15%', pos_right='2%'))
    bar.set_series_opts(label_opts=opts.LabelOpts(is_show=False), 
                        itemstyle_opts=opts.ItemStyleOpts(border_color='black', border_width=0.3))
    bar.set_colors(['#BF4C51', '#8CB9D0']) 

    return bar 
bar1 = draw_numeric_graph(df['satisfaction_level'], df['left'], title='满意度评分与是否离职')
bar1.render() 

平均每月工作时长

4

从直方图可以看出,月工作时长正常的员工离职率最低。而工时过低、过高的员工离职人数最多。证明恰当的工作任务分配是非常重要的。

 

 

员工工龄

5

可以看到7年及以上工龄的员工基本没有离职,只有工龄为5年的员工离职人数超过在职人数。可见工龄长于6年的员工,由于种种原因,其“忠诚度”较高。

而员工进入公司工作的第5年是一个较为“危险”的年份,也许是该企业的“5年之痒”,应当重点关注该阶段的员工满意度、职业晋升等情况,以顺利过渡。

职位晋升

6

 

从条形图可以看出,在过去5年内获得未晋升的员工离职率为24.2%,比获得晋升的员工高4倍。设定良好的晋升通道可以很好的防止员工流失。

薪资水平

7

 

可明显看出,薪资越高离职人数越少。证明为了减少离职率,提升员工福利待遇是一个可行的手段。

不同部门

8

可见各部门离职率如上图,离职率由高到低,前三位分别是:人力部、财务部、科技部。之后依次是:支持部、销售部、市场部、IT部门、产品部、研发部、管理部。对于离职率过高的部门,应进一步分析关键原因。

04

数据预处理

由于sklearn在建模时不接受类别型变量,我们主要对数据做以下处理,以方便后续建模分析:

 

  • 薪资水平salary为定序变量, 因此将其字符型转化为数值型。

  • 岗位是定类型变量, 对其进行one-hot编码。

 

# 数据转换
df['salary'] = df['salary'].map({"low": 0, "medium": 1, "high": 2})
# 哑变量
df_dummies = pd.get_dummies(df,prefix='sales')
df_dummies.head() 

05

建模分析

我们使用决策树和随机森林进行模型建置,首先导入所需包:

 

from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, f1_score, roc_curve, plot_roc_curve

然后划分训练集和测试集,采用分层抽样方法划分80%数据为训练集,20%数据为测试集。

x = df_dummies.drop('left', axis=1)
y = df_dummies['left']

X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, stratify=y, random_state=2020)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape) 

决策树

1

我们使用决策树进行建模,设置特征选择标准为gini,树的深度为5。输出分类的评估报告:

 

# 训练模型
clf = DecisionTreeClassifier(criterion='gini', max_depth=5, random_state=25)
clf.fit(X_train, y_train)
train_pred = clf.predict(X_train)
test_pred = clf.predict(X_test)  

print('训练集:', classification_report(y_train, train_pred))
print('-' * 60) 
print('测试集:', classification_report(y_test, test_pred))
训练集:               precision    recall  f1-score   support

           0       0.98      0.99      0.98      9142
           1       0.97      0.93      0.95      2857

    accuracy                           0.98     11999
   macro avg       0.97      0.96      0.97     11999
weighted avg       0.98      0.98      0.97     11999

------------------------------------------------------------
测试集:               precision    recall  f1-score   support

           0       0.98      0.99      0.98      2286
           1       0.97      0.93      0.95       714

    accuracy                           0.98      3000
   macro avg       0.97      0.96      0.97      3000
weighted avg       0.98      0.98      0.98      3000

假设我们关注的是1类(即离职类)的F1-score,可以看到训练集的分数为0.95,测试集分数为0.95。

# 重要性
imp = pd.DataFrame([*zip(X_train.columns,clf.feature_importances_)], columns=['vars', 'importance'])
imp.sort_values('importance', ascending=False)  
imp = imp[imp.importance!=0]
imp 

在属性的重要性排序中,员工满意度最高,其次是最新的绩效考核、参与项目数、每月工作时长。

然后使用网格搜索进行参数调优。

parameters = {'splitter':('best','random'),
              'criterion':("gini","entropy"),
              "max_depth":[*range(1, 20)],
             }

clf = DecisionTreeClassifier(random_state=25)
GS = GridSearchCV(clf, parameters, cv=10)
GS.fit(X_train, y_train)

print(GS.best_params_)

print(GS.best_score_) 
{'criterion': 'gini', 'max_depth': 15, 'splitter': 'best'}
0.9800813177648042

使用最优的模型重新评估训练集和测试集效果:

train_pred = GS.best_estimator_.predict(X_train)
test_pred = GS.best_estimator_.predict(X_test)

print('训练集:', classification_report(y_train, train_pred))
print('-' * 60) 
print('测试集:', classification_report(y_test, test_pred))
训练集:               precision    recall  f1-score   support

           0       1.00      1.00      1.00      9142
           1       1.00      0.99      0.99      2857

    accuracy                           1.00     11999
   macro avg       1.00      0.99      1.00     11999
weighted avg       1.00      1.00      1.00     11999

------------------------------------------------------------
测试集:               precision    recall  f1-score   support

           0       0.99      0.98      0.99      2286
           1       0.95      0.97      0.96       714

    accuracy                           0.98      3000
   macro avg       0.97      0.98      0.97      3000
weighted avg       0.98      0.98      0.98      3000

可见在最优模型下模型效果有较大提升,1类的F1-score训练集的分数为0.99,测试集分数为0.96。

随机森林

2

下面使用集成算法随机森林进行模型建置,并调整max_depth参数。

rf_model = RandomForestClassifier(n_estimators=1000, oob_score=True, n_jobs=-1, 
                                  random_state=0)
parameters = {'max_depth': np.arange(3, 17, 1) }
GS = GridSearchCV(rf_model, param_grid=parameters, cv=10)
GS.fit(X_train, y_train)

print(GS.best_params_) 
print(GS.best_score_) 
{'max_depth': 16}
0.988582151793161
train_pred = GS.best_estimator_.predict(X_train)
test_pred = GS.best_estimator_.predict(X_test)

print('训练集:', classification_report(y_train, train_pred))
print('-' * 60) 
print('测试集:', classification_report(y_test, test_pred))
训练集:               precision    recall  f1-score   support

           0       1.00      1.00      1.00      9142
           1       1.00      0.99      0.99      2857

    accuracy                           1.00     11999
   macro avg       1.00      1.00      1.00     11999
weighted avg       1.00      1.00      1.00     11999

------------------------------------------------------------
测试集:               precision    recall  f1-score   support

           0       0.99      1.00      0.99      2286
           1       0.99      0.97      0.98       714

    accuracy                           0.99      3000
   macro avg       0.99      0.99      0.99      3000
weighted avg       0.99      0.99      0.99      3000

可以看到在调优之后的随机森林模型中,1类的F1-score训练集的分数为0.99,测试集分数为0.98。

模型后续可优化方向:

  • 属性:数值型数据常常是模型不稳定的来源,可考虑对其进行分箱;重要属性筛选和字段扩充;

  • 算法:其他的集成方法;不同效能评估下的作法调整。

获取完整代码+数据:

扫描下方公众号,回复关键字“离职”,获取数据和代码吧。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值