--- title: "VarReg" resource_files: - resources/ output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{VarReg} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- This repository is for the data and code presented in the paper published here (to be added). ## Install packages Firstly, you will need to install the `VarReg` package and a few others to perform the code below. ```r library(VarReg) library(gamlss) #for the CD4 dataset library(tidyverse) library(kableExtra) rna<-read.csv(file="resources/rna.csv") #load rna dataset ``` ## CD4 dataset This dataset is located within the `gamlss` package. CD4 is a type of white blood cell, and in this dataset, it has been measured in uninfected children born from HIV-1 infected women. The dataset contains 609 measurements of CD4 cell counts and the child's age at which the measurements were taken. ```r data("CD4") str(CD4) #> 'data.frame': 609 obs. of 2 variables: #> $ cd4: num 387 2183 904 1681 656 ... #> $ age: num 4.5 0.83 2.06 1.44 2.67 1.17 1.94 1.72 2.54 1.66 ... ``` Lets reproduce the graphic in the paper, showing that at younger ages there is more variation in the CD4 counts than at older ages, demonstrating heteroscedasticity. ```r ggplot(data=CD4, aes(y=cd4, x=age)) + geom_point()+ xlab("Age of child in years")+ ylab("CD4 cell count")+ theme_minimal() ``` ![CD4 dataset: more variation in the CD4 counts at younger ages than at older ages](cd4p1-1.png) ### Linear model in mean and variance Let us fit a linear model in the mean and variance model, like so ```r cd4.linear<-semiVarReg(y = CD4$cd4, x=CD4$age, meanmodel = "linear", varmodel = "linear", maxit=10000) ``` key outputs for model fit: ```r cd4.linear$aic #> [1] 8999.12 cd4.linear$bic #> [1] 9016.767 ``` Key estimates from model: ```r cd4.linear$mean #> Intercept CD4$age #> 884.7263 -124.8084 cd4.linear$variance #> Intercept CD4$age #> 218069.56 -23922.79 ``` ### Visualise the model with `plotVarReg` function: ```r plotVarReg(cd4.linear, xlab = "Age in years", ylab = "CD4 cell count") ``` ![PlotVarReg example](plotcd4-1.png) ### Searching for the optimal spline Searching to a max of 7 knots in the mean and variance, with maximum iterations (`maxit`) of 100 to minimise time taken for the search: ```r cd4.best <- searchVarReg(y=CD4$cd4, x=CD4$age, maxknots.m = 7, maxknots.v = 7, selection="AIC", maxit=100) ``` lets look at the AIC table to identify where the best model is located: ```r cd4.best$AIC %>% kbl(digits=1) ```
Mean_zero Mean_constant Mean_linear Mean_Knot0 Mean_Knot1 Mean_Knot2 Mean_Knot3 Mean_Knot4 Mean_Knot5 Mean_Knot6 Mean_Knot7
Var_constant 9750.8 9205.7 9044.1 8995.6 8997.3 8977.0 8972.1 8967.6 8966.3 8964.8 8964.6
Var_linear 9662.4 9157.1 8999.8 8919.5 8916.2 8893.4 8889.8 8886.4 8885.6 8884.5 8884.7
Var_Knot0 9554.9 9157.1 8947.8 8839.2 8834.9 8862.5 8890.6 8905.7 8912.8 8916.5 8920.8
Var_Knot1 9569.4 9071.5 8904.2 8843.9 8843.7 8827.6 8825.4 8823.6 8823.3 8822.8 8823.6
Var_Knot2 9529.3 8998.8 8897.0 8842.4 8843.9 8810.5 8804.0 8799.1 8797.8 8797.3 8798.5
Var_Knot3 9524.5 8989.1 8892.3 8845.5 8847.5 8809.0 8802.2 8797.2 8796.2 8795.6 8796.8
Var_Knot4 9526.0 8989.6 8893.1 8848.0 8849.8 8813.2 8805.8 8801.3 8800.6 8800.2 8801.3
Var_Knot5 9525.9 8985.4 8894.0 8849.5 8851.4 8809.1 8803.7 8800.0 8799.1 8798.9 8800.1
Var_Knot6 9527.4 8987.0 8895.1 8851.7 8853.6 8810.9 8804.9 8801.3 8800.6 8800.4 8801.4
Var_Knot7 9530.4 8988.6 8896.6 8852.4 8854.2 8813.2 8807.9 8804.3 8803.4 8803.2 8804.4
The best model is saved within the `cd4.best` list. The key estimates from the best model are: ```r cd4.best$best.model$knots.m #> [1] 6 cd4.best$best.model$knots.v #> [1] 3 cd4.best$best.model$mean #> Intercept M_Knt6_Base1 M_Knt6_Base2 M_Knt6_Base3 M_Knt6_Base4 M_Knt6_Base5 M_Knt6_Base6 M_Knt6_Base7 #> 32.98833 1597.06078 713.32197 582.58478 472.08281 291.50092 269.24506 220.66235 #> M_Knt6_Base8 #> 155.83254 cd4.best$best.model$variance #> Intercept V_Knt3_Base1 V_Knt3_Base2 V_Knt3_Base3 V_Knt3_Base4 V_Knt3_Base5 #> 40801.4581 411830.6370 109290.5901 2784.9777 914.4245 -25616.3670 ``` ie. 6 knots in mean and 3 in variance, with parameter estimates as given. We can then plot this best model: ```r plotVarReg(cd4.best$best.model, xlab = "Age in years", ylab = "CD4 cell count") ``` ![plotVarReg example of best model from search VarReg](plotvarreg2-1.png) From these residuals, there still appears to be deviations from normality in the residuals, again seen in both the Q-Q plot and the histogram. Therefore the incorporation of a shape parameter should be investigated. ### `lssVarReg` function In order to fit models with a shape parameter, we utilise the `lssVarReg()` function. Firstly, let us fit a constant shape parameter with 6 knots in the mean and 3 knots in the variance, that is, Let us fit two models, one with a constant shape parameter and one with a linear model in the shape, with the following code. ```r con.shape<-lssVarReg(y=CD4$cd4, x=CD4$age, locationmodel="semi", knots.l=6, scale2model="semi", knots.sc=3, mono.scale = "inc", shapemodel="constant", maxit=1000 ) linear.shape<-lssVarReg(y=CD4$cd4, x=CD4$age, locationmodel="semi", knots.l=6, scale2model="semi", knots.sc=3, shapemodel="linear", int.maxit=1000, print.it=TRUE, maxit=1000 ) ``` If we want to speed up the model, we can use starting estimates (from our best model) and parameter space restrictions, like so for the constant model: ```r con.shape_faster <- lssVarReg(y=CD4$cd4, x=CD4$age, locationmodel="semi", knots.l=6, scale2model="semi", knots.sc=3, shapemodel="constant", para.space="positive", location.init = cd4.best$best.model$mean, scale2.init = cd4.best$best.model$variance, int.maxit = 10000, maxit=1000 ) ``` And compare the models as we did in the paper: ```r data.frame(Model = c("No shape", "Constant shape", "Linear shape"), AIC = c(cd4.best$best.model$aic, con.shape$aic, linear.shape$aic), BIC = c(cd4.best$best.model$bic, con.shape$bic, linear.shape$bic)) %>% kbl(digits=1, align='c', caption = "Comparison of AIC from shape models for CD4 cell counts.") %>% kable_paper(full_width = TRUE ) ```
Comparison of AIC from shape models for CD4 cell counts.
Model AIC BIC
No shape 8795.6 8861.8
Constant shape 8697.7 8768.3
Linear shape 8687.1 8762.1
And compare the residuals: ```r n<-length(CD4$age) knot6<-bs(CD4$age, df= 8, degree=2) knot3<-bs(CD4$age, df= 5, degree=2) ##normal model npred.mean<-colSums(t(cbind(rep(1,n),knot6))*cd4.best$best.model$mean) npred.var<-colSums(t(cbind(rep(1,n),knot3))*cd4.best$best.model$variance) stand.res<- (CD4$cd4-npred.mean)**2/(npred.var) chiq<-qchisq(c(1:n)/(n+1), df=1) #constant residuals con.res<-lss_calc(con.shape) con.res<-con.res[order(con.res$CD4.age),] #linear residuals lin.res<-lss_calc(linear.shape) lin.res<-lin.res[order(lin.res$CD4.age),] par(mfrow=c(1,3)) plot(chiq, sort(stand.res), main=NULL, ylim=c(0, 10), pch=19, ylab="Squared standardised residuals after fit with no shape", xlab="Chi-Square(1) quantiles") abline(0,1) mtext('A', side=3, line=2, at=0, adj=3) plot(chiq, sort(con.res$stand.res2), main=NULL, ylim=c(0, 10),pch=19, ylab="Squared standardised residuals after LSS (constant) fit", xlab="Chi-Square(1) quantiles") abline(0,1) mtext('B', side=3, line=2, at=0, adj=3) plot(chiq, sort(lin.res$stand.res2), main=NULL, ylim=c(0, 10),pch=19, ylab="Squared standardised residuals after LSS (linear) fit", xlab="Chi-Square(1) quantiles") abline(0,1) mtext('C', side=3, line=2, at=0, adj=3) ``` ![Comparison of residuals](resp-1.png) ## Viral load dataset (censored outcome data) This is a dataset of the HIV viral load (blood concentration of HIV RNA on a log10 scale) measured in 257 participants. Prior to commencing a clinical trial, participants had their blood assayed twice during a short period of time. Although the underlying viral load is unchanged in this time, the readings will differ due to measurement error. Another important aspect is that measurements cannot be detected below a particular assay limit, in this case, 2.70. Lets plot the data: ```r ggplot(rna, aes(x=x, y=y))+ geom_point()+ geom_hline(yintercept = 0)+ xlab("Mean viral load")+ ylab("Difference in viral load")+ theme_minimal() ``` ![Viral load data demonstrating measurement error](viralp-1.png) Now let us search for the optimal knots, using the censoring indicator and Monotonic decreasing model: ```r rna.best <- searchVarReg(y=rna$y, x=rna$x, maxknots.m = 5, maxknots.v = 5, mono.var = "dec", selection="AIC", maxit=1000) ``` AIC from all models: ```r rna.best$AIC %>% kbl(digits=1) ```
Mean_zero Mean_constant Mean_linear Mean_Knot0 Mean_Knot1 Mean_Knot2 Mean_Knot3 Mean_Knot4 Mean_Knot5
Var_constant 356.6 358.6 360.7 362.4 364.4 366.8 367.6 368.0 370.2
Var_linear 343.7 345.0 346.6 343.8 346.0 346.8 348.2 349.7 351.9
Var_Knot0 308.8 310.4 312.4 314.0 314.7 316.5 318.5 319.1 321.2
Var_Knot1 301.4 303.1 305.0 306.8 307.9 309.2 311.5 311.8 313.6
Var_Knot2 300.2 301.7 303.7 305.3 306.4 308.0 310.2 310.3 312.2
Var_Knot3 300.9 302.6 304.5 306.0 307.2 308.8 310.9 311.0 312.9
Var_Knot4 302.5 304.2 306.0 307.7 308.7 310.2 312.4 312.5 314.4
Var_Knot5 301.9 303.5 305.5 306.8 307.9 309.6 311.8 312.1 313.8
Find the smallest AIC: ```r min(rna.best$AIC) #> [1] 300.1673 ``` Allows increasing and decreasing: ```r rna.best2 <- searchVarReg(y=rna$y, x=rna$x, cens.ind = rna$cc, maxknots.m = 5, maxknots.v = 5, selection="AIC", maxit=1000) ``` AIC from all models: ```r rna.best2$AIC %>% kbl(digits=1) ```
Mean_zero Mean_constant Mean_linear Mean_Knot0 Mean_Knot1 Mean_Knot2 Mean_Knot3 Mean_Knot4 Mean_Knot5
Var_constant 356.6 358.6 360.7 362.4 364.4 366.8 367.6 368.0 370.2
Var_linear 343.7 345.0 346.6 343.8 346.0 346.8 348.2 349.7 351.9
Var_Knot0 364.6 366.1 368.0 365.0 367.1 368.3 369.6 371.0 373.2
Var_Knot1 323.2 325.1 327.0 327.6 329.2 330.9 333.1 332.9 334.4
Var_Knot2 299.4 300.7 302.6 303.1 304.2 306.1 308.1 308.1 309.9
Var_Knot3 299.9 301.3 303.2 303.6 304.8 306.6 308.6 308.6 310.2
Var_Knot4 300.4 302.0 303.8 304.0 304.8 306.5 308.7 308.7 310.7
Var_Knot5 301.5 303.0 304.9 304.7 305.7 307.7 309.7 310.4 311.9
Smallest AIC: ```r min(rna.best2$AIC) #> [1] 299.3517 ```