用R语言分析与预测员工离职

在实验室搬砖之后,继续我们的kaggle数据分析之旅,这次数据也是答主在kaggle上选择的比较火的一份关于人力资源的数据集,关注点在于员工离职的分析和预测,依然还是从数据读取,数据预处理,EDA和机器学习建模这几个部分开始进行,最后使用集成学习中比较火的random forest算法来预测离职情况。

数据读取
setwd(“E:/kaggle/human resource”) library(data.table) library(plotly) library(corrplot) library(randomForest) library(pROC) library(tidyverse) library(caret) hr<-as.tibble(fread(“HR_comma_sep.csv”)) glimpse(hr) sapply(hr,function(x){sum(is.na(x))}) ———————————————————————————————————————————————————————————————————————————————————— Observations: 14,999 Variables: 10 $ satisfaction_level 0.38, 0.80, 0.11, 0.72, 0.37, 0.41, 0.10, 0.92, 0.89, 0.42, 0.45, 0.11, 0.84, 0.41, 0.36, 0.38, 0.45, 0.78, 0.45, 0.76, 0.11, 0.3… $ last_evaluation 0.53, 0.86, 0.88, 0.87, 0.52, 0.50, 0.77, 0.85, 1.00, 0.53, 0.54, 0.81, 0.92, 0.55, 0.56, 0.54, 0.47, 0.99, 0.51, 0.89, 0.83, 0.5… $ number_project 2, 5, 7, 5, 2, 2, 6, 5, 5, 2, 2, 6, 4, 2, 2, 2, 2, 4, 2, 5, 6, 2, 6, 2, 2, 5, 4, 2, 2, 2, 6, 2, 2, 2, 4, 6, 2, 2, 6, 2, 5, 2, 2, … $ average_montly_hours 157, 262, 272, 223, 159, 153, 247, 259, 224, 142, 135, 305, 234, 148, 137, 143, 160, 255, 160, 262, 282, 147, 304, 139, 158, 242,… $ time_spend_company 3, 6, 4, 5, 3, 3, 4, 5, 5, 3, 3, 4, 5, 3, 3, 3, 3, 6, 3, 5, 4, 3, 4, 3, 3, 5, 5, 3, 3, 3, 4, 3, 3, 3, 6, 4, 3, 3, 4, 3, 5, 3, 3, … $ Work_accident 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, … $ left 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, … $ promotion_last_5years 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, … $ sales “sales”, “sales”, “sales”, “sales”, “sales”, “sales”, “sales”, “sales”, “sales”, “sales”, “sales”, “sales”, “sales”, “sales”, "sa… $ salary “low”, “medium”, “medium”, “low”, “low”, “low”, “low”, “low”, “low”, “low”, “low”, “low”, “low”, “low”, “low”, “low”, “low”, "low… satisfaction_level last_evaluation number_project average_montly_hours time_spend_company Work_accident left 0 0 0 0 0 0 0 promotion_last_5years sales salary 0 0 0

数据集情况如下,一共10维数据,14999个观测值,变量的代表名称分别是
satisfaction_level–满意度,last_evaluation–最后一次评估,number_project–参与项目数量,average_montly_hours–每月平均工作时间,time_spend_company–公司停留时间,Work_accident–工作事故次数,left–是否离职,promotion_last_5years–过去五年升值状况,sales–工种,salary–工资。

而且简单的观测了一下,没有发现缺失值,那么我就可以直接进入数据分析阶段了。

数据预处理
根据每一个特征的数值情况,我们可以将不少特征因子化,方便后期做不同类别的差异分析。

