Time series analysis: Case-crossover analysis

2024-07-22

Dr. Kenny Oriel Olana

Case-crossover analysis

In the case-crossover design, the study population consists of subjects who have experienced an episode of the health outcome of interest. Similar to a crossover study, each subject serves as his or her own control. As in a matched case-control study, the inference is based on a comparison of exposure distribution rather than the risk of disease. The case-crossover study is most suitable for studying relations with the following characteristics: 1) the individual exposure varies within short time intervals; 2) the disease has abrupt onset and short latency for detection; and 3) the induction period is short.

Case-crossover design allows use of routinely monitored air pollution information and at the same time makes it possible to study individuals rather than days as the unit of observation. .

##read data
data <- read.csv("/Users/kennyorielolana/Documents/DATA ANALYSIS and Mapping/Training in Time series analysis /data_urolithiasis.csv")

##Reading R packages
library(dlnm)
## This is dlnm 2.4.7. For details: help(dlnm) and vignette('dlnmOverview').
library(splines)
library(survival)

head(data)
##         date  studyid sex age event time dow   l0_wbgt   l1_wbgt   l2_wbgt
## 1 2010-01-01 382405_1   2  66     0    2   6 13.292202 12.711058 12.414207
## 2 2010-01-01    86767   2  53     0    2   6  7.000611  5.941786  8.097641
## 3 2010-01-01 307636_1   1  41     0    2   6 13.292202 12.711058 12.414207
## 4 2010-01-01  6127201   1  28     0    2   6  7.124393 20.376735 18.107819
## 5 2010-01-01     5859   1  75     0    2   6  2.210671 18.645376 18.426286
## 6 2010-01-01  6088901   2  18     0    2   6  7.124393 20.376735 18.107819
##     l3_wbgt   l4_wbgt   l5_wbgt   l6_wbgt   l7_wbgt holiday
## 1 11.202209  8.232980  9.561680  7.606777  9.417363       1
## 2  8.731275  8.817321  8.068007  6.320272  4.392536       1
## 3 11.202209  8.232980  9.561680  7.606777  9.417363       1
## 4 17.110460 17.114432 15.423693 12.200597 14.839795       1
## 5 17.955405 14.915938 13.821673 11.252827 12.311683       1
## 6 17.110460 17.114432 15.423693 12.200597 14.839795       1
## date~date, sex~1 (male) and 2 (female), event~1 refers to the case period and 0 refers to the control period; wbgt~ Wet Bulb Globe Temperature

summary(data)
##      date             studyid               sex             age       
##  Length:185777      Length:185777      Min.   :1.000   Min.   :-2.00  
##  Class :character   Class :character   1st Qu.:1.000   1st Qu.:36.00  
##  Mode  :character   Mode  :character   Median :1.000   Median :46.00  
##                                        Mean   :1.332   Mean   :47.02  
##                                        3rd Qu.:2.000   3rd Qu.:58.00  
##                                        Max.   :2.000   Max.   :98.00  
##                                                                       
##      event             time            dow           l0_wbgt      
##  Min.   :0.0000   Min.   :1.000   Min.   :1.000   Min.   :-15.49  
##  1st Qu.:0.0000   1st Qu.:2.000   1st Qu.:2.000   1st Qu.: 13.69  
##  Median :0.0000   Median :2.000   Median :4.000   Median : 20.40  
##  Mean   :0.2272   Mean   :1.773   Mean   :3.931   Mean   : 18.68  
##  3rd Qu.:0.0000   3rd Qu.:2.000   3rd Qu.:6.000   3rd Qu.: 24.99  
##  Max.   :1.0000   Max.   :2.000   Max.   :7.000   Max.   : 30.20  
##                                                   NA's   :25      
##     l1_wbgt          l2_wbgt          l3_wbgt          l4_wbgt      
##  Min.   :-15.49   Min.   :-15.49   Min.   :-15.49   Min.   :-15.49  
##  1st Qu.: 13.73   1st Qu.: 13.73   1st Qu.: 13.72   1st Qu.: 13.75  
##  Median : 20.42   Median : 20.42   Median : 20.43   Median : 20.42  
##  Mean   : 18.70   Mean   : 18.71   Mean   : 18.71   Mean   : 18.72  
##  3rd Qu.: 25.01   3rd Qu.: 24.99   3rd Qu.: 25.01   3rd Qu.: 25.04  
##  Max.   : 30.20   Max.   : 30.20   Max.   : 30.20   Max.   : 30.20  
##  NA's   :15       NA's   :19       NA's   :28       NA's   :15      
##     l5_wbgt          l6_wbgt          l7_wbgt          holiday       
##  Min.   :-15.49   Min.   :-14.38   Min.   :-15.49   Min.   :0.00000  
##  1st Qu.: 13.75   1st Qu.: 13.75   1st Qu.: 13.76   1st Qu.:0.00000  
##  Median : 20.39   Median : 20.40   Median : 20.43   Median :0.00000  
##  Mean   : 18.72   Mean   : 18.72   Mean   : 18.72   Mean   :0.07141  
##  3rd Qu.: 25.06   3rd Qu.: 25.02   3rd Qu.: 25.01   3rd Qu.:0.00000  
##  Max.   : 30.20   Max.   : 30.20   Max.   : 30.20   Max.   :1.00000  
##  NA's   :28       NA's   :29       NA's   :23
###DLNM function
## 7-day lag with 2 degrees of freedom
lag <- 7
lagnk <- 2
fmla<-as.formula(event ~ cb+strata(studyid)+as.factor(holiday))

