The R package can be installed from CRAN
The installation requires Rcpp-0.11.1 and has been tested on R-4.1.3. The installation of the ACEt package also requires installing the BH and RcppArmadillo packages.
Please contact [email protected] for more information.
We illustrate how to utilize the ACEt R package with an example dataset that can be loaded with the following codes. More detail about the method is given in He et al. (2016) and He et al. (2017).
The example dataset contains two matrices mz
and
dz
for MZ and DZ twins, respectively. Each matrix includes
2500 twin pairs, of which the first two columns are the quantitative
phenotype of the twin pair and the third column (T_m
or
T_d
) is age.
attributes(data_ace)
#> $names
#> [1] "mz" "dz"
head(data_ace$mz)
#> T_m
#> [1,] 2.5638027 4.7355457 1
#> [2,] -3.1959902 -3.0133873 1
#> [3,] 1.3924694 2.8656795 1
#> [4,] 2.4519483 1.9145994 1
#> [5,] -0.4186678 1.3470608 1
#> [6,] -1.2805044 -0.5234272 1
head(data_ace$dz)
#> T_d
#> [1,] 0.1402850 -0.3430456 1
#> [2,] 0.8588600 -0.7381698 1
#> [3,] 0.4025476 0.2794685 1
#> [4,] -0.4564107 0.2008932 1
#> [5,] -0.2458682 -3.0600677 1
#> [6,] 0.1459282 0.4588418 1
The age is distributed uniformly from 1 to 50 in both twin datasets
and the phenotypes are normally distributed with a mean equal to zero.
As discussed in He et al. (2017), before
used as an input for this package, the phenotype should be centered, for
example, by using residuals from a linear regression model
lm()
in which covariates for the mean function can be
included. Fitting an ACE(t) model can be done by calling the
AtCtEt
function, in which users can specify a function
(null, constant or splines) for each of the A, C, and E components
independently through the mod
argument.
# fitting the ACE(t) model
re <- AtCtEt(data_ace$mz, data_ace$dz, mod = c('d','d','c'), knot_a = 6, knot_c = 4)
summary(re)
#> Length Class Mode
#> n_beta_a 1 -none- numeric
#> n_beta_c 1 -none- numeric
#> n_beta_e 1 -none- numeric
#> beta_a 7 -none- numeric
#> beta_c 5 -none- numeric
#> beta_e 1 -none- numeric
#> hessian_ap 169 -none- numeric
#> hessian 169 -none- numeric
#> con 1 -none- numeric
#> lik 1 -none- numeric
#> knots_a 10 -none- numeric
#> knots_c 8 -none- numeric
#> knots_e 2 -none- numeric
#> min_t 1 -none- numeric
#> max_t 1 -none- numeric
#> boot 0 -none- NULL
In the above script, an ACE(t) model is fitted for the example
dataset. The first two arguments specify the matrices of the phenotypes
for MZ and DZ twins, respectively. The argument
mod = c('d','d','c')
specifies that we allow the variances
of the A and C components to change dynamically and assume the variance
of the E component to be a constant over age. The mod
argument is a vector of three elements corresponding to the A, C and E
components that can be 'd', 'c' or 'n'
, in which
'n'
represents the exclusion of a component. For example,
mod = c('d','n','c')
indicates that we fit an AE model with
a dynamic A component and a constant E component. It should be noted
that the E component cannot be eliminated. We can also give the number
of knots for each component, which is ignored if we choose
'c'
or 'n'
for that component. The number of
randomly generated initial values for the estimation algorithm can be
specified using the robust
argument. Multiple initial
values can be attempted to minimize the risk of missing the global
maximum. The AtCtEt
function returns both an expected and
an approximate observed Fisher information matrices (shown below), which
are close to each other in general and can be used to compute pointwise
CIs. Note that the expected information matrix is always positive
(semi)definite, but the approximated one is not necessarily positive
definite. The returned value lik
is the negative
log-likelihood that can be used for LRT for the comparison of twin
models.
# part of the expected information matrix
re$hessian[1:8,1:8]
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 3.3691795 8.660392 0.9796104 0.00000000 0.000000 0.000000
#> [2,] 8.6603922 64.693471 43.2278904 2.22600739 0.000000 0.000000
#> [3,] 0.9796104 43.227890 145.4602856 68.16259581 2.844811 0.000000
#> [4,] 0.0000000 2.226007 68.1625958 182.81270897 68.628769 2.329897
#> [5,] 0.0000000 0.000000 2.8448115 68.62876903 155.464195 54.987625
#> [6,] 0.0000000 0.000000 0.0000000 2.32989655 54.987625 113.808009
#> [7,] 0.0000000 0.000000 0.0000000 0.00000000 1.851546 23.127047
#> [8,] 4.9367150 13.554520 2.7642460 0.02667669 0.000000 0.000000
#> [,7] [,8]
#> [1,] 0.000000 4.93671496
#> [2,] 0.000000 13.55452014
#> [3,] 0.000000 2.76424605
#> [4,] 0.000000 0.02667669
#> [5,] 1.851546 0.00000000
#> [6,] 23.127047 0.00000000
#> [7,] 11.226999 0.00000000
#> [8,] 0.000000 10.92325923
# part the observed information matrix approximated by the L-BFGS algorithm
re$hessian_ap[1:8,1:8]
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 3.3700958 8.682584 0.9796059 0.0000000 0.000000 0.000000
#> [2,] 8.6825844 64.765139 43.1405091 2.2330647 0.000000 0.000000
#> [3,] 0.9796059 43.140509 145.1005156 68.1315956 2.845074 0.000000
#> [4,] 0.0000000 2.233065 68.1315956 181.6575369 67.476270 2.307737
#> [5,] 0.0000000 0.000000 2.8450740 67.4762696 154.981519 55.358617
#> [6,] 0.0000000 0.000000 0.0000000 2.3077368 55.358617 114.974072
#> [7,] 0.0000000 0.000000 0.0000000 0.0000000 1.868206 23.819879
#> [8,] 5.0693301 13.343929 2.7063748 0.0255968 0.000000 0.000000
#> [,7] [,8]
#> [1,] 0.000000 5.0693301
#> [2,] 0.000000 13.3439295
#> [3,] 0.000000 2.7063748
#> [4,] 0.000000 0.0255968
#> [5,] 1.868206 0.0000000
#> [6,] 23.819879 0.0000000
#> [7,] 11.641638 0.0000000
#> [8,] 0.000000 10.9801828
The AtCtEt
function returns the minus log-likelihood
evaluated at the estimates that is needed to make inference based on
LRT. For example, the following program tests whether the A or C
component has a constant variance with respect to age, we fit the null
models and calculate the p-values based on χ2 distributions. It can
be seen that the LRT has no sufficient statistical power to reject the
constancy of the C component with this sample size
(p1>0.05
). In addition, we test whether the C component
can be ignored by comparing re_cc
and re_cn
and compute the p-value (p3
) based on a mixture of χ2 distributions.
re_cc <- AtCtEt(data_ace$mz, data_ace$dz, mod = c('d','c','c'), knot_a = 6, knot_c = 4)
p1 <- pchisq(2*(re_cc$lik-re$lik), 4, lower.tail=FALSE)
p1
#> [1] 0.2076328
re_ac <- AtCtEt(data_ace$mz, data_ace$dz, mod = c('c','d','c'), knot_a = 6, knot_c = 4)
p2 <- pchisq(2*(re_ac$lik-re$lik), 6, lower.tail=FALSE)
p2
#> [1] 8.921199e-12
re_cn <- AtCtEt(data_ace$mz, data_ace$dz, mod = c('d','n','c'), knot_a = 6, knot_c = 4)
p3 <- 0.5*pchisq(2*(re_cn$lik-re_cc$lik), 1, lower.tail=FALSE)
p3
#> [1] 2.155026e-08
After fitting the ACE(t) model, we can plot the estimated variance
curves by calling the plot_acet
function.
By default, the 95% pointwise CIs are estimated using the delta
method. Alternatively, we can choose the bootstrap method by setting
boot=TRUE
and giving the number of bootstrap resampling,
the default value of which is 100.
## fitting an ACE(t) model with the CIs esitmated by the bootstrap method
re_b <- AtCtEt(data_ace$mz, data_ace$dz, mod = c('d','d','c'), knot_a = 6, knot_c = 4, boot = TRUE,
num_b = 60)
plot_acet(re_b, boot = TRUE)
Next, we plot the age-specific heritability by setting the argument
heri=TRUE
in the plot_acet
function. And
similarly we can choose either the delta method or the bootstrap method
to generate the CIs.
## plot dynamic heritability with the CIs using the delta method
plot_acet(re_b, heri=TRUE, boot = FALSE)
## plot dynamic heritability with the CIs using the bootstrap method
plot_acet(re_b, heri=TRUE, boot = TRUE)
An ADE(t) model can be fitted and plotted similarly using the
AtDtEt
function as shown below.
## fitting an ADE(t) model with the CIs esitmated by the bootstrap method
re_b <- AtDtEt(data_ace$mz, data_ace$dz, mod = c('d','d','c'), boot = TRUE, num_b = 60)
plot_acet(re_b, boot = TRUE)
An ACE(t)-p model is a more stable model, which reduces the
sensitivity to the number of knots by using P-splines. The ACE(t)-p
model is implemented in the AtCtEtp
function, in which
users can choose exponential of penalized splines, a linear function or
a constant to model a certain component by setting the mod
argument. Compared to the ACE(t) model, it is not an essential problem
to provide an excessive number of knots (the default value of interior
knots is 8) when using the ACE(t)-p model as it is more important to
ensure adequate knots for curves with more fluctuation than to avoid
overfitting. Below, we fit the example dataset using the
AtCtEtp
function in which the A and C components are
modelled by B-splines of 8 interior knots and the E component by a
log-linear function. Similar to the AtCtEt
function, we can
use the robust
argument to specify the number of randomly
generated initial values, which can reduce the program’s possibility of
being stuck on a local maximum in the EM algorithm.
## fitting an ACE(t)-p model
re <- AtCtEtp(data_ace$mz, data_ace$dz, knot_a = 8, knot_c = 8, mod=c('d','d','l'))
summary(re)
#> Length Class Mode
#> D_a 81 -none- numeric
#> D_c 81 -none- numeric
#> D_e 4 -none- numeric
#> pheno_m 5000 -none- numeric
#> pheno_d 5000 -none- numeric
#> T_m 5000 -none- numeric
#> T_d 5000 -none- numeric
#> knot_a 12 -none- numeric
#> knot_c 12 -none- numeric
#> knot_e 2 -none- numeric
#> beta_a 9 -none- numeric
#> beta_c 9 -none- numeric
#> beta_e 2 -none- numeric
#> con 1 -none- numeric
#> lik 1 -none- numeric
#> iter 4 -none- numeric
#> var_b_a 1 -none- numeric
#> var_b_c 1 -none- numeric
#> var_b_e 1 -none- numeric
#> mod 3 -none- character
#> hessian 9 -none- numeric
The AtCtEtp
function finds MLE of the variance σβA, C, E2
using the integrated likelihood and also provides estimates of the
spline coefficients, i.e. βA, C, E,
which are based on maximum a posteriori (MAP) estimation. For a variance
component of log-linearity (the E component in this example), β is a vector of two elements that
exp(β)
are the variances of this component at the minimum and maximum age in
the dataset. To obtain the empirical Bayes estimates of βA, C, E
and the covariance matrix using the MCMC method, we then call the
acetp_mcmc
function by plugging the result from the
AtCtEtp
function. We can also specify the numbers of the
MCMC iterations and burn-in.
re_mcmc <- acetp_mcmc(re, iter_num = 5000, burnin = 500)
summary(re_mcmc)
#> Length Class Mode
#> beta_a_mc 9 -none- numeric
#> beta_c_mc 9 -none- numeric
#> beta_e_mc 2 -none- numeric
#> cov_mc 400 -none- numeric
#> knots_a 12 -none- numeric
#> knots_c 12 -none- numeric
#> knots_e 2 -none- numeric
#> min_t 1 -none- numeric
#> max_t 1 -none- numeric
Given the esimates together with their covariance matrix, we can plot
the variance curves or dynamic heritability by calling the
plot_acet
function. The boot
option is ignored
for the ACE(t)-p model.
Assigning too many knots in the ACE(t)-p model is much less harmful than that in the ACE(t) model. Comparing the following two plots from the application of the two models with 10 knots for each component to the example data set, it suggests that the ACE(t) model has an overfitting problem but the ACE(t)-p model works properly.
Finally, we give an example to test a linear or constant variance
curve. The test_acetp
function is dedicated to the model
comparison for the ACE(t)-p model and returns a p-value from LRT using a
resampling method for testing log-linearity or from a χ2 distribution for
testing constancy. First, the following code tests whether the E
component is invariant with age. Before testing, we need to fit the data
using the AtCtEtp
function and obtain an
AtCtEtp_model
object re
. Note that when
testing a constant component, the component must be specified as
log-linear when fitting the model (as shown above).
test <- test_acetp(re, comp = 'e')
#> Model comparison:
#> [1] "Constancy (null) vs. Log-linear"
test$p
#> [,1]
#> [1,] 0.2178194
The result suggests that the E component is time-invariant as the p-value is larger than 0.05. Next, we test whether a log-linear model would be fitted better for the C component.
The result (p>0.05) shows that the null hypothesis of the log-linearity is not rejected.