##This is synthetic patient-level clinical trial data available from: https://www.kaggle.com/datasets/dillonmyrick/bells-palsy-clinical-trial, re-created based on data from a clinical trial for corticosteroids and antiviral agents as treatment for Bell’s Palsy: https://www.nejm.org/doi/full/10.1056/nejmoa072006# ##the protocol is also available as supplementary material. ##The authors conducted a double-blind, placebo-controlled, randomized, factorial trial involving patients with Bell’s Palsy who were recruited within 72 hours after the onset of symptoms. Patients were randomly assigned to receive 10 days of treatment with prednisolone, acyclovir, both agents, or placebo. The primary outcome was recovery of facial function, as rated on the House–Brackmann scale.

##Load data: done by copying the csv file into the folder for the project.

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.2     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.1     
## ── 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
bells <- read.csv("BellsPalsy.csv")
glimpse(bells)
## Rows: 494
## Columns: 12
## $ Patient.ID                                            <int> 1, 2, 3, 4, 5, 6…
## $ Sex                                                   <chr> "Female", "Femal…
## $ Age                                                   <int> 77, 61, 46, 46, …
## $ Baseline.Score.on.House.Brackmann.scale               <int> 6, 6, 4, 3, 3, 4…
## $ Time.between.onset.of.symptoms.and.start.of.treatment <chr> "Within 24 hr", …
## $ Treatment.Group                                       <chr> "Prednisolone–Pl…
## $ Received.Prednisolone                                 <chr> "Yes", "Yes", "Y…
## $ Received.Acyclovir                                    <chr> "No", "No", "No"…
## $ X3.Month.Score.on.House.Brackmann.scale               <int> 2, 1, 1, 1, 1, 1…
## $ Full.Recovery.in.3.Months                             <chr> "No", "Yes", "Ye…
## $ X9.Month.Score.on.House.Brackmann.scale               <int> 2, 1, 1, 1, 1, 1…
## $ Full.Recovery.in.9.Months                             <chr> "No", "Yes", "Ye…

##Cleaning the code ##Creating binary outcomes

bells <- bells |> 
  mutate(
    prednisolone = ifelse(Received.Prednisolone == "Yes", 1,0),
    acyclovir = ifelse(Received.Acyclovir == "Yes", 1,0),
    threemthrecovery = ifelse(Full.Recovery.in.3.Months == "Yes", 1,0),
    ninemthrecovery = ifelse(Full.Recovery.in.9.Months == "Yes", 1,0)
  )

##Creating baseline table

bells <- bells |> 
  mutate(
    group = case_when(
      prednisolone == 0 & acyclovir == 0 ~ "Neither",
      prednisolone == 1 & acyclovir == 0 ~ "Prednisolone only",
      prednisolone == 0 & acyclovir == 1 ~ "Acyclovir only",
      prednisolone == 1 & acyclovir == 1 ~ "Both"
    )
  )

##Coding time to start of treatment

bells <- bells |> 
  mutate(
    time_group = case_when(
      `Time.between.onset.of.symptoms.and.start.of.treatment` == "Within 24 hr" ~ 1,
      `Time.between.onset.of.symptoms.and.start.of.treatment` == ">24 to ≤48 hr" ~ 2,
      `Time.between.onset.of.symptoms.and.start.of.treatment` == ">48 to ≤72 hr"~ 3,
      TRUE ~ NA_real_
      )
  )

##Converting variables to proper types

bells <- bells |> 
  mutate(
    sex = as.factor(Sex),
    baseline_score = as.numeric(Baseline.Score.on.House.Brackmann.scale)
  )

##installing packages: install.packages(“gtsummary”) # run once

library(gtsummary)

##Create baseline table

tbl <- bells |> 
  select(group, sex, Age, baseline_score, time_group) |> 
  tbl_summary(
    by = group,
    statistic = list(
      all_continuous() ~ "{mean} ({sd})",
      all_categorical() ~ "{n} ({p}%)"
    ),
    digits = all_continuous() ~ 1 #rounds all continuous data to one decimal point
  ) |> 
  add_overall() %>%   # adds TOTAL column
  modify_header(label = "**Baseline Characteristic**") |> 
  bold_labels()