hr s a l e s &lt; a s . f a c t o r ( h r sales&lt;-as.factor(hr sales) hr s a l a r y &lt; a s . f a c t o r ( h r salary&lt;-as.factor(hr salary) hr l e f t &lt; a s . f a c t o r ( h r left&lt;-as.factor(hr left) hr W o r k a c c i d e n t &lt; a s . f a c t o r ( h r Work_accident&lt;-as.factor(hr Work_accident) hr l e f t &lt; r e c o d e ( h r left&lt;-recode(hr left,‘1’=“yes”,‘0’=“no”) hr p r o m o t i o n l a s t 5 y e a r s &lt; a s . f a c t o r ( h r promotion_last_5years&lt;-as.factor(hr promotion_last_5years)

看的出大部分数据都是数值型的,我们使用相关性来衡量不同变量之间的相关性高低:

cor.hr<-hr %>% select(-sales,-salary) cor.hr W o r k a c c i d e n t &lt; a s . n u m e r i c ( a s . c h a r a c t e r ( c o r . h r Work_accident&lt;-as.numeric(as.character(cor.hr Work_accident)) cor.hr p r o m o t i o n l a s t 5 y e a r s &lt; a s . n u m e r i c ( a s . c h a r a c t e r ( c o r . h r promotion_last_5years&lt;-as.numeric(as.character(cor.hr promotion_last_5years)) cor.hr l e f t &lt; a s . n u m e r i c ( a s . c h a r a c t e r ( c o r . h r left&lt;-as.numeric(as.character(cor.hr left)) corrplot(corr = cor(cor.hr),type = “lower”,method = “square”,title=“变量相关性”,order=“AOE”)

直观的来看,是否离职和满意度高低就有很高的关联性啊。

EDA
ggplot(group_by(hr,sales),aes(x=sales,fill=sales))+geom_bar(width = 1)+coord_polar(theta = “x”)+ggtitle(“不同职业的人数”) ggplot(hr,aes(x=sales,y=satisfaction_level,fill=sales))+geom_boxplot()+ggtitle(“不同职业的满意度”)+stat_summary(fun.y = mean,size=3,color=‘white’,geom = “point”)+ theme(legend.position = “none”) ggplot(hr,aes(x=sales,y=satisfaction_level,fill=left))+geom_boxplot()+ggtitle(“不同职业的满意度”) ggplot(hr,aes(x=sales,y=average_montly_hours,fill=left))+geom_boxplot()+ggtitle(“不同职业的工作时长”) ggplot(hr,aes(x=sales,y=number_project,fill=left))+geom_boxplot()+ggtitle(“不同职业的项目情况”)

首先观察不同岗位的工作人数。搞销售的人数真的是不少,难道有不少我大生科的同学吗??(哈哈哈哈哈哈哈,开个玩笑而已,不过说实话做生物真的很累啊)。销售,后期支持,和技术岗人数占据人数排行榜前三。

扫描二维码关注公众号,回复: 3908823 查看本文章

不同的职业满意度的分布大体相当,不过accounting的小伙伴们似乎打分都不高哦,其他的几个工种均值和中位数都没有明显差别,接下来我们看看不同职业是否离职的情况和打分的高低情况:

和想象中结果几乎没有区别,离职和不离职的打分区分度很高,和职业几乎没有关系。

那么不同职业的平均工作时长呢,看图而言,没有离职的人群工作时间都很稳定,但是离职人群的工作时间呈现两极分化的趋势,看来太忙和太闲都不是很好,这对hr的考验还是很大的。

后面我们来一次关注一下不同特征和离职的关系问题:

ggplot(hr,aes(x=satisfaction_level,color=left))+geom_line(stat = “density”)+ggtitle(“满意度和离职的关系”) ggplot(hr,aes(x=salary,fill=left))+geom_histogram(stat=“count”)+ggtitle(“工资和离职的关系”) ggplot(hr,aes(x=promotion_last_5years,fill=left))+geom_histogram(stat=“count”)+ggtitle(“近5年升值和离职的关系”) ggplot(hr,aes(x=last_evaluation,color=left))+geom_point(stat = “count”)+ggtitle(“最后一次评价和离职的关系”) hr %>% group_by(sales) %>% ggplot(aes(x=sales,fill=Work_accident))+geom_bar()+coord_flip()+ theme(axis.text.x = element_blank(),axis.title.x = element_blank(),axis.title.y = element_blank())+scale_fill_discrete(labels=c(“no accident”,“at least once”))

没有离职的人群打分已知非常稳定,而离职人群的打分就有点难以估摸了

还是那句话,“有钱好办事啊”

你不给宝宝升职,宝宝就生气离职

和前面的面积图差不多,hr也要警惕那些最后一次打分很高的,虽然大部分是不准备离职的,但是有些为了给老东家面子还是会来点“善意的谎言”的。

不出错是不可能的,出错人数多少基本和总人数成正比,所以这个对于离职来说不是问题。

模型构建和评估
index<-sample(2,nrow(hr),replace = T,prob = c(0.7,0.3)) train<-hr[index1,];test<-hr[index2,] model<-randomForest(left~.,data = train) predict.hr<-predict(model,test) confusionMatrix(test l e f t , p r e d i c t . h r ) p r o b . h r &lt; p r e d i c t ( m o d e l , t e s t , t y p e = &quot; p r o b &quot; ) r o c . h r &lt; r o c ( t e s t left,predict.hr) prob.hr&lt;-predict(model,test,type=&quot;prob&quot;) roc.hr&lt;-roc(test left,prob.hr[,2],levels=levels(test l e f t ) ) p l o t ( r o c . h r , t y p e = &quot; S &quot; , c o l = &quot; r e d &quot; , m a i n = p a s t e ( &quot; A U C = &quot; , r o c . h r left)) plot(roc.hr,type=&quot;S&quot;,col=&quot;red&quot;,main = paste(&quot;AUC=&quot;,roc.hr auc,sep = “”))

根据前面的特征分析,本次答主并没有觉得有很好的特征来提取,就直接扔进算法里面计算去了,计算出来的混淆矩阵的情况效果还是杠杠的:

Confusion Matrix and Statistics Reference Prediction no yes no 3429 5 yes 28 1010 Accuracy : 0.9926 95% CI : (0.9897, 0.9949) No Information Rate : 0.773 P-Value [Acc > NIR] : < 2.2e-16 Kappa : 0.9791 Mcnemar’s Test P-Value : 0.0001283 Sensitivity : 0.9919 Specificity : 0.9951 Pos Pred Value : 0.9985 Neg Pred Value : 0.9730 Prevalence : 0.7730 Detection Rate : 0.7668 Detection Prevalence : 0.7679 Balanced Accuracy : 0.9935 ‘Positive’ Class : no
yyk.39.net/hospital/f9a8f_doctors.htmlyyk.39.net/hospital/f9a8f_detail.htmlyyk.39.net/hospital/f9a8f_labs.htmlyyk.39.net/hospital/f9a8f_doctors.htmlyyk.39.net/hospital/f9a8f_guides.htmlyyk.39.net/hospital/f9a8f_knowledges.htmlyyk.39.net/hospital/f9a8f_comments.htmlyyk.39.net/hospital/f9a8f_registers.html
acc=0.9926,recall=0.9951,precision=0.9730,基本都是逆天的数据了,看来kaggle的数据集已经清洗的很棒了,rf算法也是一如既往地给力。最后贴出ROC曲线的图


作者:R语言中文社区
来源:CSDN
原文:https://blog.csdn.net/kMD8d5R/article/details/83542978
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/qq_30489981/article/details/83587015