Задача

В своём проекте я буду решать задачу анализа и предотвращения оттока(увольнения) молодых сотрудников из компании. Для того, чтобы решить данную задачу необходимо найти факторы, которые оказали наибольшее влияние на принятие решения об увольнении сотрудника из компании, для того, чтобы поменять этот фактор, чтобы, найти сотрудников, у которых есть схожие факторы и предотвратить их увольнение, основываясь на опыте уже уволившихся сотрудников, чтобы снизить затраты компании на поиски нового сотрудника.

Анализ

Данные и логика анализа

Для своего проекта я изменила изначальную подгруппу и сейчас буду изучать отток молодых(18-35) сотрудников из компании и факторы, оказывающие наибольшее влияние на это. Была выбрана именно эта подгруппа, так как в последнее время компании начали нанимать как раз очень много молодых сотруднико и в некоторых компаниях это происходит не совсем успешно – сотруднкии увольняются достаточно быстро. Мне было бы интересно выяснить, что влияет на отток молодых сотрудников из компаний.

Для начала необходимо подключиться к базе данных. Для анализа мне будут необходимы две таблицы – portfolio & profile. В этих двух таблицах хранятся как личные данные о сотрудниках(например, возраст, статус и др), а также профессиональные данные – размер зарплаты, количество лет в компании и тд. Сперва проверим, одинаково ли распределено количество ушедших из компании сотрудников в моей подгруппе и в общей базе данных:

library(DBI)
library(kableExtra)
con <- dbConnect(ClickHouseHTTP::ClickHouseHTTP(), 
                 user='studentminor', 
                 password='DataMinorHSE!2023', 
                 dbname='employee', 
                 host='rc1a-i6ui9dhblsq8rgdo.mdb.yandexcloud.net',
                 port = 8443,
                 https=TRUE,
                 ssl_verifypeer=FALSE)

