library(dplyr)
library(ggplot2)
library(gt)
library(ggiraph)
library(tidyr)
library(tidyverse)
library(corrplot)
library(bestNormalize)
library(patchwork)
library(gridExtra)
library(zoo)
library(stringr)
library(grid)
library(pracma)
library(infotheo)

Missing Variables

From the table below, it is clear that every variable has missing rows. This is going to require a lot of work to best fill in these missing values, to ensure that optimal results are achieved.

train <- read.csv("train.csv")
test <- read.csv("test.csv")
missing_train <- train |>
  dplyr::mutate(across(where(is.character), ~ dplyr::na_if(.x, ""))) |>
  dplyr::summarise(across(everything(), ~ sum(is.na(.x)))) |>
  tidyr::pivot_longer(cols = everything(), names_to = "Variables", values_to = "Total_train")

missing_test <- test |>
  dplyr::mutate(across(where(is.character), ~ dplyr::na_if(.x, ""))) |>
  dplyr::summarise(across(everything(), ~ sum(is.na(.x)))) |>
  tidyr::pivot_longer(cols = everything(), names_to = "Variables", values_to = "Total_test")

missing <- dplyr::left_join(missing_train, missing_test, by = "Variables") |> 
  dplyr::mutate(
    Pct_train = round((Total_train / nrow(train)) * 100, 2),
    Pct_test  = round((Total_test / nrow(test)) * 100, 2)
  )

missing |> gt()
Variables Total_train Total_test Pct_train Pct_test
id 0 0 0.00 0.00
health_condition 0 NA 0.00 NA
sleep_duration 75999 32571 11.01 11.01
heart_rate 7833 3357 1.14 1.14
bmi 13898 5956 2.01 2.01
calorie_expenditure 52853 22652 7.66 7.66
step_count 13916 5964 2.02 2.02
exercise_duration 6901 2958 1.00 1.00
water_intake 43477 18633 6.30 6.30
diet_type 6901 2958 1.00 1.00
stress_level 82811 35490 12.00 12.00
sleep_quality 58331 24999 8.45 8.45
physical_activity_level 36621 15695 5.31 5.31
smoking_alcohol 28582 12249 4.14 4.14
gender 21373 9160 3.10 3.10

Exploratory Data

sum_raw <- summary(train)

stat_names <- sapply(strsplit(sum_raw[, 1], ":"), function(x) trimws(x[1]))

sum_clean <- apply(sum_raw, 2, function(col) {
  sapply(strsplit(col, ":"), function(x) trimws(tail(x, 1)))
})

sum_df <- as.data.frame(sum_clean, stringsAsFactors = FALSE)
sum_df <- cbind(Statistic = stat_names, sum_df)

sum_df |>
  gt(rowname_col = "Statistic") |>
  tab_header(
    title = "Data Summary of Training Set",
    subtitle = "Summary statistics for all columns"
  ) |>
  tab_options(
    table.font.size = px(14),
    heading.align = "left",
    stub.font.weight = "bold"
  )
Data Summary of Training Set
Summary statistics for all columns
id health_condition sleep_duration heart_rate bmi calorie_expenditure step_count exercise_duration water_intake diet_type stress_level sleep_quality physical_activity_level smoking_alcohol gender
Min. 0 690088 3.00 50.0 16.00 1200 1002 0.00 0.50 690088 690088 690088 690088 690088 690088
1st Qu. 172522 character 6.16 69.4 21.32 2053 5389 29.20 1.84 character character character character character character
Median 345044 character 6.99 75.1 22.99 2241 8856 39.40 2.17 character character character character character character
Mean 345044 NA 6.99 75.1 22.98 2226 8616 38.75 2.19 NA NA NA NA NA NA
3rd Qu. 517565 NA 7.81 80.7 24.66 2456 12114 49.40 2.50 NA NA NA NA NA NA
Max. 690087 NA 10.00 107.7 34.82 3580 14999 99.80 4.72 NA NA NA NA NA NA
NA NA NA 75999 7833 13898 52853 13916 6901 43477 NA NA NA NA NA NA

