This report presents an analysis of the IBM HR Analytics Employee Attrition & Performance dataset from Kaggle. The primary objective is to understand the factors contributing to employee attrition and performance within the organization.
Data cleaning involved removing columns with fixed values, unused values and handling missing data. The cleaned dataset was then used for further analysis and visualization.
# load data in 'global' chunk so it can be shared by all users of the dashboard
library(tidyverse)
## Warning: le package 'tidyverse' a été compilé avec la version R 4.3.3
## Warning: le package 'ggplot2' a été compilé avec la version R 4.3.3
## Warning: le package 'tibble' a été compilé avec la version R 4.3.3
## Warning: le package 'tidyr' a été compilé avec la version R 4.3.3
## Warning: le package 'readr' a été compilé avec la version R 4.3.3
## Warning: le package 'purrr' a été compilé avec la version R 4.3.3
## Warning: le package 'dplyr' a été compilé avec la version R 4.3.3
## Warning: le package 'stringr' a été compilé avec la version R 4.3.3
## Warning: le package 'forcats' a été compilé avec la version R 4.3.3
## Warning: le package 'lubridate' a été compilé avec la version R 4.3.3
## ── 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
library(ggplot2)
library(DT)
## Warning: le package 'DT' a été compilé avec la version R 4.3.3
# read data
data <- readr::read_csv("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.
# find the columns with fixed values
fixed_value_columns <- sapply(data, function(col) length(unique(col))) == 1
fixed_value_columns_names <- names(fixed_value_columns)[fixed_value_columns]
# Remove columns with fixed values
df_cleaned <- data[, !fixed_value_columns]
df_cleaned <- data[, -which(names(data) == "EmployeeNumber")] #we have no use for this
#filter data based on Attrition
d1<-filter(df_cleaned,Attrition=="Yes");
d2<-filter(df_cleaned,Attrition=="No");
This section examines the characteristics of employees who have left the company.
#visualise data where Attrition= Yes
datatable(d1,options = list(scrollX = TRUE))
#Analysis where Attrition= Yes
#display the number of employees that have left in each department
d1 %>%
group_by(Department) %>%
summarise(nb = n())
#display by gender
d1 %>%
group_by(Gender) %>%
summarise(nb = n())
#by age
d1 %>%
group_by(Age) %>%
summarise(nb = n())
#by Education
d1 %>%
group_by(Education) %>%
summarise(nb = n())
#by DistanceFromHome
d1 %>%
group_by(DistanceFromHome) %>%
count()
#by BusinessTravel
d1 %>%
group_by(BusinessTravel) %>%
summarise(count = n()) %>%
mutate(percentage = count / sum(count) * 100)
#By Business travel and Department
d1 %>%
group_by(BusinessTravel, Department, .drop = FALSE) %>%
summarise(count = n(), .groups = 'drop_last') %>%
mutate(percentage = count / sum(count) * 100)
#BY Gender and department
d1 %>%
group_by(Gender, Department, .drop = FALSE) %>%
summarise(count = n(), .groups = 'drop_last') %>%
mutate(percentage = count / sum(count) * 100)
# By department and jobrole
d1 %>%
group_by(Department,JobRole , .drop = FALSE) %>%
summarise(count = n(), .groups = 'drop_last') %>%
mutate(percentage = count / sum(count) * 100)
#By MONTHLY INCOME
rates1<-d1
rates1$MonthlyIncome <- as.numeric(as.character(rates1$MonthlyIncome))
# Create a new column 'IncomeCategory' based on MonthlyIncome ranges
rates1$IncomeCategory <- cut(rates1$MonthlyIncome,
breaks = c(1000, 2500,5000, 10000, 15000, Inf),
labels = c('[1000-2500]','[2500-5000]', '[5000-10000]', '[10000-15000]', '[15000+]'),
right = FALSE)
rates2<- rates1 %>% count(IncomeCategory)
rates2
Analyze and visualize the data for employees who stayed with the company.
datatable(d2,options = list(scrollX = TRUE))
d1 <- d2
#display the number of employees that have Stayed in each department
d1 %>%
group_by(Department) %>%
summarise(nb = n())
#display by gender
d1 %>%
group_by(Gender) %>%
summarise(nb = n())
#by age
d1 %>%
group_by(Age) %>%
summarise(nb = n())
#by Education
d1 %>%
group_by(Education) %>%
summarise(nb = n())
#by DistanceFromHome
d1 %>%
group_by(DistanceFromHome) %>%
count()
#by BusinessTravel
d1 %>%
group_by(BusinessTravel) %>%
summarise(count = n()) %>%
mutate(percentage = count / sum(count) * 100)
#By Business travel and Department
d1 %>%
group_by(BusinessTravel, Department, .drop = FALSE) %>%
summarise(count = n(), .groups = 'drop_last') %>%
mutate(percentage = count / sum(count) * 100)
#BY Gender and department
d1 %>%
group_by(Gender, Department, .drop = FALSE) %>%
summarise(count = n(), .groups = 'drop_last') %>%
mutate(percentage = count / sum(count) * 100)
# By department and jobrole
d1 %>%
group_by(Department,JobRole , .drop = FALSE) %>%
summarise(count = n(), .groups = 'drop_last') %>%
mutate(percentage = count / sum(count) * 100)
#By MONTHLY INCOME
rates1<-d1
rates1$MonthlyIncome <- as.numeric(as.character(rates1$MonthlyIncome))
# Create a new column 'IncomeCategory' based on MonthlyIncome ranges
rates1$IncomeCategory <- cut(rates1$MonthlyIncome,
breaks = c(1000, 2500,5000, 10000, 15000, Inf),
labels = c('[1000-2500]','[2500-5000]', '[5000-10000]', '[10000-15000]', '[15000+]'),
right = FALSE)
rates2<- rates1 %>% count(IncomeCategory)
rates2
Comparative visualizations, such as histograms and density plots, were created to illustrate differences in attributes like age and monthly income between employees who left and those who remained. These visual insights assist in identifying significant factors related to attrition.
data1<-d1
ggplot(data1) +
geom_histogram(aes(x = Age ,fill = Attrition), binwidth = 1.5, color="black" )
ggplot(data, aes(x = Age, fill = Attrition)) + geom_density(alpha = 0.5)
ggplot(data1, aes(x = Department, fill = Attrition)) + geom_bar(width = 1) + coord_polar(theta = "y")
ggplot(data1, aes(x = Gender, fill = Attrition)) + geom_bar(width = 1) + coord_polar(theta = "y")
ggplot(data, aes(x = Attrition, y = MonthlyIncome, fill = Attrition)) + geom_boxplot()
ggplot(data1) +
geom_histogram(aes(x = DistanceFromHome ),fill = "orange", color = "black")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
In conclusion, this analysis sheds light on the critical factors influencing employee attrition at IBM. By addressing the identified issues, the company can improve retention rates and enhance overall employee satisfaction and performance.