Introduction

This dataset examines employee satisfaction and workplace dynamics across 3,025 responses from a fictional company. It includes information on demographics, job role, work-life balance, and more. The goal is to identify factors that influence employee job satisfaction using statistical techniques such as Chi-square tests, ANOVA, and regression analysis.


Dataset

The employee_survey dataset uses a synthetically made survey that a fictional company recorded the responses of their employees in regards to job satisfaction and overall happiness. Available here on kaggle:

https://www.kaggle.com/datasets/lainguyn123/employee-survey/data

The dataset contains a total of 3,025 records.

R-packages Used

library(readxl) # Load library for reading Excel files
library(dplyr)  # Data manipulation
library(ggplot2) # Plotting
library(corrplot) # Correlation matrix visual
library(knitr) #Table rendering
library(gridExtra) 

Data Exploration

The employee_survey contains 23 answer columns and a total of 3,025 recorded responses. For this project I’ll be using just 8 answer columns as my variables

  1. Gender (Gender) — Categorical variable representing the gender the employee identifies as.

  2. Age (Age) — Continuous variable measuring the age of the employee.

  3. Job Level (JbL) — Categorical variable indicating the employee’s job level (e.g., Intern/Fresher, Junior, Mid, Senior, Lead).

  4. Experience (Exp) — Continuous variable measuring the number of years of work experience the employee has.

  5. Department (Dept) — Categorical variable indicating the department where the employee works.

  6. Work-Life Balance (WLB) — Ordinal variable (1–5) indicating the employee’s perception of work-life balance, with 1 being poor and 5 being excellent.

  7. Work Environment (WkEnv) — Ordinal variable (1–5) representing the perceived quality of the employee’s work environment, from 1 (Very Poor) to 5 (Excellent).

  8. Work Load (WkLd) — Ordinal variable (1–5) indicating the employee’s perception of their workload:

    • 1 = Very Light
    • 2 = Light
    • 3 = Moderate
    • 4 = Heavy
    • 5 = Overwhelming
  9. Stress (Stress) — Ordinal variable (1–5) representing the employee’s reported level of stress.

  10. Sleep Hours (SleepH) — Continuous variable representing the average number of hours of sleep the employee reports.

  11. Training Hours Per Year (THPY) — Continuous variable measuring the number of training hours the employee receives annually.

  12. Job Satisfaction (JobSat) — Ordinal variable (1–5) representing how satisfied an employee feels with their job.

Reading the Data

#Loading the data set
emp_data <- read_excel("employee_survey.xlsx", sheet = "employee_survey (2)")

Data cleaning

#Converting categorical variables to factors
emp_data$Gender <- as.factor(emp_data$Gender) # Unordered factor
emp_data$JbL <- factor(emp_data$JbL, ordered = TRUE, levels = c("Intern/Fresher", "Junior", "Mid", "Senior", "Lead"))
emp_data$Dept <- as.factor(emp_data$Dept) # Unordered factor (categorical department names)
emp_data$WLB  <- factor(emp_data$WLB, levels = 1:5, ordered = TRUE)  # 1 = Worst, 5 = Best
emp_data$WkEnv <- factor(emp_data$WkEnv, levels = 1:5, ordered = TRUE) # Work Environment Rating
emp_data$WkLd <- factor(emp_data$WkLd, levels = 1:5, ordered = TRUE) # Work Load
emp_data$Stress <- factor(emp_data$Stress, levels = 1:5, ordered = TRUE) # Stress Level
emp_data$JobSat <- factor(emp_data$JobSat, levels = 1:5, ordered = TRUE) # Job Satisfaction

#Creating a vector of all the columns I'm using
selected_cols <- emp_data %>%
  select(EmpID, Gender, Age, JbL, Exp, Dept, WLB, WkEnv, WkLd, Stress, SleepH, THPY, JobSat)

#Creating vector of numeric columns
numeric_cols <- selected_cols %>%
  select(Age, Exp, SleepH, THPY)

Columns

#selected_cols <- emp_data %>%
  #select(Gender, Age, JbL, Exp, Dept, WLB, WkEnv, WkLd, Stress, SleepH, THPY, JobSat)