Class Imbalance Check

target_imbalance <- as.data.frame(table(train$health_condition)) 
colnames(target_imbalance) <- c("Target", "Frequency")
target_imbalance |> 
  dplyr::mutate(Per_Freq = round(Frequency / sum(Frequency) *100, 2)) |>
  gt()
Target Frequency Per_Freq
at-risk 592561 85.87
fit 39803 5.77
unhealthy 57724 8.36

Univariate Exploration

Correlation

train_numeric <- train |>
  mutate(
    health_condition = as.numeric(factor(health_condition, levels = c("fit", "at-risk", "unhealthy"))),
    stress_level = as.numeric(factor(stress_level, levels = c("low", "medium", "high"))),
    sleep_quality = as.numeric(factor(sleep_quality, levels = c("poor", "average", "good"))),
    physical_activity_level = as.numeric(factor(physical_activity_level, levels = c("sedentary", "moderate", "active"))),
    smoking_alcohol = as.numeric(factor(smoking_alcohol, levels = c("no", "occasional", "yes"))),
    diet_type = NULL,
    gender = NULL
  )

pit_corr <- stats::cor(train_numeric, use = "complete.obs", method = "spearman")

corrplot(pit_corr, method = 'color', addCoef.col = 'black', col = COL2('RdYlBu'))

Mutual Information

train_cat <- train |>
  mutate(across(where(is.numeric), ~ discretize(.x, disc = "equalfreq", nbins = 5)[[1]]))

train_cat <- as.data.frame(lapply(train_cat, function(x) as.integer(as.factor(x))))

vars <- names(train_cat)

mi_mat <- matrix(0, nrow = length(vars), ncol = length(vars),
                  dimnames = list(vars, vars))
for (i in seq_along(vars)) {
  for (j in seq_along(vars)) {
    mi_mat[i, j] <- mutinformation(train_cat[[i]], train_cat[[j]])
  }
}

nmi_mat <- mi_mat
for (i in seq_along(vars)) {
  for (j in seq_along(vars)) {
    nmi_mat[i, j] <- mi_mat[i, j] / sqrt(mi_mat[i, i] * mi_mat[j, j])
  }
}
nmi_long <- as.data.frame(nmi_mat) |>
  mutate(var1 = rownames(nmi_mat)) |>
  pivot_longer(-var1, names_to = "var2", values_to = "nmi")

ggplot(nmi_long, aes(x = var1, y = var2, fill = nmi)) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(nmi, 2)), size = 3) +
  scale_fill_distiller(palette = "RdYlBu", limits = c(0, 1)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(x = NULL, y = NULL, fill = "NMI")

target <- "health_condition"

mi_with_target <- data.frame(
  variable = setdiff(vars, target),
  mi = sapply(setdiff(vars, target), function(v) {
    mutinformation(train_cat[[v]], train_cat[[target]])
  })
)

ggplot(mi_with_target, aes(x = reorder(variable, mi), y = mi)) +
  geom_col(fill = "steelblue") +
  coord_flip() +
  labs(x = NULL, y = "Mutual Information with health_condition", title = "Predictor MI with health_condition") +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

Sleep Duration

ggplot(train, aes(x = health_condition, y = sleep_duration, fill = health_condition)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.3) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(title = "Sleep Duration by Health Condition", y = "Sleep Duration", x = "") +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = health_condition, y = heart_rate, fill = health_condition)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.3) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(title = "Heart Rate by Health Condition", y = "Heart Rate", x = "") +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = health_condition, y = bmi, fill = health_condition)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.3) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "BMI",
    y = "Density",
    x = "BMI"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = health_condition, y = calorie_expenditure, fill = health_condition)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.3) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Calorie Expenditure",
    y = "Density",
    x = "Calorie Expenditure"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = health_condition, y = step_count, fill = health_condition)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.3) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Step Count",
    y = "Density",
    x = "Step Count"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = health_condition, y = exercise_duration, fill = health_condition)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.3) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Exercise Duration",
    y = "Density",
    x = "Exercise Duration"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = health_condition, y = water_intake, fill = health_condition)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.3) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442", 
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Water Intake",
    y = "Density",
    x = "Water Intake"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = factor(diet_type, levels = c("balanced", "non-veg", "veg")),
                   fill = factor(health_condition))) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Diet Type",
    y = "Count",
    x = "Diet Type"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = factor(stress_level, levels = c("low", "medium", "high")),
                   fill = factor(health_condition))) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Stress Level",
    y = "Count",
    x = "Stress Level"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = factor(sleep_quality, levels = c("poor", "average", "good")),
                   fill = factor(health_condition))) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Sleep Quality",
    y = "Count",
    x = "Sleep Quality"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = factor(gender, levels = c("female", "male", "other")),
                   fill = factor(health_condition))) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Gender",
    y = "Count",
    x = "Gender"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = factor(smoking_alcohol, levels = c("no", "occasional", "yes")),
                   fill = factor(health_condition))) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Smoking / Alcohol Use",
    y = "Count",
    x = "Smoking / Alcohol"
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

