一、分析背景
企业培养人才需要大量的成本,为防止人才流失,因此对于员工离职因素的分析十分重要。通过员工离职的主要因素,可以预测未来的员工离职状况,从而进一步减少员工流失,为公司降低人才培养成本。
二、分析目标
基本分析目标:导致员工离职的因素。
预测:员工离职可能性预测。
三、分析思路
提出问题
- 哪些因素和离职相关性较大?(初步判定)
- 哪些因素导致员工离职?(某个因素的具体数值范围确定)
- 产生这些因素的原因有?如何解决?
分析流程确立
- 描述性分析:看基本数据分布情况。
- 相关性分析:初步判定影响较大的因素。
- 变量分析:针对每一个变量探索对离职的影响,并找到变量影响的具体数值范围。
四、分析步骤
0 数据理解
data = pd.read_csv('../data/HR_comma_sep.csv') #读取数据
print('共有',data.shape[0],'条记录,',data.shape[1],'个字段')
data.head()
初步了解数据文件的基本信息:14999条数据,10个字段。
再来看看该每个字段的含义与数据类型。
data.info()
从上面输出结果可以知一下信息:
- 10个字段中:8个数值型数据,2个分类数据。
再对分类数据进一步查看:
data.describe(include=['O'])
print(data.sales.unique())
print(data.salary.unique())
综上,可以看出整个表结构和分类变量取值范围如下表所示。
1 数据清洗与整理
1.1 检查缺失值
data.isnull().sum()
不存在缺失值。
1.2 检查异常值
利用箱型图来检测异常值。
fig, ax = plt.subplots(1,5, figsize=(15, 3))
for i in range(5):
sns.boxplot(x=df.columns[i], data=df, ax=ax[i])
plt.show()
除了工作年限意外,没有异常值存在。异常值可能为公司元老级人物,不用排除。
从1.1和1.2步骤来看,整体数据很干净,可以直接进行处理。
1.2 修改字段名与字段顺序
适当修改数据字段名和顺序方便数据理解与使用。字段名修改如下:
- sales 》 department
- promotion_last_5years 》 promotion
- Work_accident 》work_accident
df = data.rename(columns = {"sales":"department","promotion_last_5years":"promotion","Work_accident":"work_accident"})
本次分析重点是对离职状态(left)进行相关因素的探索,所有将left放在最后一列方便查看。(当然也可以不移动)
cols = df.columns
cols = list(cols[:6]) + list(cols[7:])+[cols[6]]
print('Reordered Columns:',cols)
1.3 量化类别数据
- 转换为Category类型
df['department'] = df['department'].astype('category')
df['salary'] = df['salary'].astype('category')
df.info()
- 保存类别与数据值的映射字典
这一步主要是方便后面处理使用。
salary_dict = dict(enumerate(df['salary'].cat.categories))
department_dict = dict(enumerate(df['department'].cat.categories))
salary_dict,department_dict
- 将类别数值化表示
利用映射字典作为数据的类别表示。
for feature in df.columns:
if str(df[feature].dtype) == 'category':
df[feature] = df[feature].cat.codes
df[feature] = df[feature].astype('int64')
df.head()
2 数据分析
2.1 描述性分析
df.describe().T
上述描述性分析结果显示:
2.2 相关性分析
通过求person相关系数、绘制热力图,来识别两个特征之间的相关性,给出初步的变量分析方向。
corr = df.corr().round(3) # pearson相关系数
# 构造下三角掩码矩阵
mask = np.zeros_like(corr)
mask[np.tril_indices_from(mask)]=True # np.tril_indices_from()将列表索引分成两个数组返回,形成下三角。
# 绘制热力图
sns.set_style('white')
fig = plt.figure(figsize = (10,8)) # 设置图的大小
ax = sns.heatmap(corr,
xticklabels = True, yticklabels=True,
cmap = 'RdBu', #颜色
mask = mask, #使用掩码,只绘制一部分
fmt = '.3f', #格式设置
annot = True, #方格内是否写入数据
linewidths = .5, # 热力图矩阵之间的间隔大小
vmax = .4, #图例中最大值
square = True)
plt.title('Correlation') #图表名称
label_x = ax.get_xticklabels() # 获取横坐标
plt.setp(label_x,rotation=45,horizontalalignment='right') #设置横坐标表示
plt.show()
【图表解读】
从热力图中可以看出:
- 离职(left):
- 与满意度、工伤、晋升呈较强的负相关,与薪酬有较弱的负相关。
- 与工作年限呈较强的正相关,与平均每月工作时间、所在部门有较弱的正相关。
- 满意度(satisfaction_level):与绩效呈现正相关,与完成项目数量、在职年限也有一定的负相关性。
- 绩效(last_evaluation):与项目数、平均每月工作时间呈现较强的正相关。
- 项目数(number_object):与平均每月工作时间呈较强的正相关。
2.3 变量分析
2.3.1 离职 vs 在职
首先,从整体上来看离职和在职员工比例。
colors = ['#81ecec','#ff7675']
plt.pie(left_count.left_count,
labels =['not left','left'],
autopct = '%.2f%%',
colors = colors,
startangle = 90,
wedgeprops = {'width' : 0.4},
counterclock = False)
plt.axis('square')
plt.legend(loc='upper right')
plt.show()
从可以看出约24%的员工离职,在职员工有76%左右。
接下来进行单变量分析。
2.3.2 满意度 vs 离职
- 分布情况
sns.distplot(df.loc[df['left']==1,'satisfaction_level'],color='b',label='left')
sns.distplot(df.loc[df['left']==0,'satisfaction_level'],color='r',label='no_left')
plt.legend()
plt.show()
- 箱型图
sat_box = sns.boxplot(data=df,
x='left',
y='satisfaction_level')
# 计算中位数
satisfaction_median= df.groupby(['left'])['satisfaction_level'].median()
vertical_offset = df['satisfaction_level'].median()* 0.05 #偏移量
# 相对的中位数偏移:
for xtick in sat_box.get_xticks():
sat_box.text(xtick,satisfaction_median[xtick] + vertical_offset,satisfaction_median[xtick],
horizontalalignment='center',
color='w',
weight='semibold')
结论:从满意度的箱型图来看,离职人员对公司满意度相对较低,并且波动较大。
从满意度的分布情况来看,离职员工满意度呈现多峰分布,分别在0.1、0.3-0.5、0.8左右时,出现了3个峰值。
- 满意度在0.1左右时,即低满意度离职,员工对公司不满导致离职。
- 满意度在0.3~0.5时,即较低满意度离职,离职员工对公司满意度较低而离职,有深入原因。
- 满意度在0.7~0.9右时,即高满意度离职,可能是有更好的工作机会出现,使得员工跳槽。
2.3.2 工伤 vs 离职
# 数据透视表
workacc_left_tabel = pd.crosstab(index=df['work_accident'],columns=df['left'])
workacc_left_tabel['p'] = round(workacc_left_tabel[1] / (workacc_left_tabel[1] +workacc_left_tabel[0]),3)
# 用ployly条形图
data = []
annotation =[]
work_acc_dict = {0:'没受过伤',1:'受过伤'}
left_eles = df.left.unique() # 在职和离开的数值表示
for l in left_eles:
trace = Bar(x = workacc_left_tabel.index,
y = workacc_left_tabel[l],
name = ('离职' if l == 1 else '在职'),
marker = dict(color = colors[l+4]))
data.append(trace)
for i in df.work_accident.unique():
adict=dict(x=i,y=workacc_left_tabel.loc[i,1],
text = workacc_left_tabel.loc[i,'p'].round(3))
annotation.append(adict)
layout = Layout(title = '员工是否有工伤与离职是否有关',
width = 500,height = 500,
barmode = 'stack',
annotations=annotation,
xaxis = dict(tickmode = 'array',
tickvals = list(work_acc_dict.keys()),
ticktext=list(work_acc_dict.values())))
iplot(Figure(data=data,layout=layout))
结论
- 有工伤的员工离职率低约7.8%;没有工伤的员工离职率高,为26.5%。
- 可推测公司对于工作事故的处理方式较好。
2.3.3 晋升 vs 离职
promotion_left_table = pd.crosstab(index=df['promotion'],columns=df['left'])
promotion_left_table['p'] = promotion_left_table[1]/(promotion_left_table[1]+promotion_left_table[0])
promotion_dict={0:'没有升职',1:'升过职'}
data= []
annodatin = []
for i in df.left.unique():
trace = Bar(x = promotion_left_table.index,
y = promotion_left_table[i],
name=('在职' if i == 0 else '离职'),
marker = dict(color = colors[i+4]))
data.append(trace)
for i in df.promotion.unique():
adict=dict(x=i,y=promotion_left_table.loc[i,1],
text = promotion_left_table.loc[i,'p'].round(3))
annodatin.append(adict)
layout=Layout(title='员工过去5年是否升职对离职的影响',
width=500,height=550,
annotations=annodatin,
barmode = 'stack',
xaxis=dict(tickmode='array',
tickvals=list(promotion_dict.keys()),
ticktext=list(promotion_dict.values())))
iplot(Figure(data=data,layout=layout))
结论
- 离职员工主要存在于没有升职的员工中;升过职的员工离职极少。
- 良好的晋升通道设定可以防止员工流失。
2.3.4 部门 vs 离职
depart_left_table = pd.crosstab(index=df['department'],columns=df['left']) # 创建数据透视表
depart_left_table['p']=depart_left_table[1]/depart_left_table[0]
data = []
left_eles = df.left.unique() # 在职和离开的数值表示
for l in left_eles:
trace = Bar(x = depart_left_table[l], # 数量
y = depart_left_table.index, #部门
name = ('离职' if l == 1 else '在职'),
orientation = 'h',
text=depart_left_table['p'].round(2),
hoverinfo='x+y+text',
marker = dict(color = colors[l+4]))
data.append(trace)
layout = Layout(title = '每个部门的离职员工数量与在职员工数对比',
barmode = 'stack',
width = 800,height = 500,
yaxis = dict(title = '部门',
tickmode = 'array',
tickvals = list(department_dict.keys()),
ticktext = list(department_dict.values())))
iplot(Figure(data=data,layout=layout))
data = []
left_eles = df.left.unique() # 在职和离开的数值表示
for l in left_eles:
trace = Bar(x = depart_left_table.index,
y = depart_left_table['p'].round(2), #部门
name = ('离职' if l == 1 else '在职'),
hoverinfo='x+y',
marker = dict(color = colors[l+2]))
data.append(trace)
layout = Layout(title = '部门离职比率',
width = 700, height = 400,
xaxis = dict(title = '部门',
tickmode = 'array',
tickvals = list(department_dict.keys()),
ticktext = list(department_dict.values())))
iplot(Figure(data = [trace], layout = layout))
结论:
- 单从部门离职人数来看,大部分离职员工为sales、support、technica部门l;management离职人数较低。(离职人数是虚荣指标)
- 从离职占比来看,hr离职率最高,accounting次之,随后才是离职人员比较多的sales、support、technical。
- 对于每个部门离职原因需要进一步分析。
2.3.5 薪资 vs 离职
salary_left_table = pd.crosstab(index=df['salary'],columns=df['left'])
salary_left_table['p'] = salary_left_table[1]/(salary_left_table[1]+salary_left_table[0])
data = []
annodatin = []
for i in df.left.unique():
trace = Bar(x = salary_left_table.index,
y = salary_left_table[i],
name = ('在职' if i == 0 else '离职'),
marker = dict(color = colors[i+4]))
data.append(trace)
for i in df.salary.unique():
adict=dict(x=i,y=salary_left_table.loc[i,1],
text = salary_left_table.loc[i,'p'].round(3))
annodatin.append(adict)
layout = Layout(title='员工薪资对离职的影响',
width=580,height=350,
barmode = 'stack',
annotations=annodatin,
xaxis = dict(tickmode='array',
tickvals=list(salary_dict.keys()),
ticktext=list(salary_dict.values())))
iplot(Figure(data=data,layout=layout))
结论
- 离职员工的薪资主要处于中低水平。
- 高薪资员工,离职人数少,基本不会离职。
进一步探索各部门薪资情况,是否每个部门离职员工是否有薪资影响。
depart_salary_table = pd.crosstab(index=df['department'],columns=df['salary'])
data = []
for i in df.salary.unique():
trace = Bar(x = depart_salary_table.index,
y = depart_salary_table[i],
name = salary_dict[i],
marker = dict(color=colors[i+2]))
data.append(trace)
layout = Layout(title = '公司各部门的薪资情况',
width = 800,height=450,
xaxis = dict(tickmode = 'array',
tickvals = list(department_dict.keys()),
ticktext = list(department_dict.values())))
iplot(Figure(data=data,layout=layout))
结论
- 中低收入员工主要存在于sales、support、technical部门,从部门离职情况来看,离职人数大部分也是属于这三个部门。
- management高水平薪资相较于该部门而言占多数,且部门离职人员少,因此部门薪资情况不可忽视。
2.3.6 工作年限 vs 离职
- 箱型图
tspend_box = sns.boxplot(data=df,
x='left',
y='time_spend_company')
# 计算中位数
tspend_median= df.groupby(['left'])['time_spend_company'].median()
vertical_offset = df['time_spend_company'].median()* 0.05 #偏移量
# 相对的中位数偏移:
for xtick in sat_box.get_xticks():
tspend_box.text(xtick,tspend_median[xtick] + vertical_offset,tspend_median[xtick],
horizontalalignment='center',
color='w',
weight='semibold')
- 条形图
time_left_table = pd.crosstab(index=df['time_spend_company'],columns=df['left'])
data = []
for i in df.left.unique():
trace = Bar(x = time_left_table.index,
y = time_left_table[i],
name=('在职' if i == 0 else '离职'),
marker=dict(color = colors[i+4]))
data.append(trace)
layout = Layout(title='员工在职时间长短对离职的影响',
width=700,height=500,
barmode='stack',
xaxis=dict(tickmode='array',tickvals=time_left_table.index))
iplot(Figure(data=data,layout=layout))
结论:
- 从箱型图看,离职员工工作年限相较于在职员工多1年。
- 从条形图看,离职员工大部分已经工作3~6年,而工作7年以上的员工没有离开。
2.3.7 平均工作时间 vs 离职
- 箱型图
mhours_box = sns.boxplot(data=df,
x='left',
y='average_montly_hours')
# 计算中位数
mhours_median= df.groupby(['left'])['average_montly_hours'].median()
vertical_offset = df['average_montly_hours'].median()* 0.05 #偏移量
# 相对的中位数偏移:
for xtick in sat_box.get_xticks():
mhours_box.text(xtick,mhours_median[xtick] + vertical_offset,mhours_median[xtick],
horizontalalignment='center',
color='w',
weight='semibold')
- 分布情况
sns.distplot(df.loc[df['left']==1,'average_montly_hours'],color='b',label='left')
sns.distplot(df.loc[df['left']==0,'average_montly_hours'],color='r',label='no_left')
plt.legend()
plt.show()
结论:
- 从平均每月工作时长的箱型图来看,离职人员每月工作时间相较偏长,平均每月多6小时,并且波动偏大。
- 从平均每月工作时长的分布情况来看,离职员工平均每月工作时长呈现双峰分布,主要分布在125-165、215-285之间。在职员工平均每月工作时长主要分布在155-240之间。
- 上述可以说明平均每月工作时长过短(日均6-7.5h)或者过长(日均10h以上)都可能导致员工离职。最好保持在155-240之间(日均7.5-10h)。
2.3.8 项目数 vs 离职
number_left_table = pd.crosstab(index=df['number_project'],columns=df['left'])
number_left_table['p'] = round(number_left_table[1] / (number_left_table[0]+number_left_table[1]),3)
data = []
annotation = []
left_eles = df.left.unique() # 在职和离开的数值表示
for l in left_eles:
trace = Bar(x = number_left_table.index,
y = number_left_table[l],
name = ('离职' if l == 1 else '在职'),
marker = dict(color = colors[l+4]))
data.append(trace)
for i in df.number_project.unique():
adict=dict(x=i,y = number_left_table.loc[i,1],
text = number_left_table.loc[i,'p'])
annotation.append(adict)
layout = Layout(title = '员工负责项目数与离职是否有关',
width = 500,height = 500,
barmode = 'stack',
annotations = annotation,
xaxis = dict(tickmode = 'array',
tickvals = list(number_left_table.index)))
iplot(Figure(data=data,layout=layout))
结论
- 只有2个和6个项目的员工一半以上选择离职,有7个项目的员工全部离职,有3个项目的员工离职率最低。
- 说明项目数量小于2时,员工工作不够,可能未被重视导致离职;而有6个项目以上的员工,可能过度劳累导致离职。
- 每位员工负责的项目数量保持在3~4个较好。
2.3.9 绩效 vs 离职
- 箱型图
evaluation_box = sns.boxplot(data=df,
x='left',
y='last_evaluation')
# 计算中位数
evaluation_median= df.groupby(['left'])['last_evaluation'].median()
vertical_offset = df['last_evaluation'].median()* 0.05 #偏移量
# 相对的中位数偏移:
for xtick in sat_box.get_xticks():
evaluation_box.text(xtick,evaluation_median[xtick] + vertical_offset,evaluation_median[xtick],
horizontalalignment='center',
color='w',
weight='semibold')
2.分布情况
fig=plt.figure(figsize=(10,5))
sns.distplot(df.loc[df['left']==1,'last_evaluation'],color='b',label='left')
sns.distplot(df.loc[df['left']==0,'last_evaluation'],color='r',label='no_left')
plt.legend()
plt.show()
结论
- 从箱型图来看,离职员工绩效在0.79左右,在职员工在0.71左右,离职人员平均绩效比在职人员高(需要注意,为什么平均绩效偏高反而离职?)
- 从分布情况来看,离职员工绩效呈现双峰分布:
- 绩效为0.45~0.55,绩效低离职人数多,可能原因是绩效较差导致离职;
- 绩效为0.8~1,绩效高离职人数多,可能找到更好的工作机会或个人家庭等原因导致离职,具体需要进一步探索。
- 绩效在0.6~0.8之间有较好的员工留存率。
多变量分析,探索共同作用原因。
2.3.10 项目数 + 平均工作时长 vs 离职
sns.boxplot(data = df,
x = 'number_project',
y = 'average_montly_hours',
hue = 'left')
结论
- 随着项目数量增加,在职员工平均月工作时间变化不大;而离职员工平均月工作时间随之增加;说明项目数量与平均月工作时间的正相关,主要由离职员工所带动。
- 在项目数量相同的情况下,离职员工平均月工作时间比在职员工长。说明工作时长的不平衡可能导致员工离职。
2.3.11 项目数 + 绩效 vs 离职
sns.boxplot(data = df,
x = 'number_project',
y = 'last_evaluation',
hue = 'left')
结论
- 随着项目数量增加,离职员工绩效随着增高,而在职员工绩效变化不大,说明绩效与项目数的正相关主要由离职员工带动,要注意优秀员工离职带来的公司绩效影响。
- 项目数量为2时,离职员工绩效比在职员工低,可能个人工作能力不足导致离职。
- 在项目数量为4~6时,离职人员绩效相较于在职人员高出较多。
2.3.12 绩效 + 平均每月工作时间 vs 离职
sns.lmplot(data = df,
x = 'average_montly_hours',
y = 'last_evaluation',
hue = 'left',
fit_reg = False)
结论
- 整个分布来看,离职集群有两个:
- 平均月工作时间在150左右,绩效在0.55左右时,员工离职人数多。主要原因可能是员工自身不努力。
- 平均月工作时间在255左右,绩效在0.9左右时,排除员工自身努力的原因,则主要原因可能是过度劳累或找到更好的工作机会离职。
- 总体看来,绩效和平均月工作时间分别维持在0.60.8,155255之间员工较为稳定。
2.3.13 绩效 + 满意度 vs 离职
sns.lmplot(data = df,
x = 'satisfaction_level',
y = 'last_evaluation',
hue = 'left',
fit_reg = False)
结论
- 从整体分布来看,离职集群有3个:
- 满意度在0.1,绩效在0.8~1范围,优秀员工对公司工作不满(注意保留);
- 满意度在0.4,绩效在0.45~0.58范围,这部分员工离职有公司和自身不努力等原因共同作用。
- 满意度在0.85,绩效在0.8以上,优秀员工对公司满意却离职,可能有更好的工作机会或自身家庭原因等作用。
2.4 总结
- 离职员工在工作年限、项目数、绩效、平均月工作时间上偏高,优秀员工离职比例较大。
- 大部分离职人员的主要特征
对公司满意度低,薪资处于中低水平,平均月工作时间较长约,工作年限在3~6年,过去5年没有晋升,负责项目数量偏低(2个)和偏高(6,7个),主要来自于salse、support、techenical部门(人员流动或工作压力较大的部门)。 - HR和accounting离职比例高,这两个部门需要重点关注与分析离职的主要原因。此外,受过工伤的员工离职率低,公司对员工意外事故处理这部分处理得当。
- 离职率与满意度、薪酬呈负相关,说明低满意度、薪资水平较低产生了较高的离职率。
- 从绩效来看,员工离职并不仅仅因为自身业绩不好。对于绩效高且满意度高、绩效高且平均每月工作时间长、绩效高且负责项目多的这部分优秀员工存在较高的离职率。侧面反映了优秀员工未能通过自身努力得到升职加薪、实现个人价值而导致离职。
目前看来,公司需要注意的方面主要有以下两点:
- 优秀员工(高绩效)的留存:要优化绩效考核制度,建立良好的晋升通道和薪资提升标准,使得员工在公司有较好的职业发展。
- 提升员工的满意度:主要从工作时长、项目安排和薪资上进行优化调整,降低员工平均工作时长(建议每日工作时长保持在7.5~10h之间)、合理分配项目(建议人均负责项目在3~4个),提高人效。
3 建模分析
建模分析基于sklearn机器学习库。
3.1 数据预处理
在之前进行描述分析时,使用的类别数据转换方式,未能按照薪资水平大小进行顺序赋值,需要重新编码。此外,部门类别并没有顺序意义,重新采用one-hot进行编码。
# 定序
df['salary'] = df.salary.map({"low": 0, "medium": 1, "high": 2})
df['salary'] = df['salary'].astype('int64')
df.salary.unique()
#定类
df = pd.get_dummies(df,prefix='department')
对于连续型数据需要进行标准化,这里采用归一化的方式处理。
由于satisfaction_level和last_evaluation取值范围为[0,1],则不用进行归一化。
对number_project,average_montly_hours,time_spend_company采用max-min进行归一化。
min_max_scaler = preprocessing.MinMaxScaler()
df.loc[:,['number_project','average_montly_hours','time_spend_company']] = min_max_scaler.fit_transform(df.loc[:,['number_project','average_montly_hours','time_spend_company']])
df
3.2 数据集划分
其中训练集占原始数据的80%,测试集占20%。
from sklearn.model_selection import train_test_split
y = df.left
X = df.drop('left',axis=1)
X_train,X_test,y_train,y_test = train_test_split(X, y, test_size = 0.2,random_state = 1)
3.3 模型试验
3.3.1 逻辑回归
from sklearn.linear_model import LogisticRegression
# 简单逻辑回归
LR = LogisticRegression() #创建模型
LR.fit(X_train,y_trian)
print('训练集准确性',LR.score(X_train,y_trian))
print('测试集准确性',LR.score(X_test,y_test))
准确性一般,在基于该模型上进行调参,看是否能提高准确性。
随机梯度下降
LR2 = LogisticRegression(solver='saga')
LR2.fit(X_train,y_trian)
print('训练集准确性',LR2.score(X_train,y_trian))
print('测试集准确性',LR2.score(X_test,y_test))
模型没有提升,可能是数据量不够大,惩罚项作用不大。
交叉验证
from sklearn.linear_model import LogisticRegressionCV
# 利用10折交叉验证选择合适的参数C
Cs = 10 ** np.linspace(-10, 10, 400)
LR_cv = LogisticRegressionCV(Cs=Cs, cv=10, penalty='l2', solver='saga', max_iter=10000, scoring='accuracy')
LR_cv.fit(X_train, y_train)
LR_cv.C_
利用该参数进行预测
LR3 = LogisticRegression(solver='saga', penalty='l2', C=37.92690191)
LR3.fit(X_train,y_train)
print("训练集准确率: ", LR3.score(X_train, y_train))
print("测试集准确率: ", LR3.score(X_test, y_test))
准确性稍微有所提高。
分别利用混淆矩阵和ROC进行模型评估。
混淆矩阵
from sklearn import metrics
X_train_pred = LR3.predict(X_train)
X_test_pred = LR3.predict(X_test)
print('训练集混淆矩阵:')
print(metrics.confusion_matrix(y_train, X_train_pred))
print('测试集混淆矩阵:')
print(metrics.confusion_matrix(y_test, X_test_pred))
from sklearn.metrics import classification_report
print('训练集:')
print(classification_report(y_train, X_train_pred))
print('测试集:')
print(classification_report(y_test, X_test_pred))
在训练集有0.83的精准率和0.93的召回率, 在测试集上有0.83的精准率和0.92的召回率。
ROC
from sklearn.metrics import roc_curve
lr_fpr, lr_tpr, lr_thresholds = roc_curve(y_test, LR3.predict_proba(X_test)[:,1]) # 返回假正率、真正率、阈值
lr_roc_auc = metrics.auc(lr_fpr, lr_tpr) # 计算auc值
lr_roc_auc
auc即为ROC曲线下的面积,面积越大代表模型预测效果越好。
后面的模型省略中间求准确度、混淆矩阵的步骤。
3.3.2 朴素贝叶斯
from sklearn.naive_bayes import GaussianNB
gnb = GaussianNB()
gnb.fit(X_train, y_train)
gnb_fpr, gnb_tpr, gnb_thresholds = roc_curve(y_test, gnb.predict_proba(X_test)[:,1]) # 返回假正率、真正率、阈值
gnb_roc_auc = metrics.auc(gnb_fpr, gnb_tpr) # 计算auc值
3.3.3 决策树
import sklearn.tree as sk_tree
skt = sk_tree.DecisionTreeClassifier()
skt.fit(X_train,y_train)
skt_fpr, skt_tpr, skt_thresholds = roc_curve(y_test, skt.predict_proba(X_test)[:,1]) # 返回假正率、真正率、阈值
skt_roc_auc = metrics.auc(skt_fpr, skt_tpr) # 计算auc值
3.3.4 支持向量机SVM
import sklearn.svm as sk_svm
svm = sk_svm.SVC(probability=True)
svm.fit(X_train,y_train)
svm_fpr, svm_tpr, svm_thresholds = roc_curve(y_test, svm.predict_proba(X_test)[:,1]) # 返回假正率、真正率、阈值
svm_roc_auc = metrics.auc(svm_fpr, svm_tpr) # 计算auc值
3.3.5 随机森林模型
from sklearn.ensemble import RandomForestClassifier
RR = RandomForestClassifier()
RR.fit(X_train, y_train)
rr_fpr, rr_tpr, rr_thresholds = roc_curve(y_test, RR.predict_proba(X_test)[:,1]) # 返回假正率、真正率、阈值
rr_roc_auc = metrics.auc(rr_fpr, rr_tpr) # 计算auc值
ROC综合评价
plt.figure(figsize=(8, 5))
plt.plot([0, 1], [0, 1],'--', color='r')
plt.plot(lr_fpr, lr_tpr, label='LogisticRegression(area = %0.2f)' % lr_roc_auc)
plt.plot(gnb_fpr, gnb_tpr, label='GaussianNB(area = %0.2f)' % gnb_roc_auc)
plt.plot(skt_fpr, skt_tpr, label='DecisionTree(area = %0.2f)' % skt_roc_auc)
plt.plot(svm_fpr, svm_tpr, label='SVM(area = %0.2f)' % svm_roc_auc)
plt.plot(rr_fpr, rr_tpr, label='RandomForest(area = %0.2f)' % rr_roc_auc)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.title('ROC')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend()
plt.show()
从上图可以看出,应用随机森林模型效果最好。