---
title: "Cox Mixed-Effects Models for Genome-Wide Association Studies"
author: "Liang He"
date: "`r Sys.Date()`"
bibliography: "references.bib"
output:
  html_document:
    toc: yes
  md_document:
    toc: yes
vignette: >
  %\VignetteIndexEntry{Cox Mixed-Effects Models for Genome-Wide Association Studies}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
---

```{r, message=FALSE, warning=FALSE,echo=FALSE}
# library(knitcitations)
# cleanbib()
# options("citation_format" = "pandoc")
# r<-citep("10.1534/genetics.119.302940")
# write.bibtex(file="references.bib")
```

# coxmeg 1.1.4

## Overview

Time-to-event is one of the most important phenotypes in genetic epidemiology. The R-package, "coxmeg", provides a set of utilities to fit a Cox mixed-effects model and to efficiently perform genome-wide association analysis of time-to-event phenotypes using a Cox mixed-effects model. More details can be found in [@He_2020].

## Installation

The R package can be installed from CRAN
```{r,eval=FALSE}
install.packages("coxmeg")
```

### Most recent version
```{r,eval=FALSE}
install.packages("devtools")
library(devtools)
install_github("lhe17/coxmeg")
```

## Functions

The current version provides five functions.

  *  `coxmeg`: Fit a Cox mixed-effects model.
  *  `coxmeg_m`: Perform a GWAS using a genotype matrix.
  *  `coxmeg_plink`: Perform a GWAS using plink files.
  *  `coxmeg_gds`: Perform a GWAS using a GDS file. Read more details [here](./coxmeg_gds_example.html).
  *  `fit_ppl`: Estimate hazard ratios (HRs) given a variance component.

## Fit a Cox mixed-effects model with a sparse relatedness matrix

We illustrate how to use ```coxmeg``` to fit a Cox mixed-effects model with a sparse relatedness matrix. We first simulate a block-diagonal relatedness matrix for a cohort consisting of 200 families, each of which has five members. We use 'dgCMatrix' to save memory. 

```{r,echo=TRUE}
library(coxmeg)
library(MASS)
library(Matrix)
n_f <- 200
mat_list <- list()
size <- rep(5,n_f)
offd <- 0.5
for(i in 1:n_f)
{
  mat_list[[i]] <- matrix(offd,size[i],size[i])
  diag(mat_list[[i]]) <- 1
}
sigma = as(bdiag(mat_list),'dgCMatrix')
sigma[1:5,1:5]
```

Next, we simulate random effects, censoring variables, and time-to-event outcomes assuming a constant baseline hazard function. We assume that the variance component is 0.2 and simulate a continuous variable with the effect of log(HR)=0.1. 

```{r,echo=TRUE}
n = nrow(sigma)
tau_var <- 0.2
x <- mvrnorm(1, rep(0,n), tau_var*sigma)
pred = rnorm(n,0,1)
myrates <- exp(x+0.1*pred-1)
y <- rexp(n, rate = myrates)
cen <- rexp(n, rate = 0.02 )
ycen <- pmin(y, cen)
outcome <- cbind(ycen,as.numeric(y <= cen))
head(outcome)
```

We fit a Cox mixed-effects model using the function ```coxmeg```.

```{r,echo=TRUE}
re = coxmeg(outcome,sigma,type='bd',X=pred,order=1,detap='diagonal')
```

Here, we set ```type='bd'``` because the relatedness matrix is a block-diagonal matrix. Note that ```type='bd'``` should be used only for a block-diagonal matrix or a sparse matrix of which the inverse matrix is also highly sparse. A sparse kinship matrix can be converted to a block-diagonal matrix using [kingToMatrix](./coxmeg_gds_example.html). For a general sparse relatedness matrix of which the inverse is not sparse, it is recommended that ```type='sparse'``` be used. However, if there are more than 50% non-zero elements in the matrix, ```coxmeg``` will ignore this argument and automatically treat the relatedness matrix as dense. The argument ```X``` is a design matrix of the predictors, which can be produced by e.g., the function ```model.matrix```. The design matrix for the Cox model does not include the intercept term. The columns in ```X``` should be linearly independent; otherwise the function will stop with an error indicating sigularity.    

```{r,echo=TRUE}
re
```

In the above result, ```tau``` is the estimated variance component, and ```int_ll``` is -2*log(lik) of the integrated/marginal likelihood for estimating ```tau```. 

We give more details about specifying ```order``` and ```detap```. The argument ```order=1``` (by default) uses the first-order approximation of the inverse Hessian matrix in the optimization, which works well in most general situations (See [@He_2020] for more details). By ```detap='diagonal'```, we tell ```coxmeg``` to use a diagonal approximation to compute the determinant, which is much faster under this setting, when estimating the variance component. By default (```detap='NULL'```), ```coxmeg``` will automatically select a method for computing the determinant based on ```type```, the sample size, and whether the relatedness matrix is symmetric positive definite (SPD).