ggplot(train, aes(x = factor(physical_activity_level, levels = c("sedentary", "moderate", "active")),
                   fill = factor(health_condition))) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  scale_color_manual(values = c("#E69F00", "#56B4E9", "#009E73", "#F0E442",
                                "#0072B2", "#D55E00", "#CC79A7")) +
  labs(
    title = "Activity Levels",
    y = "Count",
    x = ""
  ) +
  theme_minimal(base_size = 12, base_family = "sans") +
  theme(
    plot.title = element_text(face = "bold", size = 14, margin = margin(b = 4)),
    plot.subtitle = element_text(color = "grey40", size = 11, margin = margin(b = 12)),
    plot.caption = element_text(color = "grey60", size = 9, hjust = 0),
    plot.margin = margin(16, 16, 16, 16),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    axis.title = element_text(color = "grey30", size = 10),
    axis.text = element_text(color = "grey30"),
    axis.ticks.x = element_line(color = "grey80"),
    legend.position = "bottom",
    legend.title = element_blank()
  )

cat_prop_table <- function(data, var) {
  data |>
    dplyr::count(.data[[var]], health_condition) |>
    dplyr::group_by(.data[[var]]) |>
    dplyr::mutate(pct = round(n / sum(n) * 100, 1)) |>
    dplyr::select(-n) |>
    tidyr::pivot_wider(names_from = health_condition, values_from = pct) |>
    gt() |>
    tab_header(title = paste("Health Condition % by", var))
}

cat_prop_table(train, "stress_level")
Health Condition % by stress_level
at-risk fit unhealthy
85.9 5.7 8.4
high
71.8 0.4 27.9
low
79.7 20.1 0.3
medium
99.4 0.3 0.3
cat_prop_table(train, "physical_activity_level")
Health Condition % by physical_activity_level
at-risk fit unhealthy
85.9 5.7 8.3
active
74.3 17.2 8.5
moderate
91.1 0.3 8.5
sedentary
91.7 0.2 8.0
cat_prop_table(train, "sleep_quality")
Health Condition % by sleep_quality
at-risk fit unhealthy
86.0 5.8 8.2
average
85.9 5.7 8.3
good
88.8 8.2 3.0
poor
83.0 3.5 13.6
cat_prop_table(train, "diet_type")
Health Condition % by diet_type
at-risk fit unhealthy
86.8 5.1 8.2
balanced
85.1 6.1 8.7
non-veg
86.8 5.2 8.1
veg
85.7 6.0 8.3
cat_prop_table(train, "gender")
Health Condition % by gender
at-risk fit unhealthy
85.8 5.6 8.6
female
85.7 5.7 8.6
male
85.7 6.3 8.0
other
86.2 5.3 8.5
cat_prop_table(train, "smoking_alcohol")
Health Condition % by smoking_alcohol
at-risk fit unhealthy
85.7 5.8 8.6
no
86.7 7.9 5.5
occasional
85.9 5.8 8.4
yes
85.1 3.7 11.2