--- title: "Meta-Regression" format: html: toc: TRUE # pdf vignette: > %\VignetteIndexEntry{Meta-Regression} %\VignetteEncoding{UTF-8} %\VignetteEngine{quarto::html} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) library(dtametaTMB) ``` This vignette introduces the regression functionality of the `dtametaTMB` package for meta-analysis of diagnostic test accuracy (DTA) studies. ## Validation The subgroup HSROC and Reitsma implementations reproduce the Cochrane Handbook RF and Anti-CCP examples closely, including the baseline parameters (HSROC: accuracy, threshold, shape; Reitsma: logit sensitivity and specificity), between-study variance estimates, and subgroup effects on accuracy and threshold. The Schuetz CT/MRI analyses yielded results broadly consistent with the published subgroup parameter estimates and variance components. Likelihood-ratio tests led to identical substantive conclusions, although the LR statistics differed somewhat from the published values. ## Dummy-coding vs. cell-means parameterization For subgroup analyses, we distinguish between two equivalent parameterizations of the same model. In the reference-group parameterization, one subgroup serves as the baseline and the remaining subgroup effects are expressed as deviations from this reference. In the group-specific (cell-means) parameterization, each subgroup has its own parameter directly. The former is convenient for testing subgroup differences, whereas the latter is convenient for reporting subgroup-specific estimates and plotting subgroup-specific HSROC curves. The Reitsma subgroup model is fitted twice with both parameterizations. The subgroup HSROC model is estimated using a reference-group parameterization, and subgroup-specific parameters are recovered by evaluating the fitted linear predictors at subgroup-specific design points via $\boldsymbol{Z}_\mathrm{pred}$. ## How do we include covariates in the Reitsma model? For sensitivity in study $i$, we have the number of diseased individuals testing positive: $y_{Ai} \sim \mathcal{B}(n_{Ai},\pi_{Ai})$. Similarly for specificity, we have the number of non-diseased individuals testing negative: $y_{Bi} \sim \mathcal{B}(n_{Bi},\pi_{Bi})$. Now we introduce a $p$-dimensional design-vector $\boldsymbol{z}_i$ including study level covariates. Consequently, at the study level, we have $$ \begin{pmatrix} \boldsymbol{z}_i^{\top}\boldsymbol{\mu}_{Ai} \\ \boldsymbol{z}_i^{\top}\boldsymbol{\mu}_{Bi} \end{pmatrix} \sim \mathcal{N} \left( \begin{pmatrix} \boldsymbol{z}_i^{\top}\boldsymbol{\mu}_A \\ \boldsymbol{z}_i^{\top}\boldsymbol{\mu}_B \end{pmatrix}, \; \Sigma \right), \quad \text{with} \quad \Sigma = \begin{pmatrix} \sigma_A^2 & \sigma_{AB} \\ \sigma_{AB} & \sigma_B^2 \end{pmatrix}.$$ Let's assume that $\boldsymbol{z}_i$ includes a single binary covariate representing two subgroups. Then using dummy coding with subgroup 1 being the reference, we have $$\boldsymbol{z}_i^{\top} \boldsymbol{\mu}_{Ai} = \begin{cases} \mu_{Ai} & \text{for subgroup 1}, \\ \mu_{Ai} + \nu_{A2} & \text{for subgroup 2}, \end{cases} \quad \quad \boldsymbol{z}_i^{\top} \boldsymbol{\mu}_{Bi} = \begin{cases} \mu_{Bi} & \text{for subgroup 1}, \\ \mu_{Bi} + \nu_{B2} & \text{for subgroup 2}, \end{cases} $$ $$ \boldsymbol{z}_i^{\top} \boldsymbol{\mu}_{A} = \begin{cases} \mu_{A} & \text{for subgroup 1}, \\ \mu_{A} + \nu_{A2} & \text{for subgroup 2}, \end{cases} \quad \quad \boldsymbol{z}_i^{\top} \boldsymbol{\mu}_B = \begin{cases} \mu_{B} & \text{for subgroup 1}, \\ \mu_{B} + \nu_{B2} & \text{for subgroup 2}. \end{cases} $$ ```{r} #| echo: TRUE data("anticcp") reitsmasub <- fitReitsmaSubgroup(data=anticcp, TP=TP, FP=FP, FN=FN, TN=TN, study=study, subgroup=generation) reitsmasub summary(reitsmasub) ``` ## How do I get a summary plot of the Reitsma model? ```{r} #| fig.height: 7 #| fig.width: 8 #| echo: TRUE plot(reitsmasub, scale=0.01, nudge_legend=-0.2, size="se", col=c("black","red")) ``` ## How do I get a coupled forest plot? *Note:* Rendering forest plots may take longer in an interactive R session due to the underlying grid graphics. Performance is typically faster when knitting the vignette (e.g. via RMarkdown or Quarto). ```{r} #| fig.height: 11 #| fig.width: 13 #| echo: TRUE forest(reitsmasub,subgroup_label="Generation") ``` ## How do I constrain parameters in the Reitsma model? In sparse data one may wish to fix parameters of the random effects (variance-covariance matrix) at zero. This can be done via the `constrain` argument. For example, ```{r} #| echo: TRUE constrainA <- fitReitsmaSubgroup(data=anticcp, TP=TP, FP=FP, FN=FN, TN=TN, study=study, subgroup=generation, constrain="sigma2_A") summary(constrainA)$estimates ``` fixes the logit sensitivity variance to zero. This also implies that the random effects covariance is zero. Note that you can also set `constrain` to `"sigma_AB"`, `"sigma2_B"`, or `"all"`. Constraining fixed effects is controlled by the `sensspec_constrain` argument. For example, ```{r} #| echo: TRUE constrainsens <- fitReitsmaSubgroup(data=anticcp, TP=TP, FP=FP, FN=FN, TN=TN, study=study, subgroup=generation, sensspec_constrain="sens") summary(constrainsens)$estimates ``` assumes equal (logit) sensitivities in all subgroups. Note that you can also set `subgroup_constrain` to `"spec"` or `c("sens","spec")`. ## How can I compare `constrainsens` with the full model? We can perform a likelihood ratio test via `anova`, essentially testing whether there exist subgroup differences in sensitivity. ```{r} anova(constrainsens,reitsmasub) ``` ## How do I allow for different subgroup-specific random-effects (co-)variances in the Reitsma model? ```{r} #| fig.height: 7 #| fig.width: 8 #| echo: TRUE heteroskedastic <- fitReitsmaSubgroup(data=anticcp, TP=TP, FP=FP, FN=FN, TN=TN, study=study, subgroup=generation, variances="unequal") heteroskedastic plot(heteroskedastic, scale=0.01, nudge_legend=-0.2, size="se", col=c("black","red")) anova(reitsmasub,heteroskedastic) ``` ## How do we include covariates in the Rutter and Gatsonis model? The number of diseased individuals from study $i$ who test positive is denoted by $y_{i1} \sim \mathcal{B}(n_{i1},\pi_{i1})$. Similarly, the number of non-diseased individuals who test positive is $y_{i2} \sim \mathcal{B}(n_{i2},\pi_{i2})$. Now we introduce a $p$-dimensional design-vector $\boldsymbol{z}_i$ including study level covariates. Consequently, at the study level, we have $$\operatorname{logit}(\pi_{ij}) = \left( \boldsymbol{z}_i^{\top} \boldsymbol{\theta}_i + \boldsymbol{z}_i^{\top} \boldsymbol{\alpha}_i x_{ij} \right) \exp(-\boldsymbol{z}_i^{\top}\boldsymbol{\beta} x_{ij}), $$ $$ \boldsymbol{z}_i^{\top} \boldsymbol{\alpha}_i \sim \mathcal{N}(\boldsymbol{z}_i^{\top}\boldsymbol{\Lambda}, \sigma_\alpha^2), \quad \quad \boldsymbol{z}_i^{\top} \boldsymbol{\theta}_i \sim \mathcal{N}(\boldsymbol{z}_i^{\top}\boldsymbol{\Theta}, \sigma_\theta^2),$$ where $$x_{ij} = \begin{cases} -0.5 & \text{for non-diseased individuals}, \\ \phantom{-}0.5 & \text{for diseased individuals}. \end{cases}$$ Let's assume that $\boldsymbol{z}_i$ includes a single categorical covariate representing three subgroups. Then using dummy coding with subgroup 1 being the reference, we have $$\boldsymbol{z}_i^{\top} \boldsymbol{\theta}_i = \begin{cases} \theta_i & \text{for subgroup 1}, \\ \theta_i + \gamma_2 & \text{for subgroup 2},\\ \theta_i + \gamma_3 & \text{for subgroup 3}, \end{cases} \quad \quad \boldsymbol{z}_i^{\top} \boldsymbol{\alpha}_i = \begin{cases} \alpha_i & \text{for subgroup 1}, \\ \alpha_i + \xi_2 & \text{for subgroup 2},\\ \alpha_i + \xi_3 & \text{for subgroup 3}, \end{cases} $$ $$\boldsymbol{z}_i^{\top} \boldsymbol{\beta} = \begin{cases} \beta & \text{for subgroup 1}, \\ \beta + \delta_2 & \text{for subgroup 2},\\ \beta + \delta_3 & \text{for subgroup 3}, \end{cases}$$ $$\boldsymbol{z}_i^{\top} \boldsymbol{\Lambda} = \begin{cases} \Lambda & \text{for subgroup 1}, \\ \Lambda + \xi_2 & \text{for subgroup 2},\\ \Lambda + \xi_3 & \text{for subgroup 3}, \end{cases} \quad \quad \boldsymbol{z}_i^{\top} \boldsymbol{\Theta}_i = \begin{cases} \Theta & \text{for subgroup 1}, \\ \Theta + \gamma_2 & \text{for subgroup 2},\\ \Theta +\gamma_3 & \text{for subgroup 3}. \end{cases}$$ *Note:* For prediction `fitRutterGatsonisSubgroup()` uses the prediction matrix $$\boldsymbol{Z}_{\mathrm{pred}}=\begin{pmatrix} 1 & 0 & 0 \\ 1 & 1 & 0 \\ 1 & 0 & 1 \end{pmatrix}$$ for the case above and therefore recovers the threshold, accuracy, and shape parameters for each subgroup as if it were the reference group. ## How do I perform a Rutter and Gatsonis meta-regression with a single categorical study-level covariate? ```{r} #| echo: TRUE #| results: 'hide' data("RF") RF2 <- RF[RF$method %in% c("LA","ELISA","Nephelometry"),] RF2$method <- factor(RF2$method,levels=c("LA","ELISA","Nephelometry")) ruttergatsonissub <- fitRutterGatsonisSubgroup(data=RF2, TP=TP, FP=FP, FN=FN, TN=TN, study=study, subgroup=method, constrain="shape") # assumes equal # shapes in subgroups ``` ```{r} #| echo: TRUE ruttergatsonissub summary(ruttergatsonissub) ``` ## How do I get a summary plot of the Rutter and Gatsonis subgroup model? ```{r} #| fig.height: 6 #| fig.width: 8 #| echo: TRUE plot(ruttergatsonissub, specrange=c(0.3,0.995), size="se", col=c("red","black","green"), scale=0.015) ``` ## How do I get a coupled forest plot? *Note:* Rendering forest plots may take longer in an interactive R session due to the underlying grid graphics. Performance is typically faster when knitting the vignette (e.g. via RMarkdown or Quarto). ```{r} #| fig.height: 13 #| fig.width: 13 #| echo: TRUE forest(ruttergatsonissub,subgroup_label = "Method") ``` ## How do I constrain parameters in the Rutter and Gatsonis subgroup model? In the Rutter and Gatsonis model, all parameter constraints are controlled by `constrain`, i.e., - `constrain="sigma2_alpha"` sets $\sigma_\alpha^2$ to zero, - `constrain="sigma2_theta"` sets $\sigma_\theta^2$ to zero, - `constrain="accuracy"` assumes equal accuracy parameters across subgroups, i.e. $\xi_2=\xi_3=\dots=0$, - `constrain="threshold"` assumes equal threshold parameters across subgroups, i.e. $\gamma_2=\gamma_3=\dots=0$, - `constrain="shape"` assumes equal shape parameters across subgroups, i.e. $\delta_2=\delta_3=\dots=0$, - `constrain="shape_zero"` fixes all shape parameters at zero. Constraints can also be combined, for example `constrain=c("shape","sigma2_theta")`. ## How do I use the general Rutter and Gatsonis regression function? This method is for advanced users who feel comfortable specifying their own design and prediction matrices. For study-level covariates, the design matrix $\boldsymbol{Z}$ needs two identical consecutive rows per study, one for the diseased and one for the non-diseased. Of note, there are neither `plot()` nor `forest()` methods for `fitRutterGatsonisReg()`. Let's reproduce the subgroup-analysis from before. ```{r} #| echo: TRUE # Specify design matrix Z Z <- model.matrix(~method,data=RF2) # For study level-covariates, we need to two identical consecutive # rows per study (diseased and non-diseased). Z2 <- Z[rep(seq_len(nrow(Z)), each = 2), , drop = FALSE] # Specify prediction matrix Z_pred Z_pred <- matrix(c(1,0,0,1,1,0,1,0,1),ncol=3,nrow=3,byrow=T) constrain <- list(shape_coef=factor(c(1, rep(NA, ncol(Z2) - 1)))) ruttergatsonisreg <- fitRutterGatsonisReg(data=RF2, TP=TP, FP=FP, FN=FN, TN=TN, study=study, Z=Z2, Z_pred=Z_pred, map=constrain) ruttergatsonisreg summary(ruttergatsonisreg) ``` ## How do I compare models? In the previous section we fitted the `RF` data set using the Rutter and Gatsonis subgroup model while keeping the shape parameter equal across all subgroups `constrain="shape"`. Now let's fit the full model allowing for different shape parameters across subgroups and check whether the data lend support to this approach. ```{r} #| echo: TRUE ruttergatsonissubfull <- fitRutterGatsonisSubgroup(data=RF2, TP=TP, FP=FP, FN=FN, TN=TN, study=study, subgroup=method, constrain=NULL) ruttergatsonissubfull summary(ruttergatsonissubfull) ``` ## How do I get the log likelihood, the AIC, and the BIC of a model? ```{r} #| echo: TRUE logLik(ruttergatsonissubfull) AIC(ruttergatsonissubfull) BIC(ruttergatsonissubfull) logLik(ruttergatsonissub) AIC(ruttergatsonissub) BIC(ruttergatsonissub) ``` ## How do I perform a likelihood ratio test of the two models? The test below formally investigates whether the HSROC curve shapes are equal in all subgroups. ```{r} #| echo: TRUE anova(ruttergatsonissub, ruttergatsonissubfull) ``` ## How do I replicate results from the Cochrane Handbook with respect to the `schuetz` data set? ## What are the results for the full data set? ```{r} #| echo: TRUE #| fig.height: 6 #| fig.width: 8 data(schuetz) head(schuetz) schuetz$test <- factor(schuetz$test,levels=c("MRI","CT")) schuetzreitsma <- fitReitsmaSubgroup(data=schuetz, TP=TP,FP=FP,FN=FN,TN=TN, study=study, subgroup=test) schuetzreitsma summary(schuetzreitsma) plot(schuetzreitsma, nudge_legend=-0.2, size="se", col=c("red","black")) schuetzreitsma2 <- fitReitsmaSubgroup(data=schuetz, TP=TP,FP=FP,FN=FN,TN=TN, study=study, subgroup=test, sensspec_constrain="sens") schuetzreitsma3 <- fitReitsmaSubgroup(data=schuetz, TP=TP,FP=FP,FN=FN,TN=TN, study=study, subgroup=test, sensspec_constrain="spec") anova(schuetzreitsma2,schuetzreitsma) anova(schuetzreitsma3,schuetzreitsma) ``` ## What are the results for the direct comparisons? ```{r} #| echo: TRUE #| fig.height: 6 #| fig.width: 8 schuetz2 <- subset(schuetz,indirect==0) schuetzreitsma4 <- fitReitsmaSubgroup(data=schuetz2, TP=TP,FP=FP,FN=FN,TN=TN, study=study, subgroup=test, constrain="sigma2_A") round(summary(schuetzreitsma4)$estimates,5) plot(schuetzreitsma4,predlevel=0.000001, nudge_legend=-0.2, size="se",scale=0.0025, connectstudies = TRUE, col=c("red","black")) ``` ## References Reitsma, J. B., et al. (2005). Bivariate analysis of sensitivity and specificity produces informative summary measures in diagnostic reviews. *Journal of Clinical Epidemiology*, 58(10), 982–990. Rutter, C. M., & Gatsonis, C. A. (2001). A hierarchical regression approach to meta-analysis of diagnostic test accuracy evaluations. *Statistics in Medicine*, 20(19), 2865–2884. Harbord, R. M., Deeks, J. J., Egger, M., Whiting, P., & Sterne, J. A. C. (2007). A unification of models for meta-analysis of diagnostic accuracy studies. *Biostatistics*, 8(2), 239–251. Riley, R. D., Ensor, J., Jackson, D., & Burke, D. L. (2018). Deriving percentage study weights in multi-parameter meta-analysis models. *Statistical Methods in Medical Research*, 27(10), 2885–2905. Hoyer, A., Hirt, S., Kuss, O. (2018). Meta-analysis of full ROC curves using bivariate time-to-event models for interval-censored data. *Research Synthesis Methods*, 9(1), 62-72. Deeks, J. J., Bossuyt, P. M., Leeflang, M. M., & Takwoingi, Y. (editors) (2023). Cochrane Handbook for Systematic Reviews of Diagnostic Test Accuracy. Version 2.0 (updated July 2023). *Cochrane.*