summary(selected_cols)
##      EmpID         Gender          Age                    JbL      
##  Min.   :   1   Female:1240   Min.   :22.00   Intern/Fresher: 202  
##  1st Qu.: 757   Male  :1528   1st Qu.:27.00   Junior        : 602  
##  Median :1513   Other : 257   Median :34.00   Mid           : 766  
##  Mean   :1513                 Mean   :35.74   Senior        :1069  
##  3rd Qu.:2269                 3rd Qu.:43.00   Lead          : 386  
##  Max.   :3025                 Max.   :60.00                        
##                                                                    
##       Exp                 Dept     WLB     WkEnv   WkLd    Stress  
##  Min.   : 0.000   IT        :774   1:618   1:580   1:614   1:1809  
##  1st Qu.: 3.000   Finance   :637   2:554   2:604   2:618   2: 535  
##  Median : 8.000   Operations:455   3:549   3:631   3:610   3: 426  
##  Mean   : 9.083   Marketing :316   4:633   4:568   4:621   4: 179  
##  3rd Qu.:14.000   Sales     :281   5:671   5:642   5:562   5:  76  
##  Max.   :29.000   Legal     :272                                   
##                   (Other)   :290                                   
##      SleepH            THPY      JobSat  
##  Min.   : 4.000   Min.   :10.0   1: 417  
##  1st Qu.: 6.300   1st Qu.:23.5   2: 277  
##  Median : 7.000   Median :40.0   3: 566  
##  Mean   : 7.006   Mean   :37.3   4:1249  
##  3rd Qu.: 7.700   3rd Qu.:46.5   5: 516  
##  Max.   :10.000   Max.   :64.5           
## 

Correlation Matrix for continous variables

# Round and print as table
cor_matrix <- cor(numeric_cols, use = "complete.obs")

# Plot the correlation matrix
corrplot(cor_matrix, method = "circle", type = "lower",
         tl.col = "black", tl.srt = 45, addCoef.col = "black", number.cex = 0.7)

Observations

The correlation matrix reveals several positive relationships between Age, Experience, and TrainingHoursPerYear, indicating that older or more experienced employees tend to receive more training. However, SleepHours shows no significant linear relationship with any of the variables analyzed.

library(knitr)

# Creating a data frame with interpretation
cor_summary <- data.frame(
  `Variable Pair` = c(
    "Age vs Exp",
    "Age vs THPY",
    "Exp vs THPY",
    "SleepH with others"
  ),
  Correlation = c(0.69, 0.81, 0.74, "~0"),
  Interpretation = c(
    "Positive — older employees tend to have more experience",
    "Very strong postive — older employees likely recive more training hours per year",
    "Postive — more experienced staff likely receive more training",
    "No linear relationship — sleep hours are independent of age, experience, and THPY."
  )
)

# Display using kable
kable(cor_summary, caption = "Summary of Key Correlation Findings")
Summary of Key Correlation Findings
Variable.Pair Correlation Interpretation
Age vs Exp 0.69 Positive — older employees tend to have more experience
Age vs THPY 0.81 Very strong postive — older employees likely recive more training hours per year
Exp vs THPY 0.74 Postive — more experienced staff likely receive more training
SleepH with others ~0 No linear relationship — sleep hours are independent of age, experience, and THPY.

Test 1: Is there any association between job level (JbL) and stress?

To determine if there is an association between these two categorical variables, a Chi-squared test will be used. The Null Hypothesis usually states there is no association between stress level and employee type.

#Summary of Job Level 
summary(selected_cols$JbL)
## Intern/Fresher         Junior            Mid         Senior           Lead 
##            202            602            766           1069            386
#summary of Stress Level
summary(selected_cols$Stress)
##    1    2    3    4    5 
## 1809  535  426  179   76

Visualizing the Data

ggplot(emp_data, aes(x = Stress, fill = JbL)) +
  geom_bar(position = "dodge") +
  labs(
    title = "Distribution of Job Levels Across Stress Ratings",
    x = "Stress Level (1 = Low, 5 = High)",
    y = "Number of Employees",
    fill = "Job Level"
  ) +
  theme_minimal() +
  scale_fill_brewer(palette = "Set2")

The bar plot suggests a potential association between Job Level and reported Stress levels. Most Senior and Mid-level employees report low stress, while Interns and Junior employees appear more evenly spread across the stress spectrum. A Chi-square test can confirm whether this observed pattern is statistically significant.

Chi-Squared Test for association between Stress and JbL

#Performing Chi-Square Test
chi_sq_test <- chisq.test(table(emp_data$Stress, emp_data$JbL), simulate.p.value = TRUE)

#Results
chi_sq_test
## 
##  Pearson's Chi-squared test with simulated p-value (based on 2000
##  replicates)
## 
## data:  table(emp_data$Stress, emp_data$JbL)
## X-squared = 12.861, df = NA, p-value = 0.6977