tbl
Baseline Characteristic Overall
N = 494
1
Acyclovir only
N = 122
1
Both
N = 127
1
Neither
N = 122
1
Prednisolone only
N = 123
1
sex




    Female 238 (48%) 56 (46%) 62 (49%) 65 (53%) 55 (45%)
    Male 256 (52%) 66 (54%) 65 (51%) 57 (47%) 68 (55%)
Age 44.9 (14.6) 44.6 (14.9) 44.7 (13.4) 45.7 (15.4) 44.5 (14.6)
baseline_score




    2 84 (17%) 17 (14%) 24 (19%) 19 (16%) 24 (20%)
    3 135 (27%) 28 (23%) 37 (29%) 35 (29%) 35 (28%)
    4 163 (33%) 48 (39%) 37 (29%) 38 (31%) 40 (33%)
    5 79 (16%) 20 (16%) 23 (18%) 19 (16%) 17 (14%)
    6 33 (6.7%) 9 (7.4%) 6 (4.7%) 11 (9.0%) 7 (5.7%)
time_group




    1 249 (51%) 68 (56%) 62 (49%) 66 (54%) 53 (43%)
    2 205 (42%) 41 (34%) 53 (42%) 55 (45%) 56 (46%)
    3 39 (7.9%) 12 (9.9%) 12 (9.4%) 1 (0.8%) 14 (11%)
    Unknown 1 1 0 0 0
1 n (%); Mean (SD)

##Next plan to read the results section of NEJM to see which test was done. ##To test for association between P and A at 3 months. ##Recovery has been coded as HB grade 1 and is therefore binary ##Logistic regression is best. ##Testing for interaction

model <- glm(threemthrecovery ~ prednisolone * acyclovir + Age + Baseline.Score.on.House.Brackmann.scale,
    family = binomial,
    data = bells)
##Generating odds ratio
exp(coef(model))
##                             (Intercept)                            prednisolone 
##                              48.8659828                               3.1768886 
##                               acyclovir                                     Age 
##                               0.8541283                               0.9536483 
## Baseline.Score.on.House.Brackmann.scale                  prednisolone:acyclovir 
##                               0.7509903                               0.8010728

##Creating p values, CI and publication type tables

# Fit model (if not already saved)
model <- glm(
  threemthrecovery ~ prednisolone * acyclovir + Age + 
    Baseline.Score.on.House.Brackmann.scale,
  family = binomial,
  data = bells
)

# Extract results
coef_table <- summary(model)$coefficients

OR <- exp(coef(model))
CI <- exp(confint(model))
## Waiting for profiling to be done...
results <- data.frame(
  Variable = rownames(coef_table),
  OR = OR,
  CI_lower = CI[,1],
  CI_upper = CI[,2],
  p_value = coef_table[,4]
)

print(results)
##                                                                        Variable
## (Intercept)                                                         (Intercept)
## prednisolone                                                       prednisolone
## acyclovir                                                             acyclovir
## Age                                                                         Age
## Baseline.Score.on.House.Brackmann.scale Baseline.Score.on.House.Brackmann.scale
## prednisolone:acyclovir                                   prednisolone:acyclovir
##                                                 OR   CI_lower    CI_upper
## (Intercept)                             48.8659828 17.1073121 148.9371969
## prednisolone                             3.1768886  1.6781423   6.2022264
## acyclovir                                0.8541283  0.4874143   1.4928699
## Age                                      0.9536483  0.9382095   0.9685820
## Baseline.Score.on.House.Brackmann.scale  0.7509903  0.6167942   0.9109114
## prednisolone:acyclovir                   0.8010728  0.3291584   1.9333840
##                                              p_value
## (Intercept)                             1.676195e-12
## prednisolone                            5.024323e-04
## acyclovir                               5.800976e-01
## Age                                     4.858712e-09
## Baseline.Score.on.House.Brackmann.scale 3.911803e-03
## prednisolone:acyclovir                  6.225793e-01
##Final table will need formatting to be done.

##Parking this for now. Shall revisit.