We compare the results with coxme, which are slightly different due to different approximation of the log-determinant used in the estimation of the variance component. Also, the integrated log-likelihoods cannot be compared directly because different approximation of log-determinant is used.

```{r,echo=TRUE}
library(coxme)
bls <- c(1)
for(i in (size[1]-1):1)
{bls <- c(bls, c(rep(offd,i),1))}
tmat <- bdsmatrix(blocksize=size, blocks=rep(bls,n_f),dimnames=list(as.character(1:n),as.character(1:n)))
re_coxme = coxme(Surv(outcome[,1],outcome[,2])~as.matrix(pred)+(1|as.character(1:n)), varlist=list(tmat),ties='breslow')
re_coxme
```

In GWAS, we may split the procedure into two separate steps, (1) estimate the variance component under the null model, and (2) estimate the coefficients for the predictors using the estimated variance component. This can be carried out in the following way.
```{r,echo=TRUE}
re = coxmeg(outcome,sigma,type='bd',order=1,detap='diagonal')
tau = re$tau
print(tau)
re2 = fit_ppl(pred,outcome,sigma,type='bd',tau=tau,order=1)
re2
```

## Perform GWAS of an age-at-onset phenotype with a sparse relatedness matrix

We illustrate how to perform a GWAS using the ```coxmeg_plink``` function. This function supports plink bed files. We provide example files in the package. The example plink files include 20 SNPs and 3000 subjects from 600 families. The following code performs a GWAS for all SNPs in the example bed files. The ```coxmeg_plink``` function will write a temporary .gds file for the SNPs in the folder specified by ```tmp_dir```. The user needs to specify a ```tmp_dir``` to store the temporary file when ```bed``` is provided. The temporary file is removed after the analysis is done. 

```{r,echo=TRUE}
library(coxmeg)
bed = system.file("extdata", "example_null.bed", package = "coxmeg")
bed = substr(bed,1,nchar(bed)-4)
pheno = system.file("extdata", "ex_pheno.txt", package = "coxmeg")
cov = system.file("extdata", "ex_cov.txt", package = "coxmeg")

## building a relatedness matrix
n_f <- 600
mat_list <- list()
size <- rep(5,n_f)
offd <- 0.5
for(i in 1:n_f)
{
  mat_list[[i]] <- matrix(offd,size[i],size[i])
  diag(mat_list[[i]]) <- 1
}
sigma <- as.matrix(bdiag(mat_list))

re = coxmeg_plink(pheno,sigma,type='bd',bed=bed,tmp_dir=tempdir(),cov_file=cov,verbose=FALSE)
re
```

The above code first retrieves the full path of the files. If the full path is not given, ```coxmeg_plink``` will search the current working directory. The file name of the bed file should not include the suffix (.bed). The phenotype and covariate files have the same format as used in plink, and the IDs must be consistent with the bed files. Specifically, the phenotype file should include four columns including family ID, individual ID, time, and status. The covariate file always starts with two columns, family ID and individual ID. Missing values in the phenotype and covariate files are denoted by -9 and NA, respectively. Note that ```coxmeg_plink``` does not impute genotypes itself, and only SNPs without missing values will be analyzed. Therefore, it will be better to use imputed genotype data for ```coxmeg_plink```. 

The ```coxmeg_plink``` function first estimates the variance component(s) with only the covariates, and then uses it to analyze each SNP after filtering. These two steps can be done separately as follows. The first command without ```bed``` only esitmates the variance component tau, and the second command uses the estimated tau to analyze the SNPs. 

```{r,eval=FALSE}
re = coxmeg_plink(pheno,sigma,type='bd',cov_file=cov,verbose=FALSE)
re = coxmeg_plink(pheno,sigma,type='bd',bed=bed,tmp_dir=tempdir(),tau=re$tau,cov_file=cov,verbose=FALSE)
```

When the genotypes of a group of SNPs are stored in a matrix object, the function ```coxmeg_m``` instead can be used to perform GWAS for each of these SNPs. Similarly, ```coxmeg_m``` first estimates the variance component with only the covariates. In the following example, we simulate 10 independent SNPs, and use ```coxmeg_m``` to perform an association analysis. By default, ```coxmeg_m``` and ```coxmeg_plink``` will choose an optimal ```order``` between 1 and 10 for analyzing the SNPs when ```order``` is not specified.

```{r,echo=TRUE}
geno = matrix(rbinom(nrow(sigma)*10,2,runif(nrow(sigma)*10,0.05,0.5)),nrow(sigma),10)
pheno_m = read.table(pheno)
re = coxmeg_m(geno,pheno_m[,3:4],sigma,type='bd',verbose=FALSE)
re
```

## Perform GWAS of an age-at-onset phenotype with a dense relatedness matrix

When the relatedness matrix is dense, ```type='dense'``` should be used. In this case, it will be more efficient to use preconditioned conjugate gradient (PCG) (```solver=2```) and stochastic Lanczos quadrature (SLQ) (```detap='slq'``` or ```detap='gkb'```) in the optimization if the sample size is large (>5000). These can be specified as follows.

