# R Code for Calculation of the Minimum Clinically Important Difference (MCID) using different methodologies: Case study and practical guide
#Step 1. Import dataset accessible at https://data.mendeley.com/datasets/vm8rg6rvsw/1
install.packages("readxl")
library(readxl)
#Replace path to .xlsx file based on your download folder
df <- read_excel("~/Desktop/PT vs. Home ex. data.xlsx")
View(df)

#Step 2. Prepare data for analysis
#Removing the original columns names and substituting them for columns names appropriate for the analysis.

new_col_names <- df[1, ]
colnames(df) <- new_col_names
df <- df[-1, ]
rows_to_remove <- c(43,86)
df <- df[-rows_to_remove, ]
colnames(df)[54] <- "Symptom severity 6"

#Step 3. Reformat variables

#NRS Leg Pain Change Score at 6 weeks 
df$LegpainC <- as.numeric(df$"Leg pain C") 

#JOABPEQ Walking Ability Change Score at 6 weeks
df$JOABPEQgaitC <- as.numeric(df$"Gait C")

#ZCQ Symptom Severity Change Score at 6 weeks
df$ZCQsymptomchange <- as.numeric(df$"Symptom severity C")

#ZCQ Symptom Severity at Baseline
df$ZCQsymptombaseline <- as.numeric(df$"Symptom severity")

#ZCQ Symptom Severity at Follow-up
df$ZCQsymptomfollowup <- as.numeric(df$`Symptom severity 6`)

#Step 4. Categorise patients into "responders" and "nonresponders"

1- "responder"
0- "non-responder"

df$Legpainresponder <- ifelse(df$LegpainC <=-1.6, 1,0)
df$JOABPEQgaitresponder <- ifelse(df$JOABPEQgaitC >=20, 1,0)                        

#Step 5. MCID Calculations (Anchor-Based)

#Step 5a. Method (1) Within Patient Change Score 
mean(df$ZCQsymptomchange[df$Legpainresponder==1], na.rm =T)
mean(df$ZCQsymptomchange[df$JOABPEQgaitresponder==1 ], na.rm =T)

#Step 5b. Method (2) Between Patient Change Score 
a <- mean(df$ZCQsymptomchange[df$Legpainresponder==1], na.rm =T)
b <- mean(df$ZCQsymptomchange[df$Legpainresponder==0], na.rm =T)
b-a

a <- mean(df$ZCQsymptomchange[df$JOABPEQgaitresponder==1], na.rm =T)
b <- mean(df$ZCQsymptomchange[df$JOABPEQgaitresponder==0], na.rm =T)
b-a

#Step 5c. Method (3) Sensitivity and Specificity-Based Approach
install.packages("pROC")
library(pROC)
roc1 <- roc(df$Legpainresponder, df$ZCQsymptomchange)
smooth(roc1)
plot(roc1)
coords(roc1, "best", best.method = "closest.topleft", ret=c("threshold", "accuracy"))

roc1 <- roc(df$JOABPEQgaitresponder, df$ZCQsymptomchange)
smooth(roc1)
plot(roc1)
coords(roc1, "best", best.method = "closest.topleft", ret=c("threshold", "accuracy"))

#Step 6. MCID Calculation Methods (Distribution-Based)

#Step 6a. Method (4) Standard Error of Measurement 
sd(df$ZCQsymptombaseline)*sqrt(1-0.81)

#Step 6b. Method (5) Effect Size
sd(df$ZCQsymptombaseline)*0.2

#Step 6c. Method (6) Standardized Response Mean
sd(df$ZCQsymptomchange)*0.2

#Step 6d. Method (7) Half of Standard Deviation
sd(df$ZCQsymptombaseline)*0.5

#Step 6e. Method (8) Minimum Detectable Change
1.96*(sd(df$ZCQsymptombaseline)*sqrt(1-0.81))*sqrt(2)

#Step 6f. Method (9)  Reliable Change Index
a <- sd(df$ZCQsymptombaseline)*sqrt(1-0.81)
df$RCI <- (df$ZCQsymptomchange / sqrt(a))*-1
df$RCIresponder <- ifelse(df$RCI >= 1.96, 1, 0)  
roc1 <- roc(df$RCIresponder, df$ZCQsymptomchange)
plot(roc1)
coords(roc1, "best", best.method = "closest.topleft", ret=c("threshold", "accuracy"))

#Step 7. Other MCID Calculation Methods.
#Step 7a. Method (10) Anchor-Based Minimal Important Change (MIC) Distribution Model                                                                                             

#1) Recategorize patients into "importantly improved", "unchanged" and "importantly deteriorated"
#2 - importantly improved
#1 - unchanged
#0 - importantly deteriorated

#JOABPEQ Walking Ability
df$JOABPEQgaitresponder <- ifelse(df$JOABPEQgaitC >= 20, 2,
                                  ifelse(df$JOABPEQgaitC >= -20 & df$JOABPEQgaitC <20, 1, 0))
#2) Create a Histogram of the Change scores For Patients Who Importantly Improved

hist(df$ZCQsymptomchange[df$JOABPEQgaitresponder == 2], 
     main = "Histogram of Change Scores for Important Improvement",
     xlab = "Change Score", ylab = "Frequency", col = "skyblue", border = "black")

#3)  Plot the line distribution of Change scores for Patients in Each Group (0, 1 and 2)
plot(density(df$ZCQsymptomchange[df$JOABPEQgaitresponder == 1]), 
     main = "ZCQ Symptom Severity Change Scores for Important Improvement",
     xlab = "Change Score", ylab = "Improved", col = "blue", lwd = 2, type = "l",
     xlim = c(-25,10))

#Perform point 2) and point 3) for each patient group. Replace the "2" in df$JOABPEQgaitresponder with 0 (representing importantly deteriorated) and 1 (representing unchanged), respectively.

#4) 95% Upper Limit Cut-off
a <- mean(df$ZCQsymptomchange[df$JOABPEQgaitresponder==1], na.rm =T)
b <- sd(df$ZCQsymptomchange[df$JOABPEQgaitresponder==1], na.rm =T)
upper_limit <- a + 1.645 * b
print(upper_limit)

#5) 95% Lower Limit Cut-off
lower_limit <- a - 1.645 * b
print(lower_limit)

#6) 
#ROC Analysis for Important Improvement
subset_df1 <- df[df$JOABPEQgaitresponder %in% c(1, 2), ]
roc1 <- roc(subset_df1$JOABPEQgaitresponder, subset_df1$ZCQsymptomchange)
smooth(roc1)
plot(roc1)
coords(roc1, "best", best.method = "closest.topleft", ret=c("threshold", "accuracy"))

#ROC Analysis for Important Deterioration
subset_df2 <- df[df$JOABPEQgaitresponder %in% c(0, 1), ]
roc1 <- roc(subset_df2$JOABPEQgaitresponder, subset_df2$ZCQsymptomchange)
smooth(roc1)
plot(roc1)
coords(roc1, "best", best.method = "closest.topleft", ret=c("threshold", "accuracy"))

#Step 7b. Method (11) Calculating MCID as 30% Reduction from Baseline
df$percentage_change <- ((df$ZCQsymptomfollowup - df$ZCQsymptombaseline) / df$ZCQsymptombaseline) * 100

