HR analyics Analisi con le CP e analisi predittiva SQG file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 1/24
Dati Human Resources (HR) In questa esercitazione viene analizzato un set di dati su 15.000 dipendenti di un azienda. L obiettivo è capire perché i dipendenti lasciano l azienda e, si spera, escogitare una strategia per mantenere i migliori. library(ggplot2) library(ggfortify) file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 2/24
Caricare i dati HR=read.csv("http://www.cs.unitn.it/~taufer/Data/HR-analytics.csv") str(hr) ## 'data.frame': 14999 obs. of 10 variables: ## $ satisfaction_level : num 0.38 0.8 0.11 0.72 0.37 0.41 0.1 0.92 0.89 0.42... ## $ last_evaluation : num 0.53 0.86 0.88 0.87 0.52 0.5 0.77 0.85 1 0.53... ## $ number_project : int 2 5 7 5 2 2 6 5 5 2... ## $ average_montly_hours : int 157 262 272 223 159 153 247 259 224 142... ## $ time_spend_company : int 3 6 4 5 3 3 4 5 5 3... ## $ Work_accident : int 0 0 0 0 0 0 0 0 0 0... ## $ left : int 1 1 1 1 1 1 1 1 1 1... ## $ promotion_last_5years: int 0 0 0 0 0 0 0 0 0 0... ## $ Department : Factor w/ 10 levels "accounting","hr",..: 8 8 8 8 8 8 8 8 8 ## $ salary : Factor w/ 3 levels "high","low","medium": 2 3 3 2 2 2 2 2 2 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 3/24
Trasforma le variabili left (il nostro obiettivo), work accident e promotion last 5years in factor HR$left=factor(HR$left,levels=c(0,1),labels=c("No","Yes")) HR$Work_accident=factor(HR$Work_accident,levels=c(0,1),labels=c("No","Yes")) HR$promotion_last_5years=factor(HR$promotion_last_5years,levels=c(0,1),labels=c("No","Yes")) str(hr) ## 'data.frame': 14999 obs. of 10 variables: ## $ satisfaction_level : num 0.38 0.8 0.11 0.72 0.37 0.41 0.1 0.92 0.89 0.42... ## $ last_evaluation : num 0.53 0.86 0.88 0.87 0.52 0.5 0.77 0.85 1 0.53... ## $ number_project : int 2 5 7 5 2 2 6 5 5 2... ## $ average_montly_hours : int 157 262 272 223 159 153 247 259 224 142... ## $ time_spend_company : int 3 6 4 5 3 3 4 5 5 3... ## $ Work_accident : Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1... ## $ left : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 2 2 2 2 2... ## $ promotion_last_5years: Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1... ## $ Department : Factor w/ 10 levels "accounting","hr",..: 8 8 8 8 8 8 8 8 8 ## $ salary : Factor w/ 3 levels "high","low","medium": 2 3 3 2 2 2 2 2 2 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 4/24
Una panoramica summary(hr) table(hr$left,hr$promotion_last_5years) table(hr$left,hr$work_accident) 3571 (23.81%) hanno lasciato la compagnia 2169 (14.46%) hanno avuto un infortunio 169 di quelli che hanno avuto un incidente hanno lasciato (7.79%) 319 (2.13%) hanno avuto una promozione negli ultimi 5 anni 19 di quelli che hanno avuto una promozione hanno lasciato (5.96%) file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 5/24
PCA Si esegua una PCA sulle variabili quantitative. L obiettivo è avere una visione generale della struttura dei dati. Le variabili qualitative non sono considerate. pca.hr=prcomp(hr[,c(1:5)],scale=true) summary(pca.hr) ## Importance of components: ## PC1 PC2 PC3 PC4 PC5 ## Standard deviation 1.3526 1.0532 0.9365 0.7969 0.7410 ## Proportion of Variance 0.3659 0.2218 0.1754 0.1270 0.1098 ## Cumulative Proportion 0.3659 0.5878 0.7632 0.8902 1.0000 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 6/24
Loadings delle prime 3 CP pca.hr$rotation[,1:3] ## PC1 PC2 PC3 ## satisfaction_level 0.08688429-0.8312701 0.38205560 ## last_evaluation -0.50740199-0.3699699 0.04741566 ## number_project -0.57907693 0.1125760-0.20954619 ## average_montly_hours -0.54928085-0.1245718-0.25376183 ## time_spend_company -0.31297732 0.3793689 0.86225321 PC1 Potrebbe essere definita impegno. Essenzialmente una media delle variabili che indicano il coinvolgimento del dipendente nelle varie attività. PC2 principalmente legata al livello di soddisfazione. file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 7/24
Biplot autoplot(pca.hr,shape = FALSE, data=hr,colour="left",label=true,label.size = 1, loadings = TRUE, loadings.colour = 'blue',loadings.label = TRUE, loadings.label.size = 4,loadings.label.colour="blue") file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 8/24
Analisi PCA È interessante notare che ci sono tre gruppi principali di dipendenti che hanno lasciato l azienda (si ricordi che satisfaction level ha un coefficiente negativo in PC1): gruppo A (in basso a sinistra), che identifica i dipendenti con alti livelli di ore trascorse in azienda, punteggio elevato raggiunto nell ultima valutazione e molti progetti assegnati; gruppo B (in alto a sinistra), caratterizzato da bassi livelli di soddisfazione e alti livelli di ore trascorse in azienda; gruppo C (a destra), riguardante i soggetti con ore mensili più basse, bassi livelli nell ultima valutazione e progetti assegnati. file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 9/24
Gruppo A Costituito da soggetti che hanno deciso di lasciare il posto di lavoro pur avendo ottenuto valutazioni elevate. Questa decisione potrebbe essere motivata dal carico di lavoro eccessivo a cui questi dipendenti sono sottoposti; infatti sia il numero di progetti che le ore trascorse in azienda sono elevati. Questi sono dipendenti che l azienda vorrebbe mantenere Potrebbero essere offerte una riduzione del carico di lavoro (ore medie mensili e numero di progetti), che sembrano avere un livello soglia oltre il quale il dipendente lascerà In alternativa, potrebbero essere offerti incentivi monetari o non monetari. file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 10/24
Gruppo B Simili a quelli del gruppo A possono essere classificati come lavoratori altamente performanti; tuttavia, sembrano meno soddisfatti della posizione lavorativa ricoperta. Essendo lavoratori produttivi, la loro perdita sarebbe dannosa per l azienda. Dall analisi grafica possiamo notare che all interno del gruppo B è possibile isolare un sottogruppo estremo (identificato nella parte più a sinistra), che sembra aver superato un valore di soglia per le ore medie mensili delle variabili e il numero di progetti. Pertanto, gli incentivi monetari o non monetari potrebbero essere inefficaci; l intervento diretto sul carico di lavoro sembra obbligatorio in questo caso. file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 11/24
Gruppo C Dipendenti poco performanti e con bassi livelli legati all ultima valutazione. file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 12/24
Analisi predittiva Proviamo a costruire dei modelli per l analisi e la previsione. Per la validazione dei modelli spezziamo il data set in training e test (validation set approach) Selezionare 9000 unità come set training. Le restanti 6000 verranno utilizzate per la convalida (set di test) set.seed(2) train=sample(nrow(hr), 9000) HR.train=HR[train,] HR.test=HR[-train,] file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 13/24
Modello di regressione logistica glm.fit<-glm(left~.,family=binomial,data=hr.train) summary(glm.fit) ## ## Call: ## glm(formula = left ~., family = binomial, data = HR.train) ## ## Deviance Residuals: ## Min 1Q Median 3Q Max ## -2.26525-0.66682-0.40154-0.09602 3.03777 ## ## Coefficients: ## Estimate Std. Error z value Pr(> z ) ## (Intercept) -1.4681620 0.2491605-5.892 3.81e-09 *** ## satisfaction_level -4.1912716 0.1266668-33.089 < 2e-16 *** ## last_evaluation 0.8507747 0.1945684 4.373 1.23e-05 *** ## number_project -0.3418174 0.0277985-12.296 < 2e-16 *** ## average_montly_hours 0.0042577 0.0006709 6.346 2.20e-10 *** ## time_spend_company 0.2838646 0.0202697 14.004 < 2e-16 *** ## Work_accidentYes -1.5246742 0.1152395-13.230 < 2e-16 *** ## promotion_last_5yearsyes -1.6173249 0.3552501-4.553 5.30e-06 *** ## Departmenthr 0.1086424 0.1708848 0.636 0.5249 ## DepartmentIT -0.0492851 0.1567601-0.314 0.7532 ## Departmentmanagement -0.3750468 0.2045449-1.834 0.0667. ## Departmentmarketing 0.0836831 0.1675569 0.499 0.6175 ## Departmentproduct_mng -0.2171476 0.1690863-1.284 0.1991 ## DepartmentRandD -0.4982251 0.1837527-2.711 0.0067 ** ## Departmentsales -0.0191452 0.1312131-0.146 0.8840 ## Departmentsupport 0.0088823 0.1409565 0.063 0.9498 ## Departmenttechnical 0.1251446 0.1368642 0.914 0.3605 ## salarylow 1.9793576 0.1647236 12.016 < 2e-16 *** ## salarymedium 1.4241014 0.1655266 8.603 < 2e-16 *** ## --- ## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 ## ## (Dispersion parameter for binomial family taken to be 1) ## ## Null deviance: 9969.9 on 8999 degrees of freedom ## Residual deviance: 7736.2 on 8981 degrees of freedom ## AIC: 7774.2 ## ## Number of Fisher Scoring iterations: 5 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 14/24
Tavola di classificazione sui dati test #Predict probaility for test data Pred.Pr.glm<- predict(glm.fit,hr.test,type="response") #Predict the class "no" "yes" for test data Pred.Class.test<-rep("No",nrow(HR.test)) Pred.Class.test[Pred.Pr.glm>0.5]="Yes" #Build the classification table addmargins(table(hr.test$left,pred.class.test)) ## Pred.Class.test ## No Yes Sum ## No 4246 364 4610 ## Yes 866 523 1389 ## Sum 5112 887 5999 Errore test 0.21 Sensitivita 0.38 Specificita 0.92 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 15/24
Curva ROC sui dati test #create prediction and performance objects pred.glm <- prediction(pred.pr.glm, HR.test$left) perf.glm <- performance(pred.glm, measure = "tpr", x.measure = "fpr") #plot ROC plot(perf.glm,colorize=true,lwd=4,main="roc Logistic model") # AUC Auc=performance(pred.glm, measure = "auc",fpr.stop=0.5) Auc@y.values[[1]][1] ## [1] 0.328126 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 16/24
Un albero di classificazione tree.fit<-tree(left~.,hr.train) plot(tree.fit,lwd=3) text(tree.fit,pretty=0,col="blue",cex=1.5) file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 17/24
Validazione dell albero # predict probabilities Pred.Pr.tree<-round(predict(tree.fit,HR.test),digits=4) # predict the class Pred.Class.tree<-predict(tree.fit,HR.test,type="class") # Classification table addmargins(table(hr.test$left,pred.class.tree)) ## Pred.Class.tree ## No Yes Sum ## No 4558 52 4610 ## Yes 130 1259 1389 ## Sum 4688 1311 5999 Errore test 0.03 Sensitivita 0.91 Specificita 0.99 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 18/24
Curva ROC (dati test) # ROC pred.tree <- prediction(pred.pr.tree[,2], HR.test$left) perf.tree <- performance(pred.tree, measure = "tpr", x.measure = "fpr") plot(perf.tree,colorize=true,lwd=4,main="roc Classification tree") #AUC Auc=performance(pred.tree, measure = "auc",fpr.stop=0.5) Auc@y.values[[1]][1] ## [1] 0.4751226 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 19/24
Random Forest rf.fit<-randomforest(left~.,hr.train,mtray=3,importance=true,ntree=1000) rf.fit ## ## Call: ## randomforest(formula = left ~., data = HR.train, mtray = 3, importance = TRUE, ## Type of random forest: classification ## Number of trees: 1000 ## No. of variables tried at each split: 3 ## ## OOB estimate of error rate: 1.17% ## Confusion matrix: ## No Yes class.error ## No 6805 13 0.001906718 ## Yes 92 2090 0.042163153 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 20/24
Importance plot varimpplot(rf.fit,lwd=2,pch=19,cex=1.5,col="blue") file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 21/24
Validazione sul test set # Predict probabilities Pred.Pr.rf<-predict(rf.fit,HR.test,type="prob") # Predict class Pred.Class.rf<-predict(rf.fit,HR.test) # Classification table addmargins(table(hr.test$left,pred.class.rf)) ## Pred.Class.rf ## No Yes Sum ## No 4605 5 4610 ## Yes 48 1341 1389 ## Sum 4653 1346 5999 Errore test 0.0088 Sensitivita 0.9654 Specificita 0.9989 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 22/24
Curva ROC e AUC # ROC pred.rf <- prediction(pred.pr.rf[,2],hr.test$left) perf.rf <- performance(pred.rf, measure = "tpr", x.measure = "fpr") plot(perf.rf,colorize=true,lwd=4,main="roc Random Forest") #AUC Auc=performance(pred.rf, measure = "auc",fpr.stop=0.5) Auc@y.values[[1]][1] ## [1] 0.4933144 file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 23/24
Curve ROC - tutti i modelli plot(perf.glm, col="blue",lwd=4, main=" ROC Curves") plot(perf.tree, col="red",lwd=4,add=true) plot(perf.rf, col="green",lwd=4,add=true) legend(0.6,0.6,c('logistic','tree',"random Forest"), col=c('blue','red',"green"),lwd=4) file:///g:/il%20mio%20drive/2%20corsi/3%20sqg/labs/l10-hr_predictive.html#(1) 24/24