```{r,echo=TRUE,eval=FALSE}
re = coxmeg_plink(pheno,sigma,type='dense',bed=bed,tmp_dir=tempdir(),cov_file=cov,detap='slq',verbose=FALSE,solver=2)
```

If ```solver``` is not specified, ```coxmeg_plink``` will by default choose PCG as a solver when ```type='dense'```. If ```detap``` is not specified, ```coxmeg_plink``` will by default use ```detap='gkb'``` for a dense matrix when the sample size exceeds 5000. The number of Monte Carlo samples in the SLQ can be specified by ```mc``` (by default ```mc=100```). The difference between ```detap='slq'``` and ```detap='gkb'``` is that the former might be inaccurate when the relatedness matrix is almost singular (e.g., a kinship matrix including many monozygotic (MZ) twins) and the latter is robust against the singularity. However, ```detap='slq'``` is faster by ~50% than ```detap='gkb'``` when ```type='dense'```. In the above example, the relatedness matrix is well conditioned, so ```detap='slq'``` works properly.  

The above command estimates HRs and reports p-values. Instead, a score test, which is computationally much more efficient, can be used by specifying ```score=TRUE```.  

```{r,echo=TRUE}
re = coxmeg_plink(pheno,sigma,type='dense',bed=bed,tmp_dir=tempdir(),tau=re$tau,cov_file=cov,detap='slq',verbose=FALSE,solver=2,score=TRUE)
re
```

In this result, the column ```score_test``` is the score test statistic, which follows a $\chi^2$ distribution with 1 d.f. The column ```score``` is the score function divided by its variance. Note that ```score``` is not the estimate of log(HR) under the full model. It is actually a one-step update of the Newton-Raphson algorithm starting from the values estimated under the null model. Comparing ```score``` with log(HR) estimated in the previous section, we see that they are close to each other in this example. However, the difference can be large if the genotype is highly correlated with the covariates or random effects.  

## Handle positive semidefinite relatedness matrices

We now assume that the first two subjects in the sample are MZ twins. In this case, the relatedness matrix becomes positive semidefinite. Specifying ```spd=FALSE``` will let ```coxmeg_plink``` handle a positive semidefinite relatedness matrix.

```{r,echo=TRUE}
sigma[2,1] = sigma[1,2] = 1
re = coxmeg_plink(pheno,sigma,type='bd',cov_file=cov,verbose=FALSE,spd=FALSE)
re
```

If the user is not sure whether the relatedness matrix is positive definite or positive semidefinite, it is better to use ```spd=FALSE``` although this might be slower because ```coxmeg_plink``` will check the smallest eigenvalue. In the current version, instead of using the previously proposed GPPL in [@He_2020], coxmeg performs an eigenvalue decomposition if ```type='dense'``` and uses a modified PPL by turning all zero eigenvalues of the relatedness matrix to a small value (1e-6). This modification makes coxmeg suitable for twin cohorts. If ```type='sparse'```, coxmeg will add a small value (1e-6) to the diagonal to make it positive definite. 

## Use multiple relatedness matrices

Multiple correlation matrices might be needed in some situations, e.g., twin studies. In a twin study, the dependence between twins can be further decomposed into the additive genetic component and the shared environmental component, and thus requires two correlation matrices. The coxmeg R package can handle multiple correlation matrices. As an example, we first construct the second correlation matrix, for which we want to estimate its variance component. We then build a List object containing these two correlation matrices.

```{r,echo=TRUE}
## building two relatedness matrices and put them in a List
n_f <- 200
mat_list <- list()
size <- rep(5,n_f)
offd <- 0.5
for(i in 1:n_f)
{
  mat_list[[i]] <- matrix(offd,size[i],size[i])
  diag(mat_list[[i]]) <- 1
}
sigma = as(bdiag(mat_list),'dgCMatrix')

n_f <- 500
mat_list <- list()
size <- rep(2,n_f)
offd <- 0.9
for(i in 1:n_f)
{
  mat_list[[i]] <- matrix(offd,size[i],size[i])
  diag(mat_list[[i]]) <- 1
}
sigma2 = as(bdiag(mat_list),'dgCMatrix')
sigmas <- list(sigma,sigma2)

## run coxmeg
re = coxmeg(outcome,sigmas,type='bd',X=pred,order=1,detap='diagonal')
re
```

The sum of these correlation matrices determines which value should be specified for ```type```. As shown in the above example, because the sum of the matrices is still block diagonal, ```type='bd'``` is appropriate. If all of these matrices are sparse but not all of them are block diagonal, then ```type='sparse'``` is a good option. On the other hand, if one of these matrices is dense, then ```type='dense'``` should be used. In the current version, ```spd=FALSE``` is not supported for multiple matrices, which means that the sum of the matrices must be positive definite. A sufficient condition is that one of the matrices is positive definite. 

## References
