library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
attrition_raw_tbl <- read_csv("../00_data/WA_Fn-UseC_-HR-Employee-Attrition.csv")
## Rows: 1470 Columns: 35
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (9): Attrition, BusinessTravel, Department, EducationField, Gender, Job...
## dbl (26): Age, DailyRate, DistanceFromHome, Education, EmployeeCount, Employ...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# If data is not sensitive:
attrition_raw_tbl %>% glimpse()
## Rows: 1,470
## Columns: 35
## $ Age <dbl> 41, 49, 37, 33, 27, 32, 59, 30, 38, 36, 35, 2…
## $ Attrition <chr> "Yes", "No", "Yes", "No", "No", "No", "No", "…
## $ BusinessTravel <chr> "Travel_Rarely", "Travel_Frequently", "Travel…
## $ DailyRate <dbl> 1102, 279, 1373, 1392, 591, 1005, 1324, 1358,…
## $ Department <chr> "Sales", "Research & Development", "Research …
## $ DistanceFromHome <dbl> 1, 8, 2, 3, 2, 2, 3, 24, 23, 27, 16, 15, 26, …
## $ Education <dbl> 2, 1, 2, 4, 1, 2, 3, 1, 3, 3, 3, 2, 1, 2, 3, …
## $ EducationField <chr> "Life Sciences", "Life Sciences", "Other", "L…
## $ EmployeeCount <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ EmployeeNumber <dbl> 1, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14, 15, 16,…
## $ EnvironmentSatisfaction <dbl> 2, 3, 4, 4, 1, 4, 3, 4, 4, 3, 1, 4, 1, 2, 3, …
## $ Gender <chr> "Female", "Male", "Male", "Female", "Male", "…
## $ HourlyRate <dbl> 94, 61, 92, 56, 40, 79, 81, 67, 44, 94, 84, 4…
## $ JobInvolvement <dbl> 3, 2, 2, 3, 3, 3, 4, 3, 2, 3, 4, 2, 3, 3, 2, …
## $ JobLevel <dbl> 2, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1, 1, …
## $ JobRole <chr> "Sales Executive", "Research Scientist", "Lab…
## $ JobSatisfaction <dbl> 4, 2, 3, 3, 2, 4, 1, 3, 3, 3, 2, 3, 3, 4, 3, …
## $ MaritalStatus <chr> "Single", "Married", "Single", "Married", "Ma…
## $ MonthlyIncome <dbl> 5993, 5130, 2090, 2909, 3468, 3068, 2670, 269…
## $ MonthlyRate <dbl> 19479, 24907, 2396, 23159, 16632, 11864, 9964…
## $ NumCompaniesWorked <dbl> 8, 1, 6, 1, 9, 0, 4, 1, 0, 6, 0, 0, 1, 0, 5, …
## $ Over18 <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", …
## $ OverTime <chr> "Yes", "No", "Yes", "Yes", "No", "No", "Yes",…
## $ PercentSalaryHike <dbl> 11, 23, 15, 11, 12, 13, 20, 22, 21, 13, 13, 1…
## $ PerformanceRating <dbl> 3, 4, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, 3, …
## $ RelationshipSatisfaction <dbl> 1, 4, 2, 3, 4, 3, 1, 2, 2, 2, 3, 4, 4, 3, 2, …
## $ StandardHours <dbl> 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 8…
## $ StockOptionLevel <dbl> 0, 1, 0, 0, 1, 0, 3, 1, 0, 2, 1, 0, 1, 1, 0, …
## $ TotalWorkingYears <dbl> 8, 10, 7, 8, 6, 8, 12, 1, 10, 17, 6, 10, 5, 3…
## $ TrainingTimesLastYear <dbl> 0, 3, 3, 3, 3, 2, 3, 2, 2, 3, 5, 3, 1, 2, 4, …
## $ WorkLifeBalance <dbl> 1, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, 2, 3, 3, …
## $ YearsAtCompany <dbl> 6, 10, 0, 8, 2, 7, 1, 1, 9, 7, 5, 9, 5, 2, 4,…
## $ YearsInCurrentRole <dbl> 4, 7, 0, 7, 2, 7, 0, 0, 7, 7, 4, 5, 2, 2, 2, …
## $ YearsSinceLastPromotion <dbl> 0, 1, 0, 3, 2, 3, 0, 0, 1, 7, 0, 0, 4, 1, 0, …
## $ YearsWithCurrManager <dbl> 5, 7, 0, 0, 2, 6, 0, 0, 8, 7, 3, 8, 3, 2, 3, …
# If data is sensitive:
attrition_raw_tbl %>%
slice(0) %>%
glimpse()
## Rows: 0
## Columns: 35
## $ Age <dbl>
## $ Attrition <chr>
## $ BusinessTravel <chr>
## $ DailyRate <dbl>
## $ Department <chr>
## $ DistanceFromHome <dbl>
## $ Education <dbl>
## $ EducationField <chr>
## $ EmployeeCount <dbl>
## $ EmployeeNumber <dbl>
## $ EnvironmentSatisfaction <dbl>
## $ Gender <chr>
## $ HourlyRate <dbl>
## $ JobInvolvement <dbl>
## $ JobLevel <dbl>
## $ JobRole <chr>
## $ JobSatisfaction <dbl>
## $ MaritalStatus <chr>
## $ MonthlyIncome <dbl>
## $ MonthlyRate <dbl>
## $ NumCompaniesWorked <dbl>
## $ Over18 <chr>
## $ OverTime <chr>
## $ PercentSalaryHike <dbl>
## $ PerformanceRating <dbl>
## $ RelationshipSatisfaction <dbl>
## $ StandardHours <dbl>
## $ StockOptionLevel <dbl>
## $ TotalWorkingYears <dbl>
## $ TrainingTimesLastYear <dbl>
## $ WorkLifeBalance <dbl>
## $ YearsAtCompany <dbl>
## $ YearsInCurrentRole <dbl>
## $ YearsSinceLastPromotion <dbl>
## $ YearsWithCurrManager <dbl>
I have a dataset called attrition_raw_tbl that looks like this.
attrition_raw_tbl %>% glimpse() Rows: 1,470 Columns: 35 $ Age
41, 49, 37, 33, 27, 32, 59, 30, 38, 36, 35, 29, 31, 34, 28, 29, 32, 22, 53, 38, 24, … $ Attrition “Yes”, “No”, “Yes”, “No”, “No”, “No”, “No”, “No”, “No”, “No”, “No”, “No”, “No”, “No”… $ BusinessTravel “Travel_Rarely”, “Travel_Frequently”, “Travel_Rarely”, “Travel_Frequently”, “Travel_… $ DailyRate 1102, 279, 1373, 1392, 591, 1005, 1324, 1358, 216, 1299, 809, 153, 670, 1346, 103, 1… $ Department ”Sales”, “Research & Development”, “Research & Development”, “Research & Development… $ DistanceFromHome 1, 8, 2, 3, 2, 2, 3, 24, 23, 27, 16, 15, 26, 19, 24, 21, 5, 16, 2, 2, 11, 9, 7, 15, … $ Education 2, 1, 2, 4, 1, 2, 3, 1, 3, 3, 3, 2, 1, 2, 3, 4, 2, 2, 4, 3, 2, 4, 4, 2, 1, 3, 1, 4, … $ EducationField ”Life Sciences”, “Life Sciences”, “Other”, “Life Sciences”, “Medical”, “Life Science… $ EmployeeCount 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, … $ EmployeeNumber 1, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28… $ EnvironmentSatisfaction 2, 3, 4, 4, 1, 4, 3, 4, 4, 3, 1, 4, 1, 2, 3, 2, 1, 4, 1, 4, 1, 3, 1, 3, 2, 3, 2, 3, … $ Gender ”Female”, “Male”, “Male”, “Female”, “Male”, “Male”, “Female”, “Male”, “Male”, “Male”… $ HourlyRate 94, 61, 92, 56, 40, 79, 81, 67, 44, 94, 84, 49, 31, 93, 50, 51, 80, 96, 78, 45, 96, … $ JobInvolvement 3, 2, 2, 3, 3, 3, 4, 3, 2, 3, 4, 2, 3, 3, 2, 4, 4, 4, 2, 3, 4, 2, 3, 3, 3, 3, 1, 3, … $ JobLevel 2, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1, 1, 3, 1, 1, 4, 1, 2, 1, 3, 1, 1, 5, 1, 2, … $ JobRole “Sales Executive”, “Research Scientist”, “Laboratory Technician”, “Research Scientis… $ JobSatisfaction 4, 2, 3, 3, 2, 4, 1, 3, 3, 3, 2, 3, 3, 4, 3, 1, 2, 4, 4, 4, 3, 1, 2, 4, 1, 3, 1, 2, … $ MaritalStatus ”Single”, “Married”, “Single”, “Married”, “Married”, “Single”, “Married”, “Divorced”… $ MonthlyIncome 5993, 5130, 2090, 2909, 3468, 3068, 2670, 2693, 9526, 5237, 2426, 4193, 2911, 2661, … $ MonthlyRate 19479, 24907, 2396, 23159, 16632, 11864, 9964, 13335, 8787, 16577, 16479, 12682, 151… $ NumCompaniesWorked 8, 1, 6, 1, 9, 0, 4, 1, 0, 6, 0, 0, 1, 0, 5, 1, 0, 1, 2, 5, 0, 7, 0, 1, 2, 4, 1, 0, … $ Over18 “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”, “Y”,… $ OverTime “Yes”, “No”, “Yes”, “Yes”, “No”, “No”, “Yes”, “No”, “No”, “No”, “No”, “Yes”, “No”, “… $ PercentSalaryHike 11, 23, 15, 11, 12, 13, 20, 22, 21, 13, 13, 12, 17, 11, 14, 11, 12, 13, 16, 11, 18, … $ PerformanceRating 3, 4, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, … $ RelationshipSatisfaction 1, 4, 2, 3, 4, 3, 1, 2, 2, 2, 3, 4, 4, 3, 2, 3, 4, 2, 3, 3, 4, 2, 3, 4, 3, 4, 2, 4, … $ StandardHours 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, … $ StockOptionLevel 0, 1, 0, 0, 1, 0, 3, 1, 0, 2, 1, 0, 1, 1, 0, 1, 2, 2, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, … $ TotalWorkingYears 8, 10, 7, 8, 6, 8, 12, 1, 10, 17, 6, 10, 5, 3, 6, 10, 7, 1, 31, 6, 5, 10, 13, 0, 8, … $ TrainingTimesLastYear 0, 3, 3, 3, 3, 2, 3, 2, 2, 3, 5, 3, 1, 2, 4, 1, 5, 2, 3, 3, 5, 4, 4, 6, 2, 3, 5, 2, … $ WorkLifeBalance 1, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, 2, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, 3, 3, 2, 3, 3, … $ YearsAtCompany 6, 10, 0, 8, 2, 7, 1, 1, 9, 7, 5, 9, 5, 2, 4, 10, 6, 1, 25, 3, 4, 5, 12, 0, 4, 14, 1… $ YearsInCurrentRole 4, 7, 0, 7, 2, 7, 0, 0, 7, 7, 4, 5, 2, 2, 2, 9, 2, 0, 8, 2, 2, 3, 6, 0, 2, 13, 2, 7,… $ YearsSinceLastPromotion 0, 1, 0, 3, 2, 3, 0, 0, 1, 7, 0, 0, 4, 1, 0, 8, 0, 0, 3, 1, 1, 0, 2, 0, 1, 4, 6, 4, … $ YearsWithCurrManager 5, 7, 0, 0, 2, 6, 0, 0, 8, 7, 3, 8, 3, 2, 3, 8, 5, 0, 7, 2, 3, 3, 11, 0, 3, 8, 7, 2,…
The goal is to help predict attrition for employees.
Please write R code to create a predictive model that predicts the probability of attrition.
Please update the code to use tidymodels instead of caret and to use the h2o model instead of glmnet. # Load required libraries library(tidymodels) library(tidyverse) library(h2o)
h2o.init()
attrition_raw_tbl <- attrition_raw_tbl %>% mutate(Attrition = as.factor(Attrition))
attrition_cleaned_tbl <- attrition_raw_tbl %>% select(-c(EmployeeCount, EmployeeNumber, Over18, StandardHours))
set.seed(123) # For reproducibility data_split <- initial_split(attrition_cleaned_tbl, prop = 0.7, strata = Attrition) train_data <- training(data_split) test_data <- testing(data_split)
attrition_recipe <- recipe(Attrition ~ ., data = train_data) %>% step_dummy(all_nominal_predictors()) %>% # Convert categorical variables to dummy variables step_normalize(all_numeric_predictors()) # Normalize numeric predictors
h2o_model_spec <- boost_tree( mode = “classification”, trees = 1000, tree_depth = 6, learn_rate = 0.01 ) %>% set_engine(“h2o”, max_runtime_secs = 300)
attrition_workflow <- workflow() %>% add_recipe(attrition_recipe) %>% add_model(h2o_model_spec)
set.seed(123) attrition_fit <- fit(attrition_workflow, data = train_data)
test_predictions <- predict(attrition_fit, test_data, type = “prob”) %>% bind_cols(predict(attrition_fit, test_data)) %>% bind_cols(test_data)
metrics <- test_predictions %>% metrics(truth = Attrition, estimate = .pred_class, .pred_Yes)
print(metrics)
roc_curve <- test_predictions %>% roc_curve(truth = Attrition, .pred_Yes) %>% autoplot()
print(roc_curve)
h2o.shutdown(prompt = FALSE)
! parsnip could not locate an implementation for
boost_tree
classification model specifications using the
h2o
engine. ℹ The parsnip extension package agua implements
support for this specification. ℹ Please install (if needed) and load to
continue.
library(tidymodels) library(tidyverse) library(h2o)
h2o.init()
attrition_raw_tbl <- attrition_raw_tbl %>% mutate(Attrition = as.factor(Attrition))
attrition_cleaned_tbl <- attrition_raw_tbl %>% select(-c(EmployeeCount, EmployeeNumber, Over18, StandardHours))
set.seed(123) data_split <- initial_split(attrition_cleaned_tbl, prop = 0.7, strata = Attrition) train_data <- training(data_split) test_data <- testing(data_split)
h2o_train <- as.h2o(train_data) h2o_test <- as.h2o(test_data)
response <- “Attrition” predictors <- setdiff(names(train_data), response)
h2o_model <- h2o.gbm( x = predictors, y = response, training_frame = h2o_train, ntrees = 1000, max_depth = 6, learn_rate = 0.01, seed = 123 )
h2o_predictions <- h2o.predict(h2o_model, h2o_test) h2o_test_with_preds <- h2o_test %>% as.data.frame() %>% mutate( Predicted = as.factor(h2o_predictions\(predict), Prob_Yes = as.numeric(h2o_predictions\)Yes) )
metrics <- h2o_test_with_preds %>% metrics(truth = Attrition, estimate = Predicted)
print(metrics)
roc_curve <- h2o_test_with_preds %>% roc_curve(truth = Attrition, Prob_Yes) %>% autoplot()
print(roc_curve)
h2o.shutdown(prompt = FALSE)
# Load required libraries
library(tidymodels)
## ── Attaching packages ────────────────────────────────────── tidymodels 1.2.0 ──
## ✔ broom 1.0.5 ✔ rsample 1.2.1
## ✔ dials 1.2.1 ✔ tune 1.2.1
## ✔ infer 1.0.7 ✔ workflows 1.1.4
## ✔ modeldata 1.4.0 ✔ workflowsets 1.1.0
## ✔ parsnip 1.2.1 ✔ yardstick 1.3.1
## ✔ recipes 1.0.10
## Warning: package 'modeldata' was built under R version 4.3.3
## ── Conflicts ───────────────────────────────────────── tidymodels_conflicts() ──
## ✖ scales::discard() masks purrr::discard()
## ✖ dplyr::filter() masks stats::filter()
## ✖ recipes::fixed() masks stringr::fixed()
## ✖ dplyr::lag() masks stats::lag()
## ✖ yardstick::spec() masks readr::spec()
## ✖ recipes::step() masks stats::step()
## • Dig deeper into tidy modeling with R at https://www.tmwr.org
library(tidyverse)
library(h2o)
##
## ----------------------------------------------------------------------
##
## Your next step is to start H2O:
## > h2o.init()
##
## For H2O package documentation, ask for help:
## > ??h2o
##
## After starting H2O, you can use the Web UI at http://localhost:54321
## For more information visit https://docs.h2o.ai
##
## ----------------------------------------------------------------------
##
## Attaching package: 'h2o'
## The following objects are masked from 'package:lubridate':
##
## day, hour, month, week, year
## The following objects are masked from 'package:stats':
##
## cor, sd, var
## The following objects are masked from 'package:base':
##
## &&, %*%, %in%, ||, apply, as.factor, as.numeric, colnames,
## colnames<-, ifelse, is.character, is.factor, is.numeric, log,
## log10, log1p, log2, round, signif, trunc
# Initialize H2O
h2o.init()
##
## H2O is not running yet, starting it now...
##
## Note: In case of errors look at the following log files:
## /var/folders/yp/l2lglnf55llfxv0njn7m_ydr0000gr/T//RtmpZQeVgE/file10b82f369782/h2o_kajsabergstrand_started_from_r.out
## /var/folders/yp/l2lglnf55llfxv0njn7m_ydr0000gr/T//RtmpZQeVgE/file10b824914df9b/h2o_kajsabergstrand_started_from_r.err
##
##
## Starting H2O JVM and connecting: ...... Connection successful!
##
## R is connected to the H2O cluster:
## H2O cluster uptime: 6 seconds 370 milliseconds
## H2O cluster timezone: America/New_York
## H2O data parsing timezone: UTC
## H2O cluster version: 3.44.0.3
## H2O cluster version age: 11 months and 15 days
## H2O cluster name: H2O_started_from_R_kajsabergstrand_jth211
## H2O cluster total nodes: 1
## H2O cluster total memory: 1.77 GB
## H2O cluster total cores: 4
## H2O cluster allowed cores: 4
## H2O cluster healthy: TRUE
## H2O Connection ip: localhost
## H2O Connection port: 54321
## H2O Connection proxy: NA
## H2O Internal Security: FALSE
## R Version: R version 4.3.2 (2023-10-31)
## Warning in h2o.clusterInfo():
## Your H2O cluster version is (11 months and 15 days) old. There may be a newer version available.
## Please download and install the latest version from: https://h2o-release.s3.amazonaws.com/h2o/latest_stable.html
# Step 1: Data preprocessing
attrition_raw_tbl <- attrition_raw_tbl %>%
mutate(Attrition = as.factor(Attrition))
attrition_cleaned_tbl <- attrition_raw_tbl %>%
select(-c(EmployeeCount, EmployeeNumber, Over18, StandardHours))
# Step 2: Train-test split
set.seed(123)
data_split <- initial_split(attrition_cleaned_tbl, prop = 0.7, strata = Attrition)
train_data <- training(data_split)
test_data <- testing(data_split)
# Step 3: Prepare data for H2O
h2o_train <- as.h2o(train_data)
##
|
| | 0%
|
|======================================================================| 100%
h2o_test <- as.h2o(test_data)
##
|
| | 0%
|
|======================================================================| 100%
# Define response and predictor columns
response <- "Attrition"
predictors <- setdiff(names(train_data), response)
# Step 4: Train H2O GBM model
h2o_model <- h2o.gbm(
x = predictors,
y = response,
training_frame = h2o_train,
ntrees = 1000,
max_depth = 6,
learn_rate = 0.01,
seed = 123
)
## Warning in .h2o.processResponseWarnings(res): Dropping bad and constant columns: [JobRole, MaritalStatus, BusinessTravel, Department, OverTime, Gender, EducationField].
##
|
| | 0%
|
|= | 2%
|
|==== | 6%
|
|============ | 17%
|
|============= | 19%
|
|======================= | 32%
|
|==================================== | 51%
|
|====================================================== | 77%
|
|======================================================================| 99%
|
|======================================================================| 100%
# Step 5: Evaluate the model on test data
# Convert predictions to data frame
h2o_predictions <- as.data.frame(h2o.predict(h2o_model, h2o_test))
##
|
| | 0%
|
|======================================================================| 100%
# Combine predictions with test data
h2o_test_with_preds <- as.data.frame(h2o_test) %>%
mutate(
Predicted = as.factor(h2o_predictions$predict),
Prob_Yes = as.numeric(h2o_predictions$Yes)
)
# Calculate metrics
metrics <- h2o_test_with_preds %>%
metrics(truth = Attrition, estimate = Predicted)
print(metrics)
## # A tibble: 2 × 3
## .metric .estimator .estimate
## <chr> <chr> <dbl>
## 1 accuracy binary 0.837
## 2 kap binary 0.158
# Optional: Plot ROC curve
roc_curve <- h2o_test_with_preds %>%
roc_curve(truth = Attrition, Prob_Yes) %>%
autoplot()
print(roc_curve)
# Shut down H2O instance
h2o.shutdown(prompt = FALSE)