Observation

With a p-value ≥ 0.05, we fail to reject the null hypothesis, suggesting that there is not a statistically significat association between Job Level and Stress Level.

Test 1.2 Is there any association between Stress and Job Satisfaction?

ggplot(emp_data, aes(x = Stress, fill = JobSat)) +
  geom_bar(position = "dodge") +
  labs(
    title = "Distribution of Job Satisfaction Across Stress Levels",
    x = "Stress Level (1 = Low, 5 = High)",
    y = "Number of Employees",
    fill = "Job Satisfaction"
  ) +
  theme_minimal() +
  scale_fill_brewer(palette = "Spectral")

The barplot suggests a potential association between an employee’s percieved level of stress and job satisfaction.

Chi-Square test for Stress and Job Satisfaction

#Performing Chi-Square test
chi_sq_jb <- chisq.test(table(emp_data$Stress, emp_data$JobSat), simulate.p.value = TRUE)

#Results
chi_sq_jb
## 
##  Pearson's Chi-squared test with simulated p-value (based on 2000
##  replicates)
## 
## data:  table(emp_data$Stress, emp_data$JobSat)
## X-squared = 195.7, df = NA, p-value = 0.0004998

Observation

With a p-value < 0.05, this Chi-Square test indicates that we can reject the null hypothesis. Which means there is strong evidence to suggest a relationship or association exists between Stress and Job Satisfaction.

Test 2: Is there a significant difference in Sleep Hours (SleepH) across different gender groups (Gender)?

A One-way ANOVA test will be used to compare the means of Sleep Hours (SleepH) across different gender groups (Gender).

A One-way ANOVA uses one categorical (nominal or ordinal) independent variable and one continuous (interval or ratio) dependent variable to determine if there is a statistically significant difference in the means of the dependent variable across the different levels of the independent variable.


Independent Variable:
- Gender
- Categorical: It categorizes subjects into three groups — Male, Female, and Other.
- Satisfies the requirement of having at least two levels.

Dependent Variable:
- SleepH (Sleep Hours)
- Continuous: It represents the average number of hours an employee reports sleeping, ranging across a numerical scale.


This test will determine whether there is a statistically significant difference in average sleep duration across gender identities within the company.

Visualizing the Variables

# Visualize Data
ggplot(emp_data, aes(x = Gender, y = SleepH, fill = Gender)) +
  geom_boxplot() +
  labs(title = "Sleep Hours by Gender", x = "Gender", y = "Average Sleep Hours") +
  theme_minimal()

Because the boxes do overlap much, the boxplot suggests there is no significant difference in SleepH between the groups.

One-way ANOVA Test

For a one-way ANOVA, the The Null Hypothesis states that the mean sleep hours for all gender groups are equal, while the Alternative Hypothesis states at least one group mean is different from the others.

#Perform one-way ANOVA
anova_gender_sleep <- aov(SleepH ~ Gender, data = emp_data)

#Output the results
summary(anova_gender_sleep)
##               Df Sum Sq Mean Sq F value Pr(>F)
## Gender         2      2  0.9887   0.983  0.374
## Residuals   3022   3038  1.0053

Observation

Based on the ANOVA output, the test produced an F-statistic of 0.983 with a corresponding p-value of 0.374.

Since the p-value is greater than 0.05, we fail to reject the null hypothesis. This suggests that there is no statistically significant difference in average Sleep Hours (SleepH) across the three gender groups (Gender).

In other words, the data does not provide sufficient evidence to conclude that gender identity is associated with different sleep durations among employees in this dataset.

Test 3: Is there a significant difference in Stress levels based on Work Load and Work Environment?

A two-way ANOVA will be used to analyze whether the average Stress (treated as numeric) differs based on levels of WkEnv and WkLd. Both WkLd and WkEnv are treated as categorical grouping variables with 5 levels (1–5).

Dependent Variable: - Stress (treated as numeric for this test)

Independent Variables: - WkLd (Work Load, ordinal) - WkEnv (Work Environment, ordinal)

The two-way ANOVA tests: 1. Whether WkLd affects Stress 2. Whether WkEnv affects Stress 3. Whether there’s an interaction effect between them ### Visualization

# Create the interaction plot (NOTE THAT STRESS IS BEING TREATED AS NUMERIC FOR THIS TEST)
interaction.plot(
  x.factor = emp_data$WkEnv,
  trace.factor = emp_data$WkLd,
  response = as.numeric(emp_data$Stress),
  fun = mean,
  type = "b",
  legend = TRUE,
  xlab = "Work Environment (1 = Poor, 5 = Excellent)",
  ylab = "Mean Stress Level",
  trace.label = "Work Load Level",
  col = rainbow(5),
  pch = 16,
  main = "Interaction Plot: Work Environment x Work Load on Stress"
)