## Removing Temperature Extremes
wbgt <- data[,8:(8+7)]
p99<-quantile(wbgt, probs = 0.999,na.rm = T)
p1<-quantile(wbgt, probs = 0.001,na.rm = T)
wbgt[wbgt > p99] <- NA
wbgt[wbgt < p1] <- NA
bound<-c(round(p1,1),round(p99,1))

##
t1<-round(quantile(wbgt,0.01,na.rm = T),1)
t2<-round(quantile(wbgt,0.025,na.rm = T),1)
t3<-round(quantile(wbgt,0.975,na.rm = T),1)
t4<-round(quantile(wbgt,0.99,na.rm = T),1)

## building up cross-bases
argvar <- list(fun="ns", knots = equalknots(wbgt,fun = "ns",df=4),
Bound=bound)
cb <- crossbasis(wbgt,lag=lag,argvar=argvar,
arglag=list(knots=logknots(lag,lagnk)))
model<-clogit(fmla,data=data,na.action=na.exclude)
pred <- crosspred(cb,model,by=0.1,cumul = TRUE)
## centering value unspecified. Automatically set to 10
cen<-pred$predvar[which.min(pred$allfit)]
print(cen) ## MMT
## [1] 15
pred_S <- crosspred(cb,model,by=0.1,cumul = TRUE,cen=cen,
at=c(seq(bound[1],bound[2],by=0.1),t3,t4))

##Calculating OR
x1<-t(as.matrix(round(with(pred,cbind(allRRfit,allRRlow,allRRhigh)[as.character(t1),]),3)))
x2<-t(as.matrix(round(with(pred,cbind(allRRfit,allRRlow,allRRhigh)[as.character(t2),]),3)))
x3<-t(as.matrix(round(with(pred,cbind(allRRfit,allRRlow,allRRhigh)[as.character(t3),]),3)))
x4<-t(as.matrix(round(with(pred,cbind(allRRfit,allRRlow,allRRhigh)[as.character(t4),]),3)))
result <- data.frame(rbind(x1,x2,x3,x4))
rownames(result) <- c(t1,t2,t3,t4)

##Exposure-response curve
# Define the x-axis label with the degree symbol
xlab <- expression(paste("WBGT (", degree, "C)"))

# Set up plotting parameters
par(mar = c(4, 4, 3, 1), cex.axis = 0.9, mgp = c(2.5, 1, 0), cex.lab = 1)

# Ensure that pred_S is properly defined and that the plot function supports your arguments
if (exists("pred_S")) {
    plot(pred_S, "overall", col = 2, cex.axis = 1, xlab = xlab, ylab = "Odds ratio", ylim = c(0.8, 2.0), 
         main = paste0("Exposure-response curve"), cex.main = 1, ci = "area", ci.arg = list(col = grey(0.85)))
    lines(pred_S, col = 2, lwd = 2)
} else {
    warning("The object 'pred_S' does not exist.")
}

# Save the plot as a TIFF file
tiff("figure_ER.tiff", res = 300, height = 1200, width = 1200)

# Reproduce the plot for saving
par(mar = c(4, 4, 3, 1), cex.axis = 0.9, mgp = c(2.5, 1, 0), cex.lab = 1)
plot(pred_S, "overall", col = 2, cex.axis = 1, xlab = xlab, ylab = "Odds ratio", ylim = c(0.8, 2.0), 
     main = paste0("Exposure-response curve"), cex.main = 1, ci = "area", ci.arg = list(col = grey(0.85)))
lines(pred_S, col = 2, lwd = 2)

# Close the TIFF device
dev.off()
## quartz_off_screen 
##                 2
## lag pattern curve
# Define the x-axis label
xlab <- "Lag (day)"
ylab <- "Odds ratio"

# Set up plotting parameters
par(mar = c(4, 4, 3, 1), cex.axis = 0.9, mgp = c(2.5, 1, 0), cex.lab = 1)

# Ensure that pred_S and t4 are properly defined
if (exists("pred_S") && exists("t4")) {
    plot(pred_S, "slices", var = t4,
         xlim = c(0, 7), cex.main = 1,
         col = 2, lwd = 2,
         xlab = xlab,
         ylab = ylab, cex.lab = 1,
         ci = "area", ci.arg = list(col = grey(0.85)),
         main = paste0("Lag pattern"))
    lines(pred_S, col = 1, lwd = 2)
} else {
    warning("The objects 'pred_S' or 't4' do not exist.")
}

# Save the plot as a TIFF file
tiff("figure_lag.tiff", res = 300, height = 1200, width = 1200)

# Set up plotting parameters
par(mar = c(4, 4, 3, 1), cex.axis = 0.9, mgp = c(2.5, 1, 0), cex.lab = 1)

# Ensure that pred_S and t4 are properly defined
if (exists("pred_S") && exists("t4")) {
    plot(pred_S, "slices", var = t4,
         xlim = c(0, 7), cex.main = 1,
         col = 2, lwd = 2,
         xlab = xlab,
         ylab = ylab, cex.lab = 1,
         ci = "area", ci.arg = list(col = grey(0.85)),
         main = paste0("Lag pattern"))
    lines(pred_S, col = 1, lwd = 2)
} else {
    warning("The objects 'pred_S' or 't4' do not exist.")
}

# Close the TIFF device
dev.off()
## quartz_off_screen 
##                 2