dbGetQuery(con, "SELECT Attrition, COUNT(Attrition) AS Occurence FROM profile
           INNER JOIN portfolio ON profile.EmployeeNumber = portfolio.EmployeeNumber
           WHERE Age BETWEEN 18 AND 35
           GROUP BY Attrition") %>%
  kable()%>%
  kable_styling(bootstrap_options=c("bordered", "responsive","striped"), full_width = FALSE)
Attrition Occurence
0 404
1 119
dbGetQuery(con, "SELECT Attrition, COUNT(Attrition) AS Occurence FROM
           portfolio
           GROUP BY Attrition") %>%
  kable()%>%
  kable_styling(bootstrap_options=c("bordered", "responsive","striped"), full_width = FALSE)
Attrition Occurence
0 879
1 179
dbGetQuery(con, "SELECT 
  ROUND(SUM(CASE WHEN Attrition = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS young_attrition_percent
FROM portfolio
INNER JOIN profile ON portfolio.EmployeeNumber = profile.EmployeeNumber
WHERE profile.Age BETWEEN 18 AND 35
") %>%
  kable()%>%
  kable_styling(bootstrap_options=c("bordered", "responsive","striped"), full_width = FALSE)
young_attrition_percent
22.75
dbGetQuery(con, "SELECT 
  ROUND(SUM(CASE WHEN Attrition = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS attrition_percent
FROM portfolio") %>%
  kable()%>%
  kable_styling(bootstrap_options=c("bordered", "responsive","striped"), full_width = FALSE)
attrition_percent
16.92

В целом, процент ушедших сотрудниках в подгруппе и в общих данных примерно одинаковый, с небольшим различием. Сохраним данные для выбранной подгруппы в отдельную таблицу, а также отключимся от базы, она нам более не нужна.

youth= dbGetQuery(con, "SELECT * FROM profile
           INNER JOIN portfolio ON profile.EmployeeNumber = portfolio.EmployeeNumber
           WHERE Age BETWEEN 18 AND 35")
dbDisconnect(con)

Модель

Для начала преобразуем все character в факторы и удалим дублирующуюся колонку с идентификационным номером сотрудника.

library(dplyr)
youth$Attrition[youth$Attrition == 1] = "Yes"
youth$Attrition[youth$Attrition == 0] = "No"
youth = youth %>% dplyr::select(-portfolio.EmployeeNumber) %>% mutate_if(is.character, as.factor)

Разделим данные на обучающую и тестовую выборки.

library(partykit)
library(tidymodels)
set.seed(100)
ind = initial_split(youth, prop = 0.8)
train = training(ind)
test = testing(ind)

Построим модель с помощью логистической регрессии, посмотрим на ее показатели:

model = logistic_reg()
logreg = model %>% fit(Attrition~., data = train)
predlog = predict(logreg, test)


test %>% 
  mutate(pred =predlog$.pred_class) %>% 
  conf_mat(estimate = pred, truth = Attrition) %>% 
  summary() %>%
  kable()%>%
  kable_styling(bootstrap_options=c("bordered", "responsive","striped"), full_width = FALSE)
.metric .estimator .estimate
accuracy binary 0.8476190
kap binary 0.5918367
sens binary 0.9220779
spec binary 0.6428571
ppv binary 0.8765432
npv binary 0.7500000
mcc binary 0.5949422
j_index binary 0.5649351
bal_accuracy binary 0.7824675
detection_prevalence binary 0.7714286
precision binary 0.8765432
recall binary 0.9220779
f_meas binary 0.8987342

В целом, модель достаточно хорошо справилась с предсказанием, точночть примерно 0.83. Теперь проверим важность признаков:

library(vip)
vip(logreg)

Наиболее важным признаком оказалось наличие переработок – чаще всего молодые сотрудники увольняются из-за наличия переработок. Посмотрим, можно ли с этим что-либо сделать.

Симуляция

Я предлагаю немного изменить политику в отношении переработок – добавим в данные чуть больше людей, у которых нет переработок, посмотрим как это повлияет на наши данные и предсказание. Предположим, что мы “избавили” от переработок 10% молодых сотрудников c переработками.

test2 = test

test2$OverTime[test2$OverTime == "Yes"] = 
  sample(c("Yes", "No"),
         size = length(test2$OverTime[test2$OverTime == "Yes"]),
         replace = T,
         prob = c(0.9, 0.1))

predTest = predict(logreg, test2)$.pred_class
predInitial = predict(logreg, test)$.pred_class
ggplot(data.frame(predTest)) + geom_bar(aes(x = predTest), alpha = 0.5, fill = "red") +
  geom_bar(data = test, aes(x = predInitial), alpha = 0.4, fill = "blue") +
  labs( x= "Предсказание", y ="Количество")

Как мы видим из графика, наше решение пошло на пользу компании – количество уволившихся сотрудников уменьшилось в сравнении с изначальными данными. Может быть мы можем сделать что-то еще? На основе анализа важности признаков можно заметить, что одной из немаловажных характеристик, на которые может повлиять работодатель является наличие/отсутствие командировок, в нашем случае важной является та часть молодых сотрудников, которые путешествуют часто. Возможно, это не совсем нравится молодым сотрудникам. Попробуем просто уменьшить количество сотрудников, которые часто путешествуют по работе, а также и уменьшить количество командировок, и количество переработок(то есть дополним наше предыдущее предложение)

test3 = test 
test3$BusinessTravel[test3$BusinessTravel == "Travel_Frequently"] = 
  sample(c("Travel_Rarely", "Non-Travel", "Travel_Frequently"), 
         size = length(test3$BusinessTravel[test3$BusinessTravel == "Travel_Frequently"]),
         replace = T, 
         prob = c(0.4,0.2,0.4))


test2$BusinessTravel[test2$BusinessTravel == "Travel_Frequently"] = 
  sample(c("Travel_Rarely", "Non-Travel", "Travel_Frequently"), 
         size = length(test2$BusinessTravel[test2$BusinessTravel == "Travel_Frequently"]),
         replace = T, 
         prob = c(0.4,0.2,0.4))

predTest = predict(logreg, test2)$.pred_class
predTest3 = predict(logreg, test3)$.pred_class

ggplot(data.frame(predTest)) + geom_bar(aes(x = predTest), alpha = 0.5, fill = "red") +
   geom_bar(data = data.frame(predTest3), aes(x = predTest3), alpha = 0.5, fill = "blue") +
  geom_bar(data = test, aes(x = predInitial), alpha = 0.5, fill = "yellow") +
    labs( x= "Предсказание", y ="Количество")

Из всех сотрудников, кто часто путешествует по работе я решила оставить 40% кто путешествует часто, 40% кто путешествует реже и 20% тех, кто не путешествует вовсе. Как мы видим, количество тех, кто остался в компании увеличилось даже в той симуляции, где мы уменьшаем только количество командировок, но все же – уменьшение переработок с одновременным уменьшением количества командировок все еще лучшее решение для того, чтобы сохранить как можно больше сотрудников.

Дэшборд

В дэшборде будет часть с симуляциями – для того, чтобы понять, какое из предложений по уменьшению оттока сотрудников лучше. Также в дэшборде будет часть с общим описанием данных – сколько уволившихся сотрудников в общей базе данных, сколько в конкретной подгруппе, а также сравнение подгруппы сотрудников по разным параметрам – наличию/отсутствию переработок, количеству командировок. Дэшборд преимущественно для работодателей, владельцев компании, HR менеджеров.

Общие выводы

В ходе работы был проведен анализ увольнения молодых сотрудников, выявлены факторы, влияющие на увольнение молодых сотрудников, а также были предложениы варианты улучшения ситуации в компании, чтобы уменьшить отток молодых сотрудников из компании.