The interaction plot suggests that stress levels are influenced by both WkLd and WkEnv, with strong evidence from crossing-lines suggesting a strong interaction event.

Two-way ANOVA Test

In a Two-Way ANOVA, we test several hypotheses to understand the effects of two factors and their interaction on a dependent variable. Here are the hypotheses involved:

-Null Hypotheses (H₀):

-There is no difference in mean stress levels across different levels of Work Load.

-There is no difference in mean stress levels across different levels of Work Environment.

-There is no interaction between Work Load and Work Environment on stress.

Alternative Hypotheses (H₁):

-At least one level of Work Load has a different mean stress level.

-At least one level of Work Environment has a different mean stress level.

-There is an interaction effect between Work Load and Work Environment on stress.

# Perform two way ANOVA
anova_stress <- aov(as.numeric(Stress) ~ WkLd * WkEnv, data = emp_data)

# Output findings
summary(anova_stress)
##               Df Sum Sq Mean Sq F value Pr(>F)
## WkLd           4      2   0.473   0.417  0.796
## WkEnv          4      3   0.789   0.696  0.594
## WkLd:WkEnv    16     21   1.301   1.149  0.303
## Residuals   3000   3399   1.133

Observation

Since all p-values are greater than 0.05, we fail to reject the null hypotheses. This suggests that:

-There is no statistically significant difference in mean stress levels across levels of Work Load or Work Environment.

-Additionally, there is no significant interaction effect, meaning the relationship between Work Load and Stress does not depend on Work Environment in a statistically meaningful way.

Test 4: How does stress, WLK, WkEnv, THPY, and Gender affect percived job satisfaction ratings?

A Multiple Linear Regression test will be used to model the relationship between JobSat, as the dependent variable, and for the predictors:

Predictors for Multiple Linear Regression on Job Satisfaction
Predictor Type Rationale
Stress Ordinal → Numeric Higher stress is likely to reduce job satisfaction.
WLB Ordinal → Numeric Better work-life balance often leads to higher satisfaction.
WkEnv Ordinal → Numeric Positive work environments are linked to satisfaction.
THPY Continuous Training may boost morale and long-term job fulfillment.
Gender Categorical (factor) Controls for potential gender-related differences.

Multiple Linear Regression Test

# Ensure JobSat is numeric for regression
emp_data$JobSatNum <- as.numeric(as.character(emp_data$JobSat))
emp_data$Stress <- as.numeric(as.character(emp_data$Stress))
emp_data$WLB <- as.numeric(as.character(emp_data$WLB))
emp_data$WkEnv <- as.numeric(as.character(emp_data$WkEnv))

# Fit the multiple linear regression model
mlr_model <- lm(JobSatNum ~ Stress + WLB + WkEnv + THPY + Gender, data = emp_data)

# Output model summary
summary(mlr_model)
## 
## Call:
## lm(formula = JobSatNum ~ Stress + WLB + WkEnv + THPY + Gender, 
##     data = emp_data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -2.9676 -0.7683  0.2322  0.7621  3.1082 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2.5056855  0.0964067  25.991   <2e-16 ***
## Stress      -0.2508591  0.0196025 -12.797   <2e-16 ***
## WLB          0.2256344  0.0144241  15.643   <2e-16 ***
## WkEnv        0.2178628  0.0147436  14.777   <2e-16 ***
## THPY        -0.0004239  0.0015379  -0.276    0.783    
## GenderMale  -0.0380143  0.0438510  -0.867    0.386    
## GenderOther  0.0129429  0.0786610   0.165    0.869    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.147 on 3018 degrees of freedom
## Multiple R-squared:  0.1738, Adjusted R-squared:  0.1721 
## F-statistic: 105.8 on 6 and 3018 DF,  p-value: < 2.2e-16

Observations

The regression analysis reveals that Stress, Work-Life Balance, and Work Environment are strong, statistically significant predictors of job satisfaction. In contrast, Training Hours and Gender (both Male and Other) do not appear to significantly influence satisfaction ratings.

Final Conclusisons

This employee survey analysis explored how various workplace factors influence stress and job satisfaction. Multiple statistical tests—including ANOVAs and multiple linear regression—were performed to examine relationships among variables.

Overall Insights: