From 2f1b7fe49ee3a51f2307fdfa087b9bf4d3173dff Mon Sep 17 00:00:00 2001 From: Marco Nijmeijer Date: Fri, 17 Feb 2017 13:38:14 +0000 Subject: [PATCH] version 1.0.0 --- DESCRIPTION | 18 ++ MD5 | 66 +++++ NAMESPACE | 20 ++ R/AIC.lmvar.R | 18 ++ R/alias.lmvar.R | 53 ++++ R/beta_sigma_names.R | 57 +++++ R/coef.lmvar.R | 54 ++++ R/df.residual.lmvar.R | 23 ++ R/dfree.R | 46 ++++ R/examples/AIC_examples.R | 8 + R/examples/alias_examples.R | 31 +++ R/examples/beta_sigma_names_examples.R | 13 + R/examples/coef_examples.R | 25 ++ R/examples/df.residual_examples.R | 26 ++ R/examples/dfree_examples.R | 23 ++ R/examples/fisher_examples.R | 23 ++ R/examples/fitted_examples.R | 47 ++++ R/examples/lmvar_examples.R | 32 +++ R/examples/logLik_examples.R | 21 ++ R/examples/nobs_examples.R | 20 ++ R/examples/predict_examples.R | 58 +++++ R/examples/residuals_examples.R | 17 ++ R/examples/summary_examples.R | 20 ++ R/examples/vcov_examples.R | 23 ++ R/fisher.R | 90 +++++++ R/fitted.lmvar.R | 61 +++++ R/gaussian_var.R | 8 + R/lmvar.R | 255 +++++++++++++++++++ R/logLik.lmvar.R | 21 ++ R/make_matrix_full_rank.R | 15 ++ R/matrix_column_names.R | 23 ++ R/nobs.lmvar.R | 18 ++ R/predict.lmvar.R | 279 ++++++++++++++++++++ R/print.summary_lmvar.R | 51 ++++ R/residuals.lmvar.R | 36 +++ R/summary.lmvar.R | 114 +++++++++ R/vcov.lmvar.R | 82 ++++++ README.md | 72 ++++++ build/vignette.rds | Bin 0 -> 252 bytes inst/doc/Intro.R | 45 ++++ inst/doc/Intro.Rmd | 176 +++++++++++++ inst/doc/Intro.html | 261 +++++++++++++++++++ inst/doc/Math.ltx | 328 ++++++++++++++++++++++++ inst/doc/Math.pdf | Bin 0 -> 165927 bytes man/AIC.lmvar.Rd | 31 +++ man/alias.lmvar.Rd | 66 +++++ man/beta_sigma_names.Rd | 48 ++++ man/coef.lmvar.Rd | 62 +++++ man/df.residual.lmvar.Rd | 53 ++++ man/dfree.Rd | 63 +++++ man/fisher.Rd | 76 ++++++ man/fitted.lmvar.Rd | 118 +++++++++ man/lmvar.Rd | 110 ++++++++ man/logLik.lmvar.Rd | 45 ++++ man/nobs.lmvar.Rd | 41 +++ man/predict.lmvar.Rd | 152 +++++++++++ man/print.summary_lmvar.Rd | 19 ++ man/residuals.lmvar.Rd | 52 ++++ man/summary.lmvar.Rd | 90 +++++++ man/vcov.lmvar.Rd | 47 ++++ tests/create_test_data.R | 55 ++++ tests/testthat.R | 6 + tests/testthat/test_extractors.R | 26 ++ tests/testthat/test_lmvar.R | 74 ++++++ tests/testthat/test_predict.R | 336 +++++++++++++++++++++++++ vignettes/Intro.Rmd | 176 +++++++++++++ vignettes/Math.ltx | 328 ++++++++++++++++++++++++ 67 files changed, 4751 insertions(+) create mode 100644 DESCRIPTION create mode 100644 MD5 create mode 100644 NAMESPACE create mode 100644 R/AIC.lmvar.R create mode 100644 R/alias.lmvar.R create mode 100644 R/beta_sigma_names.R create mode 100644 R/coef.lmvar.R create mode 100644 R/df.residual.lmvar.R create mode 100644 R/dfree.R create mode 100644 R/examples/AIC_examples.R create mode 100644 R/examples/alias_examples.R create mode 100644 R/examples/beta_sigma_names_examples.R create mode 100644 R/examples/coef_examples.R create mode 100644 R/examples/df.residual_examples.R create mode 100644 R/examples/dfree_examples.R create mode 100644 R/examples/fisher_examples.R create mode 100644 R/examples/fitted_examples.R create mode 100644 R/examples/lmvar_examples.R create mode 100644 R/examples/logLik_examples.R create mode 100644 R/examples/nobs_examples.R create mode 100644 R/examples/predict_examples.R create mode 100644 R/examples/residuals_examples.R create mode 100644 R/examples/summary_examples.R create mode 100644 R/examples/vcov_examples.R create mode 100644 R/fisher.R create mode 100644 R/fitted.lmvar.R create mode 100644 R/gaussian_var.R create mode 100644 R/lmvar.R create mode 100644 R/logLik.lmvar.R create mode 100644 R/make_matrix_full_rank.R create mode 100644 R/matrix_column_names.R create mode 100644 R/nobs.lmvar.R create mode 100644 R/predict.lmvar.R create mode 100644 R/print.summary_lmvar.R create mode 100644 R/residuals.lmvar.R create mode 100644 R/summary.lmvar.R create mode 100644 R/vcov.lmvar.R create mode 100644 README.md create mode 100644 build/vignette.rds create mode 100644 inst/doc/Intro.R create mode 100644 inst/doc/Intro.Rmd create mode 100644 inst/doc/Intro.html create mode 100644 inst/doc/Math.ltx create mode 100644 inst/doc/Math.pdf create mode 100644 man/AIC.lmvar.Rd create mode 100644 man/alias.lmvar.Rd create mode 100644 man/beta_sigma_names.Rd create mode 100644 man/coef.lmvar.Rd create mode 100644 man/df.residual.lmvar.Rd create mode 100644 man/dfree.Rd create mode 100644 man/fisher.Rd create mode 100644 man/fitted.lmvar.Rd create mode 100644 man/lmvar.Rd create mode 100644 man/logLik.lmvar.Rd create mode 100644 man/nobs.lmvar.Rd create mode 100644 man/predict.lmvar.Rd create mode 100644 man/print.summary_lmvar.Rd create mode 100644 man/residuals.lmvar.Rd create mode 100644 man/summary.lmvar.Rd create mode 100644 man/vcov.lmvar.Rd create mode 100644 tests/create_test_data.R create mode 100644 tests/testthat.R create mode 100644 tests/testthat/test_extractors.R create mode 100644 tests/testthat/test_lmvar.R create mode 100644 tests/testthat/test_predict.R create mode 100644 vignettes/Intro.Rmd create mode 100644 vignettes/Math.ltx diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..4a9b3c2 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,18 @@ +Package: lmvar +Type: Package +Title: Linear Regression with Non-Constant Variances +Version: 1.0.0 +Author: Posthuma Partners +Maintainer: Marco Nijmeijer +Description: Runs a linear regression in which both the expected value and the variance can vary per observation. The expected values mu follows the standard linear model mu = X_mu * beta_mu. The standard deviation sigma follows the model log(sigma) = X_sigma * beta_sigma. The package comes with two vignettes: 'Intro' gives an introduction, 'Math' gives mathematical details. +License: GPL-3 +LazyData: TRUE +Imports: Matrix (>= 1.2-4), matrixcalc (>= 1.0-3), nleqslv (>= 3.0.3), + stats (>= 3.2.5) +RoxygenNote: 6.0.1 +Suggests: testthat, knitr, rmarkdown, R.rsp +VignetteBuilder: knitr, R.rsp +NeedsCompilation: no +Packaged: 2017-02-16 16:39:12 UTC; Marc +Repository: CRAN +Date/Publication: 2017-02-17 14:38:14 diff --git a/MD5 b/MD5 new file mode 100644 index 0000000..ff08231 --- /dev/null +++ b/MD5 @@ -0,0 +1,66 @@ +0da3dd6021303151430b92d13b01bc04 *DESCRIPTION +41b7f05cd32d8769ef2208ad6368d7e9 *NAMESPACE +799ae591e93eb076cea0d9f8150235dd *R/AIC.lmvar.R +b0137d370c4c1a01bc5ceb87d8cc6285 *R/alias.lmvar.R +c5a11e9f3431dd97d7e32a2df0f1fbd5 *R/beta_sigma_names.R +08618c12995a54734f49b0735c535257 *R/coef.lmvar.R +010573949388442cd98049ecc6b0e7b2 *R/df.residual.lmvar.R +a9d9d476093ad924986c191b5241769b *R/dfree.R +39b90ad72cc9880282de9bf614d68133 *R/examples/AIC_examples.R +bd9d7d3681defffd188f22a59df22c77 *R/examples/alias_examples.R +13fa82f04c348bab1ab18187053eea3b *R/examples/beta_sigma_names_examples.R +c5ae01de2d2f10f7b4bfa919e3f388a6 *R/examples/coef_examples.R +ee365be6d30d6714e4a6454e6a0bfef7 *R/examples/df.residual_examples.R +9d526fd9bc9b4c72c55cc5cd2614b4fa *R/examples/dfree_examples.R +dd73ddf4aff15db9a6a6407af1a59577 *R/examples/fisher_examples.R +698ac483d76f91ef2a49fc965577ee33 *R/examples/fitted_examples.R +8cb1e5039896f1872911159fc875f758 *R/examples/lmvar_examples.R +e93509e8f18367eae4c7a21672482354 *R/examples/logLik_examples.R +02000462392443088a7b9628b773cd8a *R/examples/nobs_examples.R +f28168301e48d6a216067c9e6f46320a *R/examples/predict_examples.R +014ab1c3a4fb3f2511a5df2dbe775723 *R/examples/residuals_examples.R +3b54dd7601fce2246ecfe4fbebaf345f *R/examples/summary_examples.R +2139927b488f26929811b608c885885f *R/examples/vcov_examples.R +65c5d7d3efb959034969ce25081d0525 *R/fisher.R +bb4e182ff8110e449ab82117c67b5f6f *R/fitted.lmvar.R +d97d4f2dd4613ba9af5c79e8c683d4b7 *R/gaussian_var.R +ae576df528a3f5b30cac7df2df9dce68 *R/lmvar.R +8a5f8803d15359cd28f236e6a59d3d1d *R/logLik.lmvar.R +11a615ab05ce7c6a45d5905a064587b6 *R/make_matrix_full_rank.R +c6eb72596cb95e6d1f12968a110a1fcb *R/matrix_column_names.R +4f63ac17353588bd3d9497d181ace9cb *R/nobs.lmvar.R +f37f6f29c93effe8ebfdc3998dc28a20 *R/predict.lmvar.R +af17a34e533280763874b7faa31208a1 *R/print.summary_lmvar.R +68ba53a968caa6fc52a96117a4b2a537 *R/residuals.lmvar.R +6f3aa4fe0edbf10588592d9bef786368 *R/summary.lmvar.R +b07e75a5335b4375cedc45d4e876594f *R/vcov.lmvar.R +058e5cb3b2ffde63a0e073c229b7ca24 *README.md +9a51ea3e128c9edff4d3fe1f448b53a5 *build/vignette.rds +828d6a905ed48145c432c23f00ef645c *inst/doc/Intro.R +475cfafe2a4d03be48ab649bab4d5f81 *inst/doc/Intro.Rmd +7fff116f96908a44f030b786be788671 *inst/doc/Intro.html +0d2d2347fc49b246c9f6607324c60005 *inst/doc/Math.ltx +604b46aa4979321bd4c90566bfa4cc44 *inst/doc/Math.pdf +cdc8775371ef46701cbbfdd098441d22 *man/AIC.lmvar.Rd +40be9e23383ce6cfb87f6158572eab2e *man/alias.lmvar.Rd +96870ffeb6e33b5476b9014730e99d0f *man/beta_sigma_names.Rd +dc231983bd8fc1c8234230199df56ebc *man/coef.lmvar.Rd +ae69a6216348af4e1787e9550574a03e *man/df.residual.lmvar.Rd +8a46914afe8717717af7868eb56fe898 *man/dfree.Rd +a5e5ccd1c0fafcdaee3bbeb7cab47cd5 *man/fisher.Rd +f84bf4c6fc34202b0f52fc560ac08b84 *man/fitted.lmvar.Rd +9105d49018403123fc7fe8430ec2299a *man/lmvar.Rd +d3041936af6e96cdc0ae4464e0f52796 *man/logLik.lmvar.Rd +c33fe1105392aeab24e540c8f09459a4 *man/nobs.lmvar.Rd +85f6305560b23fac8565e52f25fc606a *man/predict.lmvar.Rd +080d695ec1395b492167dbf7e898c71a *man/print.summary_lmvar.Rd +9b35a0b154bc37c64d22c063fe84850e *man/residuals.lmvar.Rd +3001d4fdbb5a458419ddcac4c7e161f7 *man/summary.lmvar.Rd +103ad2096a2c2810478be7d856ea2b32 *man/vcov.lmvar.Rd +bde5eb3a375b2d0298b8c17d84eda405 *tests/create_test_data.R +b5e9bbfbc1b319bc3baec90d163e1426 *tests/testthat.R +9181c1bb3ff9b24d1d5da2dcf1a0ce1e *tests/testthat/test_extractors.R +3dc4e0f80fc5c12cef9aadd1a98116f7 *tests/testthat/test_lmvar.R +18b7f56763d877e27e3f5083153c384f *tests/testthat/test_predict.R +475cfafe2a4d03be48ab649bab4d5f81 *vignettes/Intro.Rmd +0d2d2347fc49b246c9f6607324c60005 *vignettes/Math.ltx diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..91e4337 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,20 @@ +# Generated by roxygen2: do not edit by hand + +S3method(AIC,lmvar) +S3method(alias,lmvar) +S3method(coef,lmvar) +S3method(df.residual,lmvar) +S3method(fitted,lmvar) +S3method(logLik,lmvar) +S3method(nobs,lmvar) +S3method(predict,lmvar) +S3method(print,summary_lmvar) +S3method(residuals,lmvar) +S3method(summary,lmvar) +S3method(vcov,lmvar) +export(beta_sigma_names) +export(dfree) +export(fisher) +export(lmvar) +importFrom(stats,alias) +importFrom(stats,nobs) diff --git a/R/AIC.lmvar.R b/R/AIC.lmvar.R new file mode 100644 index 0000000..f45adec --- /dev/null +++ b/R/AIC.lmvar.R @@ -0,0 +1,18 @@ +#' @title AIC for an object of class 'lmvar' +#' +#' @description AIC (Aikaike's 'An Information Criterion') for an object of class 'lmvar' +#' +#' @param object Object of class 'lmvar' +#' @param ... For compatibility with \code{\link[stats]{AIC}} generic +#' @param k Numeric, the penalty per parameter to be used. The default k = 2 is the classical AIC. +#' +#' @return the AIC of the object +#' +#' @export +#' +#' @example R/examples/AIC_examples.R +#' +AIC.lmvar <- function(object, ..., k = 2){ + df = dfree(object) + return(k*df - 2 * logLik.lmvar(object)[1]) +} diff --git a/R/alias.lmvar.R b/R/alias.lmvar.R new file mode 100644 index 0000000..3f135cf --- /dev/null +++ b/R/alias.lmvar.R @@ -0,0 +1,53 @@ +#' +#' @title Aliased coefficients in an 'lmvar' object +#' +#' @description Returns the columns present in the user-specified model-matrices \eqn{X_\mu} and \eqn{X_\sigma} that were removed by +#' \code{lmvar} to make the matrices full-rank. +#' +#' @param object Object of class 'lmvar' +#' @param mu Boolean, specifies whether the aliased columns from the model matrix \eqn{X_\mu} must be returned +#' @param sigma Boolean, specifies whether the aliased columns from the model matrix \eqn{X_\sigma} must be returned +#' @param ... Additional arguments, not used in the current implementation +#' +#' @return A character vector containing the names of the aliased columns +#' +#' @details If \code{mu = TRUE} and \code{sigma = TRUE}, the function returns the aliased columns of both \eqn{X_\mu} +#' and \eqn{X_\sigma}. The string "_s" is appended to the aliased column names from \eqn{X_\sigma} if at least one of those +#' names also appears in \eqn{X_\mu} +#' +#'If \code{mu = TRUE} and \code{sigma = FALSE}, the function returns the aliased columns of \eqn{X_\mu}. +#' +#'If \code{mu = FALSE} and \code{sigma = TRUE}, the function returns the aliased columns of \eqn{X_\sigma}. +#' +#' @export +#' +#' @importFrom stats alias +#' +#' @example R/examples/alias_examples.R +#' +alias.lmvar <- function( object, mu = TRUE, sigma = TRUE, ...){ + + aliased_mu = character() + if (mu){ + aliased_mu = names(object$aliased_mu)[object$aliased_mu] + } + + aliased_sigma = character() + if (sigma){ + aliased_sigma = names(object$aliased_sigma)[object$aliased_sigma] + } + + if (mu & !sigma){ + return(aliased_mu) + } + else if (!mu & sigma){ + return(aliased_sigma) + } + else if (mu & sigma){ + a_names = c( aliased_mu, beta_sigma_names( names(object$aliased_mu), aliased_sigma)) + return(as.character(a_names)) + } + else { + return(character()) + } +} diff --git a/R/beta_sigma_names.R b/R/beta_sigma_names.R new file mode 100644 index 0000000..fa812e7 --- /dev/null +++ b/R/beta_sigma_names.R @@ -0,0 +1,57 @@ +#' +#' @title Unique names for beta_sigma +#' +#' @description Returns adapted names for the coefficients \eqn{\beta_\sigma} to distinguish them from the names +#' of the coefficients +#' \eqn{\beta_\mu}. This is a helper function which is used in situations where it is necessary or convenient +#' for the coefficient names of \eqn{\beta_\sigma} +#' to be different from \eqn{\beta_\mu}. +#' +#' @param beta_mu_names Character vector with the names of the coefficients \eqn{\beta_\mu} +#' @param beta_sigma_names Character vector with the names of the coefficients \eqn{\beta_\sigma} +#' @param ... Additional arguments, not used in the current implementation +#' +#' @return Named character vector with the names of the coefficients \eqn{\beta_\sigma}. The name of a vector element +#' is the original +#' name of the coefficient. The value is the adapted name. The name and the value are equal if no adaptation was needed. +#' +#' @details When the name of at least one coefficient in \eqn{\beta_\sigma} is equal to one of the names of the +#' coefficients in \eqn{\beta_\mu}, the string '_s' is +#' appended to the names of all coefficients in \eqn{\beta_\sigma}. +#' Otherwise, the names of the coefficients in \eqn{\beta_\sigma} are left unchanged. +#' +#' @export +#' +#' @example R/examples/beta_sigma_names_examples.R +#' + +beta_sigma_names <- function( beta_mu_names, beta_sigma_names, ...){ + + if (is.null(beta_sigma_names)){ + return(character()) + } + else + { + # Check if at least one name of beta_sigma is identical to beta_mu + bool = any(is.element( beta_sigma_names, beta_mu_names)) + + # Adapt the names of beta_sigma if at least one is identical to beta_mu + if (bool){ + beta_sigma_names_new = sapply( beta_sigma_names, function(x){ + if (x != "(Intercept_s)"){ + return(paste( x, "_s", sep="")) + } + else { + return(x) + } + }) + } + else { + beta_sigma_names_new = beta_sigma_names + } + + names(beta_sigma_names_new) = beta_sigma_names + + return(beta_sigma_names_new) + } +} diff --git a/R/coef.lmvar.R b/R/coef.lmvar.R new file mode 100644 index 0000000..6bbc3d2 --- /dev/null +++ b/R/coef.lmvar.R @@ -0,0 +1,54 @@ +#' +#' @title Extracts coefficients from an 'lmvar' object. +#' +#' @description Extracts maximum-likelihood estimators for \eqn{\beta_\mu} and \eqn{\beta_\sigma} from an 'lmvar' object. +#' +#' @param object Object of class 'lmvar' +#' @param mu Boolean, specifies whether or not to return the maximum-likelihood estimator for \eqn{\beta_\mu} +#' @param sigma Boolean, specifies whether or not to return the maximum-likelihood estimator for \eqn{\beta_\sigma} +#' @param ... For compatibility with \code{\link[stats]{coef}} generic +#' +#' @return When \code{mu = TRUE} and \code{sigma = TRUE}, a named numeric vector with the elements of \eqn{\beta_\mu}, +#' followed by the elements of \eqn{\beta_\sigma}. +#' +#' When \code{mu = TRUE} and \code{sigma = FALSE}, a named numeric vector with the elements of \eqn{\beta_\mu}. +#' +#' When \code{mu = FALSE} and \code{sigma = TRUE}, a named numeric vector with the elements of \eqn{\beta_\sigma}. +#' +#' @details When both \code{mu = TRUE} and \code{sigma = TRUE}, the names of the +#' coefficients in \eqn{\beta_\sigma} are adapted to distinguish them from the names in \eqn{\beta_\mu}, if needed. +#' +#' @seealso \code{\link{beta_sigma_names}} for the adaptation of the names of the coefficients in \eqn{\beta_\sigma}. +#' +#' @export +#' +#' @example R/examples/coef_examples.R +#' + +coef.lmvar <- function( object, mu = TRUE, sigma = TRUE, ...){ + + beta_mu = numeric() + beta_sigma = numeric() + beta_mu_names = character() + beta_sigma_names = character() + + if (mu){ + beta_mu = object$coefficients_mu + beta_mu_names = names(object$coefficients_mu) + } + + if (sigma){ + beta_sigma = object$coefficients_sigma + if (mu){ + beta_sigma_names = lmvar::beta_sigma_names( names(object$coefficients_mu), names(object$coefficients_sigma)) + } + else { + beta_sigma_names = names(object$coefficients_sigma) + } + } + + betas = c( beta_mu, beta_sigma) + names(betas) = c( beta_mu_names, beta_sigma_names) + + return(betas) +} diff --git a/R/df.residual.lmvar.R b/R/df.residual.lmvar.R new file mode 100644 index 0000000..73d51ab --- /dev/null +++ b/R/df.residual.lmvar.R @@ -0,0 +1,23 @@ +#' @title Residual degrees of freedom for an object of class 'lmvar' +#' +#' @description Residual degrees of freedom for an object of class 'lmvar'. The residual degrees of freedom are defined +#' as the number of observations minus the degrees of freedom of the model. +#' +#' @param object Object of class 'lmvar' +#' @param ... For compatibility with \code{\link[stats]{df.residual}} generic +#' +#' @return Residual degees of freedom for \code{object}. +#' +#' @export +#' +#' @seealso \code{\link{dfree}} for the degrees of freedom of an object of class 'lmvar' +#' +#' \code{\link{nobs.lmvar}} for the number of observations in an object of class 'lmvar' +#' +#' @example R/examples/df.residual_examples.R +#' + +df.residual.lmvar <- function(object, ...){ + df = nobs(object) - dfree(object) + return(df) +} diff --git a/R/dfree.R b/R/dfree.R new file mode 100644 index 0000000..f1b226e --- /dev/null +++ b/R/dfree.R @@ -0,0 +1,46 @@ +#' @title Degrees of freedom for an object of class 'lmvar' +#' +#' @description Degrees of freedom for the model in an object of class 'lmvar'. The degrees of freedom are defined as the rank of the +#' model matrix \eqn{X_\mu} for the expectation values, plus the rank of the model matrix \eqn{X_\sigma} for the standard deviations. +#' +#' @param object Object of class 'lmvar' +#' @param mu Boolean, specifies whether the degrees of freedom for the model for the expectation values must be included. +#' @param sigma Boolean, specifies whether the degrees of freedom for the model for the standard deviations must be included. +#' @param ... Additional arguments, not used in the current implementation +#' +#' @return An integer containing the degrees of freedom for the model in \code{object}. +#' +#' @details If \code{mu = TRUE} and \code{sigma = TRUE}, the function returns the rank of the model-matrix \eqn{X_\mu} plus the +#' rank of the model matrix \eqn{X_\sigma}. +#' +#' If \code{mu = TRUE} and \code{sigma = FALSE}, the function returns the rank of the model-matrix \eqn{X_\mu}. +#' +#' If \code{mu = FALSE} and \code{sigma = TRUE}, the function returns the rank of the model-matrix \eqn{X_\sigma}. +#' +#' Both model matrices contain a column corresponding to an intercept term. This column is added by \code{\link{lmvar}}. +#' See also the vignette 'Intro'. +#' +#' @export +#' +#' @seealso \code{\link{df.residual.lmvar}} for the residual degrees of freedom for an object of class 'lmvar' +#' +#' @example R/examples/dfree_examples.R +#' + +dfree <- function( object, mu = TRUE, sigma = TRUE, ...){ + + if (class(object) != 'lmvar'){ + stop("Object must be an 'lmvar' object") + } + + if (mu & sigma){ + return( ncol(object$X_mu) + ncol(object$X_sigma)) + } + else if (mu){ + return( ncol(object$X_mu)) + } + else { + return( ncol(object$X_sigma)) + } + +} diff --git a/R/examples/AIC_examples.R b/R/examples/AIC_examples.R new file mode 100644 index 0000000..063dd94 --- /dev/null +++ b/R/examples/AIC_examples.R @@ -0,0 +1,8 @@ +\dontrun{ + +# Let 'fit' be an object of class 'lmvar'. The classical AIC is +AIC(fit) + +# To calculate the AIC with penalty-parameter k = 3 run +AIC(fit, k = 3) +} diff --git a/R/examples/alias_examples.R b/R/examples/alias_examples.R new file mode 100644 index 0000000..f5da716 --- /dev/null +++ b/R/examples/alias_examples.R @@ -0,0 +1,31 @@ +# Create matrix columns +my_intercept = rep(1, 20) +v1 = c(rep(1, 10), rep(0, 10)) +v2 = c(rep(0, 10), rep(1, 10)) + +# Create model matrices +X = cbind(my_intercept, v1, v2) +X_s = X + +# Rename the last column of the model matrix 'X_s' to make this example more clear. +colnames(X_s)[3] = "v3" + +# Create response vector +y = rnorm(20) + +# Perform fit +fit = lmvar(y, X, X_s) + +# The column 'my_intercept' is identical to '(Intercept)' added by 'lmvar' +# to the model matrix 'X'. Column 'v2' is equal to '(Intercept)' minus 'v1'. +# The same holds for the model matrix 'X_s'. +alias(fit) + +# The aliased columns are left out if you extract the coefficients from a summary +coef(summary(fit)) + +# Only return the aliased colums in the model matrix for the expectation values +alias(fit, sigma = FALSE) + +# Only return the aliased colums in the model matrix for the standard deviations +alias(fit, mu = FALSE) diff --git a/R/examples/beta_sigma_names_examples.R b/R/examples/beta_sigma_names_examples.R new file mode 100644 index 0000000..b325961 --- /dev/null +++ b/R/examples/beta_sigma_names_examples.R @@ -0,0 +1,13 @@ +# If the names in beta_sigma are all different from all of the names in +# beta_mu, the function returns the names of beta_sigma +mu_names = c("(Intercept)", "age", "gender") +sigma_names = c("(Intercept_s)", "smoker", "job_code") + +beta_sigma_names(mu_names, sigma_names) + +# If at least one of the names in beta_sigma is equal to a name in +# beta_mu, all the names in beta_sigma get the string '_s' appended, +# except for '(intercept_s)' +sigma_names = c("(Intercept_s)", "age", "job_code") + +beta_sigma_names(mu_names, sigma_names) diff --git a/R/examples/coef_examples.R b/R/examples/coef_examples.R new file mode 100644 index 0000000..91b0893 --- /dev/null +++ b/R/examples/coef_examples.R @@ -0,0 +1,25 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist, attenu$mag + attenu$dist) +colnames(X) = c("mag", "dist", "mag+dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# Extract all coefficients +coef(fit) + +# Extract only the coefficients corresponding to the (non-aliased) +# columns in the model matrix for the expected values +coef(fit, sigma = FALSE) + +# Extract only the coefficients corresponding to the (non-aliased) +# columns in the model matrix for standard deviations +coef(fit, mu = FALSE) diff --git a/R/examples/df.residual_examples.R b/R/examples/df.residual_examples.R new file mode 100644 index 0000000..b2d1fb3 --- /dev/null +++ b/R/examples/df.residual_examples.R @@ -0,0 +1,26 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# To see how many observations the dataset contains, run +help("attenu") + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# The number of observations in the fit is +nobs(fit) + +# The degrees of freedom are +dfree(fit) + +# The residual degrees of freedom are +df.residual(fit) diff --git a/R/examples/dfree_examples.R b/R/examples/dfree_examples.R new file mode 100644 index 0000000..8d9f86a --- /dev/null +++ b/R/examples/dfree_examples.R @@ -0,0 +1,23 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# The degrees of freedom are +dfree(fit) + +# The degrees of freedom of the expected values are +dfree(fit, sigma = FALSE) + +# The degrees of freedom of the standard deviations are +dfree(fit, mu = FALSE) diff --git a/R/examples/fisher_examples.R b/R/examples/fisher_examples.R new file mode 100644 index 0000000..6cf325f --- /dev/null +++ b/R/examples/fisher_examples.R @@ -0,0 +1,23 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# The complete Fisher information matrix is +fisher(fit) + +# The left-upper block matrix relating to the expected values is +fisher(fit, sigma = FALSE) + +# The right-lower block matrix relating to the variances is +fisher(fit, mu = FALSE) diff --git a/R/examples/fitted_examples.R b/R/examples/fitted_examples.R new file mode 100644 index 0000000..384e653 --- /dev/null +++ b/R/examples/fitted_examples.R @@ -0,0 +1,47 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +y = attenu$accel +fit = lmvar(y, X, X_s) + +# Calculate the expected value of each observation +fitted(fit, sigma = FALSE) + +# Calculate the standard deviation of each observation +fitted(fit, mu = FALSE) + +# Calculate the expected values and their 95% confidence intervals +fitted(fit, sigma = FALSE, interval = "confidence") + +# Calculate the standard deviations and their 80% confidence intervals +fitted(fit, mu = FALSE, interval = "confidence", level = 0.8) + +# Calculate both the expected values and the standard deviations +fitted(fit) + +# Calculate the expected values, the standard deviations and their 95% confidence intervals +fitted(fit, interval = "confidence") + +# Fit the log of 'accel' +y = log(attenu$accel) +fit_log = lmvar(y, X, X_s) + +# Calculate both the expected values and the standard deviations of the log of 'accel' +fitted(fit_log) + +# Calculate the expected values and the standard deviations of 'accel' +fitted(fit_log, log = TRUE) + +# Calculate the expected values and the standard deviations of 'accel', +# as well as their 90% confidence intervals +fitted(fit_log, log = TRUE, interval = "confidence", level = 0.9) diff --git a/R/examples/lmvar_examples.R b/R/examples/lmvar_examples.R new file mode 100644 index 0000000..7e1bf2a --- /dev/null +++ b/R/examples/lmvar_examples.R @@ -0,0 +1,32 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# For more info on the data, study the dataset +help("attenu") + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. The standard deviation +# is large for small distances and small for large distances. The use of 'dist' +# as explanatory variable makes the beta for the intercept term blow up. +# Therefore we use '1 / dist' as explanatory variable +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit_lmvar = lmvar(attenu$accel, X, X_s) + +# Inspect the results. Note from the p-value for the difference in +# deviance that this fit appears to be significantly better than +# a classical linear fit +summary(fit_lmvar) + +# Carry out a classical linear fit for comparison +fit_lm = lm(attenu$accel ~ mag + dist, attenu) + +# A comparison of the AIC values also favours the fit with 'lmvar' +AIC(fit_lm) +AIC(fit_lmvar) diff --git a/R/examples/logLik_examples.R b/R/examples/logLik_examples.R new file mode 100644 index 0000000..1405174 --- /dev/null +++ b/R/examples/logLik_examples.R @@ -0,0 +1,21 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# Show the log-likelihood and the degrees of freedom of the fit +# using the 'print' method for an object of class 'logLik' +logLik(fit) + +# Obtain the log-likelihood itself +logLik(fit)[1] diff --git a/R/examples/nobs_examples.R b/R/examples/nobs_examples.R new file mode 100644 index 0000000..8e75863 --- /dev/null +++ b/R/examples/nobs_examples.R @@ -0,0 +1,20 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# Return the number of observations in the fit +nobs(fit) + +# Check that this is equal to the number of observations in the dataset +nobs(fit) == nrow(attenu) diff --git a/R/examples/predict_examples.R b/R/examples/predict_examples.R new file mode 100644 index 0000000..dfcd953 --- /dev/null +++ b/R/examples/predict_examples.R @@ -0,0 +1,58 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Create the response vector +y = attenu$accel + +# Carry out the fit +fit = lmvar(y, X, X_s) + +# Calculate the expected values and standard deviations of 'accel' +# for the current magnitudes and distances +predict(fit) + +# Calculate the expected values and standard deviations of 'accel' for earthquakes +# with a 10% larger magnitude, at the current distances +XP = cbind(1.1 * attenu$mag, attenu$dist) +colnames(XP) = c("mag", "dist") + +XP_s = cbind(1.1 * attenu$mag, 1 / attenu$dist) +colnames(XP_s) = c("mag", "dist_inv") + +predict(fit, XP, XP_s) + +# Calculate only the expected values +predict(fit, XP, XP_s, sigma = FALSE) + +# Calculate only the standard deviations +predict(fit, XP, XP_s, mu = FALSE) + +# Calculate the expected values and their 95% confidence intervals +predict(fit, XP, XP_s, sigma = FALSE, interval = "confidence") + +# Calculate the standard deviations and their 90% confidence intervals +predict(fit, XP, XP_s, sigma = FALSE, interval = "confidence", level = 0.9) + +# Change the model and fit the log of 'accel' +y = log(attenu$accel) +fit_log = lmvar(y, X, X_s) + +# Calculate the expected values and standard deviations of the log of 'accel' +predict(fit_log, XP, XP_s) + +# Calculate the expected values and standard deviations of 'accel' +predict(fit_log, XP, XP_s, log = TRUE) + +# Calculate the expected values and standard deviations of 'accel', +# as well as their 99% confidence intervals +predict(fit_log, XP, XP_s, log = TRUE, interval = "confidence", level = 0.99) + diff --git a/R/examples/residuals_examples.R b/R/examples/residuals_examples.R new file mode 100644 index 0000000..e941637 --- /dev/null +++ b/R/examples/residuals_examples.R @@ -0,0 +1,17 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# Calculate the residuals +residuals(fit) diff --git a/R/examples/summary_examples.R b/R/examples/summary_examples.R new file mode 100644 index 0000000..d9f31f3 --- /dev/null +++ b/R/examples/summary_examples.R @@ -0,0 +1,20 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# Print a summary of the fit +summary(fit) + +# Extract the matrix of coefficients from the summary +coef(summary(fit)) diff --git a/R/examples/vcov_examples.R b/R/examples/vcov_examples.R new file mode 100644 index 0000000..6ee2d9a --- /dev/null +++ b/R/examples/vcov_examples.R @@ -0,0 +1,23 @@ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# The complete covariance matrix is +vcov(fit) + +# The covariance matrix for the coefficients for the expected values is +vcov(fit, sigma = FALSE) + +# The covariance matrix for the coefficients for the standard deviations is +vcov(fit, mu = FALSE) diff --git a/R/fisher.R b/R/fisher.R new file mode 100644 index 0000000..2d4b6ac --- /dev/null +++ b/R/fisher.R @@ -0,0 +1,90 @@ +#' @title Fisher information matrix for an object of class 'lmvar' +#' +#' @description Fisher information matrix for +#' an object of class 'lmvar'. +#' +#' @param object Object of class 'lmvar' +#' @param mu Specifies whether or not the block-matrix for \eqn{\beta_\mu} is included in the returned matrix +#' @param sigma Specifies whether or not the block-matrix for \eqn{\beta_\sigma} is included in the returned matrix +#' @param ... Additional arguments, not used in the current implementation +#' +#' @return An object of class 'matrix' containing the Fisher information matrix of \code{object}. +#' +#' @details The Fisher information matrix is calculated as minus \eqn{-E[H]/n} with \eqn{E[H]} the expected value of +#' the Hessian matrix \eqn{H} of the +#' log-likelihood and \eqn{n} the number of observations. +#' +#' The matrix is calculated using the maximum-likelihood estimators of \eqn{\mu} and \eqn{\sigma}. +#' +#' If \code{mu = TRUE} and \code{sigma = TRUE}, the full Fisher information matrix is returned. +#' +#' If \code{mu = TRUE} and \code{sigma = FALSE}, only the left-upper block-matrix is returned, corresponding to the part of +#' the Fisher information matrix pertaining to \eqn{\beta_\mu}. +#' +#' If \code{mu = FALSE} and \code{sigma = TRUE}, only the right-lower block-matrix is returned, corresponding to the part of +#' the Fisher information matrix pertaining to \eqn{\beta_\sigma}. +#' +#' @export +#' +#' @seealso \code{\link{vcov.lmvar}} calculates the covariance matrix for the maximum-likelihood estimators of +#' \eqn{\beta_\mu} and \eqn{\beta_\mu} +#' +#' \code{\link{nobs.lmvar}} for the number of observations in an object of class 'lmvar' +#' +#' \code{\link{coef.lmvar}} for the coefficients \eqn{\beta_\mu} and \eqn{\beta_\sigma} +#' +#' \code{\link{fitted.lmvar}} for the expectation values \eqn{\mu} and standard deviations \eqn{\sigma}. +#' +#' See the vignette "Math" (to be viewed with \code{vignette("Math", "lmvar")}) for details. +#' +#' @example R/examples/fisher_examples.R +#' +fisher <- function(object, mu = TRUE, sigma = TRUE, ...){ + + X_sigma = object$X_sigma + + # Calculate block-matrix for mu + if (mu){ + X = object$X_mu + sigma_object = as.numeric(exp(X_sigma %*% stats::coef(object, mu=FALSE))) + I_mu = X * (1/sigma_object) + I_mu = (Matrix::t(I_mu) %*% I_mu) / nobs(object) + } + + # Calculate block-matrix for sigma + if (sigma){ + I_sigma = 2 * (Matrix::t(X_sigma) %*% X_sigma) / nobs(object) + } + + # Create block-matrix of zeros + if (mu & sigma){ + H_0 = matrix( 0, nrow = nrow(I_mu), ncol = ncol(I_sigma)) + } + + # Set row and column names + beta_mu_names = names( stats::coef(object, sigma = FALSE)) + beta_sigma_names = names( stats::coef(object, mu = FALSE)) + + # Compose matrix from block-matrices + if (mu & !sigma){ + rownames(I_mu) = beta_mu_names + colnames(I_mu) = beta_mu_names + return(I_mu) + } + else if (!mu & sigma){ + rownames(I_sigma) = beta_sigma_names + colnames(I_sigma) = beta_sigma_names + return(I_sigma) + } + else if (mu & sigma){ + I = rbind( cbind( I_mu, H_0), cbind( Matrix::t(H_0), I_sigma)) + beta_sigma_names = beta_sigma_names( beta_mu_names, beta_sigma_names) + beta_names = c( beta_mu_names, beta_sigma_names) + rownames(I) = beta_names + colnames(I) = beta_names + return(I) + } + else{ + return(matrix( 0, nrow = 0, ncol = 0)) + } +} diff --git a/R/fitted.lmvar.R b/R/fitted.lmvar.R new file mode 100644 index 0000000..ccc34a0 --- /dev/null +++ b/R/fitted.lmvar.R @@ -0,0 +1,61 @@ +#' @title Fitted values for an 'lmvar' object +#' +#' @description Estimators and confidence intervals for the expected values and standard deviations of the response-vector \eqn{Y} of +#' an 'lmvar' model. The model can be a fit +#' to the response vector or to the logarithm of the response vector. +#' +#' @param object An 'lmvar' object +#' @param mu Boolean, specifies whether or not to return the expected values +#' @param sigma Boolean, specifies whether or not to return the standard deviations +#' @param log Boolean, specifies whether the observations \eqn{Y} have been fitted or the logarithm \eqn{\log Y}. In both cases, +#' \code{fitted.lmvar} returns expected values and standard deviations for \eqn{Y} itself. +#' @param interval Character string, specifying the type of interval. Possible values are +#' \itemize{ +#' \item "none" No interval +#' \item "confidence" Confidence intervals for the expected values (if \code{mu = TRUE}) and the standard deviation +#' (if \code{sigma = TRUE}) +#' } +#' @param level Numeric value between 0 and 1, specifying the confidence level +#' @param ... For compatibility with \code{\link[stats]{fitted}} generic. +#' +#' @return In the case \code{mu = FALSE} and \code{interval = "none"}: a numeric vector containing the estimators for +#' the standard deviation. +#' +#' In the case \code{sigma = FALSE} and \code{interval = "none"}: a numeric vector containing the estimators for +#' the expected values. +#' +#' In all other cases: a matrix with one column for each requested feature and one row for each observation. The column names are +#' \itemize{ +#' \item \code{mu} Estimators for the expected value \eqn{\mu} +#' \item \code{sigma} Estimators for the standard deviation \eqn{\sigma} +#' \item \code{mu_lwr} Lower bound of the interval for \eqn{\mu} +#' \item \code{mu_upr} Upper bound of the interval for \eqn{\mu} +#' \item \code{sigma_lwr} Lower bound of the interval for \eqn{\sigma} +#' \item \code{sigma_upr} Upper bound of the interval for \eqn{\sigma} +#' } +#' +#' @export +#' +#' @details If \code{log = FALSE} and \eqn{Y} the vector of observations stored in \code{object}, \code{fitted.lmvar} returns +#' expected values and standard deviations for the observations \eqn{Y}. +#' +#' If \code{log = TRUE} and \eqn{Y} the vector of observations stored in \code{object}, \code{fitted.lmvar} returns expected +#' values and standard deviations for \eqn{e^Y}. +#' +#' Confidence intervals are calculated with an approximation that is valid when the number of observations is large. +#' Intervals must be treated cautiously in case of a small number of observations. +#' +#' This function is identical to the function \code{\link{predict.lmvar}} in which the parameters \code{X_mu} and +#' \code{X_sigma} are left unspecified. +#' +#' @seealso \code{\link{predict.lmvar}} for expected values, standard deviations and intervals for model matrices different from +#' the ones present in \code{object}. +#' +#' @example R/examples/fitted_examples.R +#' + +fitted.lmvar <- function( object, mu = TRUE, sigma = TRUE, log = FALSE, interval = c("none", "confidence"), level = 0.95, ...){ + + return(predict.lmvar( object, mu = mu, sigma = sigma, log = log, interval = interval, level = level, ...)) + +} diff --git a/R/gaussian_var.R b/R/gaussian_var.R new file mode 100644 index 0000000..3184bc1 --- /dev/null +++ b/R/gaussian_var.R @@ -0,0 +1,8 @@ +gaussian_var <- function(){ + + # Function returns (part of) a family object for an 'lmvar' type of fit + + rlist = list( family = "gaussian with non-constant variances", + link = "identity") + return (structure( rlist, class = "family")) +} diff --git a/R/lmvar.R b/R/lmvar.R new file mode 100644 index 0000000..b8baffa --- /dev/null +++ b/R/lmvar.R @@ -0,0 +1,255 @@ +#' @title Linear regression with non-constant variances +#' +#' @description Performs a Gaussian regression with non-constant variances and outputs an 'lmvar' object. +#' +#' @param y Vector of observations +#' @param X_mu Model matrix for the expected values \eqn{\mu} +#' @param X_sigma Model matrix for the logarithms of the standard deviations \eqn{\sigma} +#' @param check_hessian Boolean, if TRUE it is checked whether the Hessian is negative-definite +#' @param ... Additional arguments, not used in the current implementation +#' +#' @return An object of class 'lmvar'. +#' +#' @details If the matrix \code{X_mu} is not specified, the model for the expected values \eqn{\mu} will consist of an intercept term only. +#' Likewise, the model for \eqn{\log \sigma} will consist of an intercept term only if \code{X_sigma} is not specified. +#' In the latter case, the model reduces to a standard linear model. +#' +#' The input matrices can be of class \code{\link{matrix}} or of class \link[Matrix:Matrix-class]{Matrix} +#' +#' When \code{check_hessian = TRUE}, it is checked whether the fitted log-likelihood is at a maximum. A warning will be issued if +#' that is not the case. +#' +#' The vector \code{y} must be a numeric vector. It can not contain special values like \code{NULL}, \code{NaN}, etc. +#' +#' Both model matrices must be numeric matrices. They can not contain special values like \code{NULL}, \code{NaN}, etc. +#' +#' All columns in the matrix \code{X_mu} must either have a name, or no column has a name at all. It is not allowed that some +#' colums have a +#' name while others don't. The same is true for \code{X_sigma}. +#' +#' If supplied, the column names +#' must be unique for \code{X_mu}. The same is true for \code{X_sigma}. A column name can be used in both \code{X_mu} and +#' \code{X_sigma} though. +#' +#' In case the matrix \code{X_mu} has no columns with a column name, \code{lmvar} gives the names \code{v1}, +#' \code{v2} etc. to the columns. Likewise, if the matrix \code{X_sigma} has no columns with a column name, \code{lmvar} +#' gives the names \code{v1_s}, \code{v2_s} etc. to the columns. +#' +#' Matrix \code{X_mu} can not have a column with the name '(Intercept)'. +#' Matrix \code{X_sigma} can not have a column with the name '(Intercept_s)'. Both names are reserved names. +#' +#' The function \code{nleqslv} from the \code{nleqslv} package, is used to solve the non-linear equations that comprise the fit. +#' \code{nleqslv} returns a +#' termination code which reports whether a solution was found, see \code{\link[nleqslv]{nleqslv}}. +#' A potential problem is reported by a termination code different from \code{1}. Termination codes different from \code{1} +#' as passed on by \code{lmvar}. Termination codes \code{2} and \code{3} are passed on as a warning. +#' Other termination codes are passed on as an error. +#' +#' An \code{lmvar} object is a list. Users are discouraged to access list-members directly. +#' Instead, list-members are to be accessed with the various accessor and utility functions in the package. +#' Exceptions are the following list members for which no accessor functions exist: +#' \itemize{ +#' \item \code{object$y} the vector of observations +#' \item \code{object$X_mu} the model matrix for \eqn{\mu}. In general, it differs from the user-supplied \code{X_mu} because +#' \code{lmvar} adds an intercept-column and makes the matrix full-rank. +#' \item \code{object$X_sigma} the model matrix for \eqn{\log \sigma}. In general, it differs from the user-supplied +#' \code{X_sigma} because +#' \code{lmvar} adds an intercept-column and makes the matrix full-rank. +#' } +#' +#' See the vignettes +#' that come with the \code{lmvar} package for more info. Run \code{vignette(package="lmvar")} to list the available vignettes. +#' +#' @export +#' +#' @example R/examples/lmvar_examples.R +#' +lmvar <- function( y, X_mu = NULL, X_sigma = NULL, check_hessian = TRUE, ...){ + + dlogL <- function(beta_sigma){ + + # Functions returns derivative (gradient) of log likelihood wrt beta_sigma + + sigma = as.numeric(exp( X_sigma %*% beta_sigma)) + + M = X_mu * (1/sigma) + M = tryCatch( chol2inv(chol(Matrix::t(M) %*% M)), # Exploit that t(M) %*% M is symmetric and positive-definite + + error = function(e){ + i = which.min(beta_sigma) + name = colnames(X_sigma)[i] + value = beta_sigma[i] + message( "Smallest element of beta_sigma is '", name, "' with value ", signif( value, 3)) + i = which.max(beta_sigma) + name = colnames(X_sigma)[i] + value = beta_sigma[i] + message( "Largest element of beta_sigma is '", name, "' with value ", signif( value, 3)) + stop(e) + }) + + beta_mu = M %*% Matrix::t(X_mu) %*% (y / (sigma * sigma)) + mu = as.numeric(X_mu %*% beta_mu) + + res = (y - mu) / sigma + + dBeta_sigma = as.numeric(Matrix::t(X_sigma) %*% (res*res - 1)) # gradient of log-likelihood w.r.t. beta_sigma + + return(dBeta_sigma) + } + + hesslogL <- function(beta_sigma){ + + # Functions returns hessian matrix of log likelihood + + sigma = as.numeric(exp( X_sigma %*% beta_sigma)) + + M = X_mu * (1/sigma) + M = chol2inv(chol(Matrix::t(M) %*% M)) # Exploit that t(M) %*% M is symmetric and positive-definite + + beta_mu = M %*% Matrix::t(X_mu) %*% (y / (sigma * sigma)) + mu = as.numeric(X_mu %*% beta_mu) + res = (y - mu) / sigma + + XT = chol(M) %*% Matrix::t(X_mu) %*% (X_sigma * (res / sigma)) # Use Choleski decomposition to have H_ss_1 symmetric + H_ss_1 = 4 * as.matrix(Matrix::t(XT) %*% XT) + + XT = X_sigma * abs(res) + H_ss_2 = -2 * as.matrix(Matrix::t(XT) %*% XT) + + return(H_ss_1 + H_ss_2) + } + + # Check inputs + if (!is.null(X_mu)){ + if (nrow(as.matrix(X_mu)) != length(y)){ + stop("Number of rows of matrix X_mu not equal to length of response vector y") + } + if (is.element( "(Intercept)", colnames(X_mu))){ + stop("Matrix X_mu can not have a column with the name '(Intercept)'") + } + } + if + (!is.null(X_sigma)){ + if (nrow(as.matrix(X_sigma)) != length(y)){ + stop("Number of rows of matrix X_sigma not equal to length of response vector y") + } + if (is.element( "(Intercept_s)", colnames(X_sigma))){ + stop("Matrix X_sigma can not have a column with the name '(Intercept_s)'") + } + } + + n = length(y) + + # Add intercept column to X_mu and X_sigma + Intercept = rep.int(1, n) + if (is.null(X_mu)){ + X_mu = matrix(Intercept, nrow=n, ncol=1) + } + else { + X_mu = cbind( Intercept, X_mu) + } + + if (is.null(X_sigma)){ + X_sigma = matrix(Intercept, nrow=n, ncol=1) + } + else { + X_sigma = cbind( Intercept, X_sigma) + } + + # Initialize aliased columns + aliased_mu = logical(length = ncol(X_mu)) + names(aliased_mu) = matrix_column_names( X_mu, X_sigma)$colnames_X + aliased_sigma = logical(length = ncol(X_sigma)) + names(aliased_sigma) = matrix_column_names( X_mu, X_sigma)$colnames_X_sigma + + # Turn matrices into a full-rank matrices + X_mu = make_matrix_full_rank(X_mu) + if (class(X_mu) == 'numeric'){ + X_mu = as.matrix(X_mu) + } + X_sigma = make_matrix_full_rank(X_sigma) + if (class(X_sigma) == 'numeric'){ + X_sigma = as.matrix(X_sigma) + } + + # Give matrices column names if there are none + colnames(X_mu) = matrix_column_names( X_mu, X_sigma)$colnames_X + colnames(X_sigma) = matrix_column_names( X_mu, X_sigma)$colnames_X_sigma + + # set aliased columns + a_names = names(aliased_mu) + aliased_mu = !is.element( a_names, colnames(X_mu)) + names(aliased_mu) = a_names + a_names = names(aliased_sigma) + aliased_sigma = !is.element( a_names, colnames(X_sigma)) + names(aliased_sigma) = a_names + + if (nrow(X_mu) < (ncol(X_mu) + ncol(X_sigma))){ + stop("Too few observations. There must be at least ", ncol(X_mu) + ncol(X_sigma), " observations.") + } + + # Initial estimate by ordinary linear regression + fit = stats::lm( y ~ .+0, as.data.frame(as.matrix(X_mu)), model = FALSE) + beta = stats::coef(fit) + sigma = summary(fit)$sigma + beta_sigma = log(sigma) * solve( Matrix::t(X_sigma) %*% X_sigma) %*% Matrix::colSums(X_sigma) # Minimize sum over all elements of (X_sigma %*% beta_sigma - log(sigma))^2 + beta_sigma = as.numeric(beta_sigma) + + l = length(beta) + + # Likelihood of model with constant variance + sigma2 = fit$residuals %*% fit$residuals / n + logLik_lm = -n * (log(2*pi*sigma2) + 1) / 2 + logLik_lm = as.numeric(logLik_lm) + + # Calculate betas + solve_result = nleqslv::nleqslv( beta_sigma, dlogL, jac = hesslogL) + + if (solve_result$termcd == 2 | solve_result$termcd == 3){ + max_value = max(abs(dlogL(solve_result$x))) + warning( c( solve_result$message, ". Maximum absolute value in gradient should be within 1e-08 but is ", signif( max_value, 4))) + } + else if (solve_result$termcd > 3 | solve_result$termcd < 1){ + stop( solve_result$message) + } + beta_sigma = solve_result$x + + sigma = as.numeric(exp( X_sigma %*% beta_sigma)) + M = X_mu * (1/sigma) + M = solve(Matrix::t(M) %*% M) + beta = as.numeric(M %*% Matrix::t(X_mu) %*% (y / (sigma * sigma))) + + + # Check Hessian + if (check_hessian){ + if(!matrixcalc::is.negative.definite(hesslogL(beta_sigma))){ + warning("Log-likelihood appears not to be at a maximum!") + } + } + + # Calculate log-likelihood + mu = as.numeric(X_mu %*% beta) + sigma = as.numeric(exp(X_sigma %*% beta_sigma)) + res = (y-mu) / sigma + logLik= -0.5*n*log(2*pi) - sum(log(sigma)) - 0.5*sum(res*res) + + # Associate betas and other result vectors with names of covariates + names(beta) = colnames(X_mu) + names(beta_sigma) = colnames(X_sigma) + + rlist = list( call = match.call(), + coefficients_mu = beta, + coefficients_sigma = beta_sigma, + logLik = logLik, + logLik_lm = logLik_lm, + aliased_mu = aliased_mu, + aliased_sigma = aliased_sigma, + y = y, + X_mu = X_mu, + X_sigma = X_sigma) + + class(rlist) = "lmvar" + + return(rlist) + +} diff --git a/R/logLik.lmvar.R b/R/logLik.lmvar.R new file mode 100644 index 0000000..4275a1e --- /dev/null +++ b/R/logLik.lmvar.R @@ -0,0 +1,21 @@ +#' Log-likelihood for an object of class 'lmvar' +#' +#' @param object Object of class 'lmvar' +#' @param ... For compatibility with \code{\link[stats]{logLik}} generic +#' +#' @return 'logLik' object, a number containing the log-likelihood with an attribute 'df' containing the degrees of freedom +#' +#' @export +#' +#' @seealso \code{\link{dfree}} for the degrees of freedom for an object of class 'lmvar'. +#' +#' @example R/examples/logLik_examples.R +#' +logLik.lmvar <- function( object, ...){ + + logl = object$logLik + attr(logl, "df") = dfree(object) + class(logl) = "logLik" + + return(logl) +} diff --git a/R/make_matrix_full_rank.R b/R/make_matrix_full_rank.R new file mode 100644 index 0000000..0a13764 --- /dev/null +++ b/R/make_matrix_full_rank.R @@ -0,0 +1,15 @@ + +make_matrix_full_rank <- function( X){ + + # Function removes as many columns from the matrix as needed to make the matrix X full-rank + + # Input: X: matrix + + # Output: the full rank-matrix + + qX = qr(as.matrix(X)) + + X = X[, qX$pivot[1:qX$rank]] + + return(X) +} diff --git a/R/matrix_column_names.R b/R/matrix_column_names.R new file mode 100644 index 0000000..ab3dc61 --- /dev/null +++ b/R/matrix_column_names.R @@ -0,0 +1,23 @@ +matrix_column_names <- function( X, X_sigma){ + + # Helper function to set column names of matrices + + colnames(X)[1] = "(Intercept)" + l = ncol(X) + if (l > 1){ + if (all(colnames(X)[2:l] == "")){ + colnames(X)[2:l] = sapply(2:l, function(x){paste('v', as.character(x-1), sep="")}) + } + } + + colnames(X_sigma)[1] = "(Intercept_s)" + l = ncol(X_sigma) + if (l > 1){ + if (all(colnames(X_sigma)[2:l] == "")){ + colnames(X_sigma)[2:l] = sapply(2:l, function(x){paste('v', as.character(x-1), "_s", sep="")}) + } + } + + return( list( colnames_X = colnames(X), + colnames_X_sigma = colnames(X_sigma))) +} diff --git a/R/nobs.lmvar.R b/R/nobs.lmvar.R new file mode 100644 index 0000000..70c3235 --- /dev/null +++ b/R/nobs.lmvar.R @@ -0,0 +1,18 @@ +#' @title Number of observations for an object of class 'lmvar' +#' +#' @description The number of observations in an object of class 'lmvar'. +#' +#' @param object Object of class 'lmvar' +#' @param ... For compatibility with \code{\link[stats]{nobs}} generic +#' +#' @return Integer containing the number of observations in the model in \code{object}. +#' +#' @importFrom stats nobs +#' +#' @export +#' +#' @example R/examples/nobs_examples.R + +nobs.lmvar <- function( object, ...){ + return(length(object$y)) +} diff --git a/R/predict.lmvar.R b/R/predict.lmvar.R new file mode 100644 index 0000000..a46f767 --- /dev/null +++ b/R/predict.lmvar.R @@ -0,0 +1,279 @@ +#' @title Predictions for model matrices +#' +#' @description Estimators and confidence intervals for the expected values and standard deviations of the response-vector \eqn{Y}, given +#' model matrices \code{X_mu} and \code{X_sigma}. +#' The estimators are based on the maximum likelihood-estimators for \eqn{\beta_\mu} and \eqn{\beta_\sigma} +#' present in an 'lmvar' object. This object can be a fit to either the response vector or the logarithm of the response vector. +#' +#' @param object Object of class 'lmvar' +#' @param X_mu Model matrix for the expected values +#' @param X_sigma Model matrix for the logarithm of the standard deviations +#' @param mu Boolean, specifies whether or not to include the predictions for the expected values +#' @param sigma Boolean, specifies whether or not to include the predictions for the standard deviations +#' @param log Boolean, specifies whether \code{object} is a fit to a response-variable \eqn{Y} or to its logarithm \eqn{\log Y} +#' In both cases, \code{predict.lmvar} returns expeced values and standard deviations for \eqn{Y} itself. +#' @param interval Character string, specifying the type of interval. Possible values are +#' \itemize{ +#' \item "none" No interval +#' \item "confidence" Confidence intervals for the expected values (if \code{mu = TRUE}) and the standard deviation +#' (if \code{sigma = TRUE}) +#' } +#' @param level Numeric value between 0 and 1, specifying the confidence level +#' @param ... For compatibility with \code{\link[stats]{predict}} generic +#' +#' @return In the case \code{mu = FALSE} and \code{interval = "none"}: a numeric vector containing the estimators for +#' the standard deviation. +#' +#' In the case code{sigma = FALSE} and \code{interval = "none"}: a numeric vector containing the estimators for +#' the expected values. +#' +#' In all other cases: a matrix with one column for each requested feature and one row for each observation. The column names are +#' \itemize{ +#' \item \code{mu} Estimators for the expected value \eqn{\mu} +#' \item \code{sigma} Estimators for the standard deviation \eqn{\sigma} +#' \item \code{mu_lwr} Lower bound of the interval for \eqn{\mu} +#' \item \code{mu_upr} Upper bound of the interval for \eqn{\mu} +#' \item \code{sigma_lwr} Lower bound of the interval for \eqn{\sigma} +#' \item \code{sigma_upr} Upper bound of the interval for \eqn{\sigma} +#' } +#' +#' @export +#' +#' @details When \code{X_mu = NULL}, the model matrix \eqn{X_\mu} is taken from \code{object}. Likewise, when +#' \code{X_sigma = NULL}, \eqn{X_\sigma} is taken from \code{object}. +#' +#' Both \code{X_mu} and \code{X_sigma} must have column names. Column names are matched with the names of the elements of +#' \eqn{\beta_\mu} and \eqn{\beta_\sigma} in \code{object}. Columns with non-matching names are ignored. In case not all +#' names in \eqn{\beta_\mu} can be matched with a column in \code{X_mu}, a warning is given. The same is true for \eqn{\beta_\sigma} +#' and \code{X_sigma}. +#' +#' \code{X_mu} can not have a column with the name "(Intercept)". This column is added by \code{predict.lmvar}. Likewise, +#' \code{X_sigma} can not have a column with the name "(Intercept_s)". +#' +#' Both matrices must be numeric and can not contain special values like +#' \code{NULL}, \code{NaN}, etc. +#' +#' If \code{log = FALSE}, \code{predict.lmvar} returns +#' expected values and standard deviations for the observations \eqn{Y} corresponding to the model matrices \eqn{X_\mu} +#' and \eqn{X_\sigma}. +#' +#' If \code{log = TRUE}, \code{predict.lmvar} returns expected values and standard deviations for \eqn{e^Y}. +#' +#' Confidence intervals are calculated with an approximation that is valid when the number of observations is large. +#' Intervals must be treated cautiously in case of a small number of observations. +#' +#' \code{predict.lmvar} with \code{X_mu = NULL} and \code{X_sigma = NULL} is equivalent to the function +#' \code{\link{fitted.lmvar}}. +#' +#' @seealso \code{\link{coef.lmvar}} for the maximum likelihood estimators of \eqn{\beta_\mu} and \eqn{\beta_\sigma} +#' in an object of class 'lmvar'. +#' +#' \code{\link{fitted.lmvar}} for the expected values and standard deviations of the response vector in an object of class +#' 'lmvar'. +#' +#' @example R/examples/predict_examples.R +#' + +predict.lmvar <- function( object, X_mu = NULL, X_sigma = NULL, mu = TRUE, sigma = TRUE, log = FALSE, + interval = c("none", "confidence"), level = 0.95, ...){ + + # Check column names + if (is.element('(Intercept)', colnames(X_mu))){ + stop("Matrix X_mu is not allowed to have a column named '(Intercept)'") + } + if (is.element('(Intercept_s)', colnames(X_sigma))){ + stop("Matrix X_sigma is not allowed to have a column named '(Intercept_s)'") + } + + # Check interval + interval = interval[1] + if (!is.element( interval, c("none", "confidence"))){ + stop("The value of 'interval' is invalid") + } + + # Check level + if (level <= 0 | level >=1){ + stop("The value of 'level' must be larger than 0 and smaller than 1") + } + + # Set matrices, check number of matrix rows + if (is.null(X_mu)){ + X_mu = object$X_mu + } + else { + X_mu = as.matrix(X_mu) + Intercept = rep.int(1, nrow(X_mu)) + X_mu = cbind( Intercept, X_mu) + } + + if (is.null(X_sigma)){ + X_sigma = object$X_sigma + } + else { + X_sigma = as.matrix(X_sigma) + Intercept = rep.int(1, nrow(X_sigma)) + X_sigma = cbind( Intercept, X_sigma) + } + + # check number of rows + if (nrow(X_mu) != nrow(X_sigma)){ + stop("Number of rows in X_mu and X_sigma are not equal") + } + + # Set column names + colnames(X_mu) = matrix_column_names( X_mu, X_sigma)$colnames_X + colnames(X_sigma) = matrix_column_names( X_mu, X_sigma)$colnames_X_sigma + + # Check column names + covnames = names(coef.lmvar( object, sigma = FALSE)) + if (!all(is.element( covnames, colnames(X_mu)))){ + warning("Model matrix for mu does not contain all covariates for mu in 'lmvar' object. + Beware of unreliable predictions.") + } + covnames = names(coef.lmvar( object, mu = FALSE)) + if (!all(is.element( covnames, colnames(X_sigma)))){ + warning("Model matrix for sigma does not contain all covariates for sigma in 'lmvar' object. + Beware of unreliable predictions.") + } + + # Remove columns not present in the coefficients + beta_mu = coef.lmvar( object, sigma = FALSE) + beta_sigma = coef.lmvar( object, mu = FALSE) + + cols = which(is.element( colnames(X_mu), names(beta_mu))) + if (length(cols) == 1){ + cnames = colnames(X_mu)[cols] + X_mu = as.matrix(X_mu[,cols]) + colnames(X_mu) = cnames + } + else { + X_mu = X_mu[,cols] + } + + cols = which(is.element( colnames(X_sigma), names(beta_sigma))) + if (length(cols) == 1){ + cnames = colnames(X_sigma)[cols] + X_sigma = as.matrix(X_sigma[,cols]) + colnames(X_sigma) = cnames + } + else { + X_sigma = X_sigma[,cols] + } + + # Select beta_mu and beta_sigma elements and re-order + beta_mu = beta_mu[colnames(X_mu)] + beta_sigma = beta_sigma[colnames(X_sigma)] + + # Calculate predictions + predicted_mu = numeric() + predicted_sigma = numeric() + + if (mu | log){ + + predicted_mu = as.numeric(X_mu %*% beta_mu) + } + + if (sigma | log | (interval != "none")){ + + predicted_sigma = as.numeric(exp(X_sigma %*% beta_sigma)) + + # Store value for later use + predicted_sigma_not_log = predicted_sigma + } + + if (log){ + predicted_mu = exp( predicted_mu + predicted_sigma_not_log^2 / 2) + if (sigma){ + predicted_sigma = predicted_mu * sqrt(exp(predicted_sigma_not_log^2) - 1) + } + } + + # Calculate confidence intervals + if (interval != "none"){ + + z = stats::qnorm( 0.5 + level/2) + + if (mu | log){ + + # Calculate variances of mu + S = vcov.lmvar( object, sigma = FALSE) + S = S[ colnames(X_mu), colnames(X_mu)] + S = chol(S) + S = X_mu %*% Matrix::t(S) + variances_mu = Matrix::rowSums(S*S) + } + + if (sigma | log){ + + # Calculate variances of log sigma + S = vcov.lmvar( object, mu = FALSE) + S = S[ colnames(X_sigma), colnames(X_sigma)] + S = chol(S) + S = X_sigma %*% Matrix::t(S) + variances_log_sigma = Matrix::rowSums(S*S) + } + + # Calculate intervals for mu + if (mu){ + if (!log){ + delta = z * sqrt(variances_mu) + } + else { + delta = z * predicted_mu * sqrt(variances_mu + predicted_sigma_not_log^4 * variances_log_sigma) + } + mu_down = predicted_mu - delta + mu_up = predicted_mu + delta + } + + # Calculate intervals for sigma + if (sigma){ + if (!log){ + delta = z * predicted_sigma * sqrt(variances_log_sigma) + } + else { + delta = predicted_sigma^2 * variances_mu + + (2 * predicted_sigma + predicted_mu^2 / predicted_sigma)^2 * predicted_sigma_not_log^4 * variances_log_sigma + delta = z * sqrt(delta) + } + sigma_down = predicted_sigma - delta + sigma_up = predicted_sigma + delta + } + } + + # Construct output for expected values + mu_out = numeric() + if (mu){ + if (interval == "none"){ + mu_out = matrix( predicted_mu, ncol = 1) + colnames(mu_out) = "mu" + } + else { + mu_out = cbind( predicted_mu, mu_down, mu_up) + colnames(mu_out) = c("mu", "mu_lwr", "mu_upr") + } + } + + # Construct output for standard deviations + sigma_out = numeric() + if (sigma){ + if (interval == "none"){ + sigma_out = matrix( predicted_sigma, ncol = 1) + colnames(sigma_out) = "sigma" + } + else { + sigma_out = cbind( predicted_sigma, sigma_down, sigma_up) + colnames(sigma_out) = c("sigma", "sigma_lwr", "sigma_upr") + } + } + + # Construct full output + out = cbind( mu_out, sigma_out) + if (ncol(out) == 1){ + out = as.numeric(out) + } + else{ + colnames(out) = c( colnames(mu_out), colnames(sigma_out)) + } + + return(out) +} diff --git a/R/print.summary_lmvar.R b/R/print.summary_lmvar.R new file mode 100644 index 0000000..0b37bf2 --- /dev/null +++ b/R/print.summary_lmvar.R @@ -0,0 +1,51 @@ +#' @title Print method for the summary of an 'lmvar' object. +#' +#' @description Print method for an object of the class 'summary_lmvar'. This object is created by \code{\link{summary.lmvar}}. +#' +#' @param x Object of class 'summary_lmvar' +#' @param ... For compatibility with \code{\link[base]{print}} generic. +#' +#' @export +#' +#' @seealso \code{\link{summary.lmvar}} for a summary of the fit present in an object of class 'lmvar'. +#' +#' @method print summary_lmvar +#' + +print.summary_lmvar <- function( x, ...){ + + cat ("Call: \n ") + print( x$call) + cat("\n") + + cat ("Standardized residuals: \n") + print( round( x$residuals, 4)) + cat("\n") + + + # Add aliased coefficients to the table of coefficients + b_names = c( names(x$aliased_mu), beta_sigma_names( names(x$aliased_mu), names(x$aliased_sigma))) + df = x$coefficients[ b_names,] + rownames(df) = b_names + + # Number of aliased coefficients + n = sum(x$aliased_mu) + sum(x$aliased_sigma) + if (n==0){ + cat("Coefficients:\n") + } + else { + cat("Coefficients: (", n, " not defined because of singularities)","\n", sep = "") + } + + stats::printCoefmat( df, cs.ind = 1:2, tst.ind = 3, has.Pvalue = TRUE, P.values = TRUE) + cat("\n") + + cat ("Standard deviations: \n") + print( round( x$sigma, 4)) + cat("\n") + + cat("Comparison to model with constant variance (i.e. classical linear model)\n") + cat("Log likelihood-ratio:", x$logLik_ratio, "\n") + cat("Additional degrees of freedom:", x$df, "\n") + cat("p-value for difference in deviance:", signif( x$p_value, 3), "\n") +} diff --git a/R/residuals.lmvar.R b/R/residuals.lmvar.R new file mode 100644 index 0000000..1836ad3 --- /dev/null +++ b/R/residuals.lmvar.R @@ -0,0 +1,36 @@ +#' @title Residuals from an 'lmvar' object +#' +#' @description Calculates residuals from an 'lmvar' object. This object can be a fit to either a response vector or the +#' logarithm of the response vector. +#' +#' @param object Object of class 'lmvar' +#' @param log Boolean, specifies whether \code{object} is a fit to a response-variable \eqn{Y} or to its logarithm \eqn{\log Y} +#' In both cases, \code{residuals.lmvar} returns residuals for \eqn{Y} itself. +#' @param ... For compatibility with \code{\link[stats]{residuals}} generic +#' +#' @return A numeric vector with the residual for each observation in \code{object}. +#' +#' @details In case \code{log = FALSE}, the residual of an observation is defined as \eqn{y - \mu}, where \eqn{y} is the value of the observation and \eqn{\mu} its expected +#' value. +#' +#' In case \code{log = TRUE}, the residual of an observation is defined as \eqn{e^y - \mu}, where \eqn{\mu} is the expected +#' value of \eqn{e^y}. +#' +#' @seealso \code{\link{fitted.lmvar}} for the expected values in an object of class 'lmvar'. +#' +#' @export +#' +#' @example R/examples/residuals_examples.R +#' + +residuals.lmvar <- function( object, log = FALSE, ...){ + + if (log){ + res = exp(object$y) - fitted.lmvar(object, sigma = FALSE, log = TRUE) + } + else { + res = object$y - fitted.lmvar(object, sigma = FALSE) + } + + return(res) +} diff --git a/R/summary.lmvar.R b/R/summary.lmvar.R new file mode 100644 index 0000000..5e11d4d --- /dev/null +++ b/R/summary.lmvar.R @@ -0,0 +1,114 @@ +#' @title Summary overview for an object of class 'lmvar' +#' +#' @description Summary overview for an object of class 'lmvar'. +#' +#' @param object Object of class 'lmvar' +#' @param ... For compatibility with \code{\link[base]{summary}} generic +#' +#' @return An object of class 'summary_lmvar'. This is a list with the following members: +#' \itemize{ +#' \item \code{call} Call that created \code{object} +#' +#' \item \code{coefficients} Data frame +#' with one row for each element of \eqn{\beta_\mu} and \eqn{\beta_\sigma} and the following variables. +#' \itemize{ +#' \item \code{Estimate} maximum-likelihood estimate +#' \item \code{Std. Error} standard error, defined as \eqn{\sqrt(var(\beta))} with \eqn{var(\beta)} the estimated variance +#' of \eqn{\beta}. +#' \item \code{t value} t-statistic, defined as \eqn{\beta / \sqrt(var(\beta))} +#' \item \code{Pr(>|t|)} p-value of the t-statistic, calculated from the normal distribution. +#' } +#' \item \code{residuals} A numeric vector with the minimum, the 25\% quartile, the median, the 75\% quartile and the maximum +#' standardized residual. The standardized residual of an observation is defined as \eqn{(y - \mu) / \sigma} where \eqn{y} is the value +#' of the observation, \eqn{\mu} the expectation value and \eqn{\sigma} +#' the standard deviation of the observation. +#' \item \code{sigma} A numeric vector with the minimum, the 25\% quartile, the median, the 75\% quartile and the maximum +#' standard deviation \eqn{\sigma} of all observations. +#' \item \code{aliased_mu} A named logical vector. The names are the column names of the user-supplied model matrix +#' \eqn{X_\mu}. The values (\code{TRUE} or \code{FALSE}) tell whether or not the column +#' has removed by \code{lmvar} to make the matrix full-rank. +#' \item \code{aliased_sigma} As \code{aliased_mu} but for the user-supplied model matrix \eqn{X_\sigma}. +#' \item \code{logLik_ratio} The difference in log-likelihood between the model in \code{object} and a classical linear +#' model with model matrix \eqn{X_\mu} and a constant variance for all observations. +#' \item \code{df} The difference in degrees in freedom between the model in \code{object} and a classical linear +#' model with model matrix \eqn{X_\mu} and a constant variance for all observations. +#' \item \code{p_value} The p-value of \code{2 loglik_ratio}, calculated from a chi-squared distribution with \code{df} +#' degrees of freedom. +#' } +#' +#' @details Standard errors and t-statistics are calculated from the estimated covariance matrix and may not +#' be reliable when the number of observations in \code{object} is small. +#' +#' @seealso \code{\link[stats]{coef}} to extract the matrix with estimates, standard-errors, t-statistics and +#' p-values for \eqn{\beta_\mu} and \eqn{\beta_\sigma} from a 'summary_lmvar' object. +#' +#' \code{\link{vcov.lmvar}} for the covariance matrix of the \eqn{\beta_\mu} and \eqn{\beta_\sigma} in an object of class +#' 'lmvar'. +#' +#' \code{\link{print.summary_lmvar}} for a print method for a 'summary_lmvar' object. +#' +#' \code{\link{fitted.lmvar}} for the expected values and standard deviations +#' of the observations in an object of class 'lmvar'. +#' +#' \code{\link{logLik.lmvar}} for the log-likelihood of a fit in an object of class 'lmvar'. +#' +#' \code{\link{alias.lmvar}} to obtain the aliased columns of the user-supplied model matrices in the call of \code{\link{lmvar}}. +#' +#' @method summary lmvar +#' +#' @export +#' +#' @example R/examples/summary_examples.R +#' +summary.lmvar <- function(object, ...){ + + beta_mu = coef.lmvar( object, sigma = FALSE) + beta_sigma = coef.lmvar( object, mu = FALSE) + + # get the names of the betas + beta_sigma_names = beta_sigma_names( names(beta_mu), names(beta_sigma)) + beta_names = c( names(beta_mu), beta_sigma_names) + + # Calculate varianve-covariance matrices + I_mu = vcov.lmvar( object, sigma = FALSE) + I_sigma = vcov.lmvar( object, mu = FALSE) + + # Calculate variance-related statistics + variances = c( Matrix::diag(I_mu), Matrix::diag(I_sigma)) + sterr = sqrt(variances) + z_values = c(beta_mu, beta_sigma) / sterr + pr_z = 2 * stats::pnorm( abs(z_values), lower.tail = FALSE) + + # calculate data-vectors for dataframe 'coefficients' + estimate = c( beta_mu, beta_sigma) + + coeff = data.frame( "Estimate"= estimate, "Std. Error"=sterr, "z value"=z_values, "Pr(>|z|)"=pr_z, + row.names = beta_names, check.names = FALSE) + + # Retrieve sigmas + sigma = fitted.lmvar( object, mu=FALSE) + + # Calculate standardized residuals + res = residuals.lmvar(object) / sigma + res = stats::quantile( res, c( 0, 0.25, 0.5, 0.75, 1)) + names(res) = c( "Min", "1Q", "Median", "3Q", "Max") + + # Summarize sigmas in quantiles + sigma = stats::quantile( sigma, c( 0, 0.25, 0.5, 0.75, 1)) + names(sigma) = c( "Min", "1Q", "Median", "3Q", "Max") + + + rlist = list( call = object$call, + residuals = res, + coefficients = coeff, + sigma = sigma, + aliased_mu = object$aliased_mu, + aliased_sigma = object$aliased_sigma, + logLik_ratio = object$logLik - object$logLik_lm, + df = dfree( object, mu = FALSE) - 1, + p_value = stats::pchisq(2 * (object$logLik - object$logLik_lm), dfree( object, mu = FALSE) - 1, lower.tail = FALSE)) + + class(rlist) = "summary_lmvar" + + return(rlist) +} diff --git a/R/vcov.lmvar.R b/R/vcov.lmvar.R new file mode 100644 index 0000000..77a511b --- /dev/null +++ b/R/vcov.lmvar.R @@ -0,0 +1,82 @@ +#' @title Variance-covarience matrix of the coefficients beta for an object of class 'lmvar' +#' +#' @description Variance-covarience matrix (also simply called the 'covariance matrix') for the +#' maximum-likelihood estimators of \eqn{\beta_\mu} and \eqn{\beta_\sigma}. +#' The matrix is calculated using an expression which is only valid in the limit of a large number of +#' observations. +#' +#' @param object Object of class 'lmvar' +#' @param mu Specifies whether or not the covariance matrix for \eqn{\beta_\mu} is included in the returned matrix +#' @param sigma Specifies whether or not the covariance matrix for \eqn{\beta_\sigma} is included in the returned matrix +#' @param ... For compatibility with \code{\link[stats]{vcov}} generic +#' +#' @return A 'matrix' object containing the (approximate) variance-covariance matrix of the maximum-likelihood estimators +#' of \eqn{\beta_\mu} and \eqn{\beta_\sigma} in \code{object}. +#' +#' @details The variance-covariance matrix is calculated as \eqn{I^{-1} / n} where \eqn{I} is the Fisher +#' information matrix and \eqn{n} the number of observations. +#' +#' When \code{mu = TRUE} and \code{sigma = TRUE}, the full covariance matrix for the combined vector +#' \eqn{(\beta_\mu, \beta_\sigma)} is returned. +#' +#' When \code{mu = TRUE} and \code{sigma = FALSE}, only the covariance matrix for \eqn{\beta_\mu} is returned. +#' +#' When \code{mu = FALSE} and \code{sigma = TRUE}, only the covariance matrix for \eqn{\beta_\sigma} is returned. +#' +#' @export +#' +#' @seealso \code{\link{summary.lmvar}} for standard errors for \eqn{\beta_\mu} and \eqn{\beta_\mu}. +#' +#' \code{\link{nobs.lmvar}} for the number of observations in an object of class 'lmvar'. +#' +#' \code{\link{fisher}} for the Fisher information matrix of an object of class 'lmvar'. +#' +#' See the vignette "Math" (to be viewed with \code{vignette("Math", "lmvar")}) for details. +#' + +vcov.lmvar <- function(object, mu = TRUE, sigma = TRUE, ...){ + + # Calculate the inverses per block-matrix for efficiency + + if (mu){ + S_mu = fisher( object, sigma = FALSE) + S_mu = chol2inv(chol(S_mu)) / nobs(object) + } + + if (sigma){ + S_sigma = fisher( object, mu = FALSE) + S_sigma = chol2inv(chol(S_sigma)) / nobs(object) + } + + # Create block-matrix of zeros + if (mu & sigma){ + S_0 = matrix( 0, nrow = nrow(S_mu), ncol = ncol(S_sigma)) + } + + # Set row and column names + beta_mu_names = names( stats::coef(object, sigma = FALSE)) + beta_sigma_names = names( stats::coef(object, mu = FALSE)) + + # Compose matrix from block-matrices + if (mu & !sigma){ + rownames(S_mu) = beta_mu_names + colnames(S_mu) = beta_mu_names + return(S_mu) + } + else if (!mu & sigma){ + rownames(S_sigma) = beta_sigma_names + colnames(S_sigma) = beta_sigma_names + return(S_sigma) + } + else if (mu & sigma){ + S = rbind( cbind( S_mu, S_0), cbind( Matrix::t(S_0), S_sigma)) + beta_sigma_names = beta_sigma_names( beta_mu_names, beta_sigma_names) + beta_names = c( beta_mu_names, beta_sigma_names) + rownames(S) = beta_names + colnames(S) = beta_names + return(S) + } + else{ + return(matrix( 0, nrow = 0, ncol = 0)) + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e90e65f --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ + + +When to use the 'lmvar' package? +-------------------------------- + +The 'lmvar' package fits a linear model in which the variance can be different for different observations. The assumption of a constant variance inherent in a classical linear model, is dropped in 'lmvar'. I.e., 'lmvar' fits a heteroscedastic model whereas the classical linear model is homoscedastic. In those cases where the restriction of a constant variance is too restrictive in the linear model, 'lmvar' provides an alternative. + +Hence 'lmvar' is an alternative for the function `lm` in the package 'stats'. + +How to use the 'lmvar' package? +------------------------------- + +The main function in the package is `lmvar`. Its basic usage requires three arguments: + +- a vector of response values +- a model matrix for the expected values of the responses +- a model matrix for the logarithms of the standard deviations of the responses. + +As an example we use the data frame 'cats' in the package 'MASS'. We regress the cats heart weight 'Hwt' onto their body weight 'Bwt'. + +``` r +require(MASS) +#> Loading required package: MASS +require(lmvar) +#> Loading required package: lmvar + +# Create the model matrix. Use the same matrix for the expected values and the standard deviations. +X = matrix( cats$Bwt, ncol = 1) +colnames(X) = "Bwt" + +# Perform the fit +fit = lmvar( cats$Hwt, X, X) + +# Print a summary of the fit +summary(fit) +#> Call: +#> lmvar(y = cats$Hwt, X_mu = X, X_sigma = X) +#> +#> Standardized residuals: +#> Min 1Q Median 3Q Max +#> -2.4220 -0.7276 -0.0656 0.6722 2.6313 +#> +#> Coefficients: +#> Estimate Std. Error t value Pr(>|t|) +#> (Intercept) -0.012179 0.679820 -0.0179 0.985707 +#> Bwt 3.904310 0.258964 15.0766 < 2.2e-16 *** +#> (Intercept_s) -0.522274 0.337044 -1.5496 0.121244 +#> Bwt_s 0.315837 0.121843 2.5922 0.009537 ** +#> --- +#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 +#> +#> Standard deviations: +#> Min 1Q Median 3Q Max +#> 1.1094 1.2227 1.3892 1.5385 2.0087 +#> +#> Comparison to model with constant variance (i.e. classical linear model) +#> Log likelihood-ratio: 4.069774 +#> Additional degrees of freedom: 1 +#> p-value for difference in deviance: 0.00433 +``` + +The low p-value in the summary is a strong indication that 'lmvar' does a better fit than 'lm'. The spread of the heart weight values grows with increasing body weight, resulting in a larger standard deviation of the heart weight with increasing body weight. + +What is in the 'lmvar' package? +------------------------------- + +The function `lmvar` produces an object of class 'lmvar'. In the example above, this is the object `fit`. The package provides a number of utility functions to extract information from an 'lmvar' object. The example above demonstrates the utility function `summary`. There are also utility functions to obtain the fitted coefficients, the expected values, the standard deviations, the log-likelihood, the degrees of freedom, the covariance matrix, the AIC value, and more. To view the whole list of functions, use `help(package = "lmvar")`. + +Further reading +--------------- + +The package comes with two vignettes: 'Intro' and 'Math'. 'Intro' gives an introduction to the package and is helpful reading for new users. 'Math' gives a detailed mathematical background to the package. The vignette 'Intro' can be viewed with `vignette( "Intro", package = "lmvar")`, and likewise for 'Math'. diff --git a/build/vignette.rds b/build/vignette.rds new file mode 100644 index 0000000000000000000000000000000000000000..1d79215cff143528356512b1e3dfbd88a56b0df2 GIT binary patch literal 252 zcmV)zwimDO8h6Y?*j+!)50|d%PScJG18wLikf{QKeBZF2(dic;fJr{_0RRAJ C3UaLg literal 0 HcmV?d00001 diff --git a/inst/doc/Intro.R b/inst/doc/Intro.R new file mode 100644 index 0000000..4d68a8e --- /dev/null +++ b/inst/doc/Intro.R @@ -0,0 +1,45 @@ +## ------------------------------------------------------------------------ +library(lmvar) + +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +## ------------------------------------------------------------------------ +summary(fit) + +## ------------------------------------------------------------------------ +sigma = fitted(fit, mu = FALSE) +hist(sigma) + +## ------------------------------------------------------------------------ +hist(residuals(fit)) + +## ------------------------------------------------------------------------ +dfree(fit, sigma = FALSE) + +## ------------------------------------------------------------------------ +nobs(fit) +logLik(fit) +AIC(fit) + +## ------------------------------------------------------------------------ +coef(fit) + +## ------------------------------------------------------------------------ +coef(fit, mu = FALSE) + +## ------------------------------------------------------------------------ +vcov(fit, sigma = FALSE) + diff --git a/inst/doc/Intro.Rmd b/inst/doc/Intro.Rmd new file mode 100644 index 0000000..6216d38 --- /dev/null +++ b/inst/doc/Intro.Rmd @@ -0,0 +1,176 @@ +--- +title: "A linear model with non-constant variances" +author: "Posthuma Partners" +date: "`r Sys.Date()`" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Introduction to the package} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +## The package +The 'lmvar' package fits a linear model in which the assumption of homoscedasticity (i.e., the variance is independent of the expectation value) is dropped. Instead, the variance has its own model, comparable to the model for the expectation value. + +The fit results in an 'lmvar' object, which is a list of class 'lmvar'. Accessor functions are provided to extract the list members such as the fitted betas and the log-likelihood for the model. Various utility functions such as `residuals` to calculate residuals, `AIC` to calculate the AIC, `fitted` to obtain expected values and standard deviations, etc., are also provided by the package. + +The package lacks much of the sophistication of the 'lm' and 'glm' packages. On the bright side, this means it is simple to use. It is intended for people who run a classical linear model and want to see what happens if the restriction of a constant variance is dropped. Questions in this context are: does the allowance of heteroscedasticity result in a better fit, lower values for the AIC or BIC, smaller errors from a cross-validation, etc.? + +## The model +The package fits the following model. A vector $Y$ of observations (sometimes called 'responses') of length $n$ is a stochastic vector. It is distributed according to a multivariate Gaussian distribution: + +\begin{equation} +Y \sim \mathcal{N}_n( \mu, \Sigma), +\end{equation} +where $\mu$ is the vector of expectation values and $\Sigma$ the covariance matrix (also called the 'variance-covariance matrix'). Just like in the standard linear model, the covariance is taken to be a $n \times n$ diagonal matrix but contrary to the standard linear model, the diagonal entries need not be all the same: +\begin{equation} +\Sigma_{ij} = +\begin{cases} +0 & i \neq j\\ +\sigma_i^2 & i=j +\end{cases} +\end{equation} + +### Model for the expectation values + +As in the classical linear model, the vector of expectation values $\mu$ is given by +\begin{equation} +\mu = X_\mu \beta_\mu +\end{equation} +where $X_\mu$ is the 'model matrix' or 'design matrix' for $\mu$ and $\beta_\mu$ the parameter vector for $\mu$. $X_\mu$ is a $n \times k_\mu$ matrix and $\beta_\mu$ a vector of length $k_\mu$. + +### Model for the variances + +Let $\sigma$ denotes the vector $(\sigma_1, \dots, \sigma_n)$. The model for $\sigma$ is +\begin{equation} +\log \sigma = X_\sigma \beta_\sigma +\end{equation} +where $\log \sigma$ stands for the vector $(\log\sigma_1, \dots, \log\sigma_n)$, $X_\sigma$ is the 'model matrix' or 'design matrix' for $\sigma$ and $\beta_\sigma$ the parameter vector for $\sigma$. The logarithm is taken to be the 'natural logarithm' with base $e$. The dimensions of $X_\sigma$ are $n \times k_\sigma$ and $\beta_\sigma$ is a vector of length $k_\sigma$. + +### Also know that... + +The vector of observations $Y$ and the matrices $X_\mu$ and $X_\sigma$ are specified by the user. They must contain real values. The fit returns the maximum-likelihood estimators for $\beta_\mu$ and $\beta_\sigma$. They are also real-valued vectors. + +The model for both $\mu$ and $\sigma$ contains an intercept term. That means that the first column of both matrices is a column in which each matrix-element equals 1. The package will add this column to the user-suppplied matrices to ensure that the intercept term is always present. There is no need for a user to include such a column in a user-supplied model-matrix. + +After adding the intercept column, the package will check whether the resulting matrices are full rank. If not, columns will be removed from each matrix until it is full rank. + +The addition of an intercept column and, possibly, the removal of columns to obtain a full-rank matrix, imply that the actual matrices used in the fit can be different from the user-specified matrices. The matrices that are actually used in the fit are returned as members of the `lmvar` object. + +Carrying out the fit boils down to solving a set of non-linear equations. This is carried out by the function `nleqslv` from the package with the same name. + +More mathematical details about the model can be found in the vignette 'Math' which comes with this package. It can be viewed with `vignette("Math")` or `vignette("Math", package="lmvar")`. + +## Using the package + +The main function in the package is `lmvar`. It carries out a fit and returns an `lmvar` object. + +The user must specify a vector of observations and two model-matrices when calling `lmvar`. They must meet the following conditions: + +* All observations and matrix elements must be real-valued. +* Missing values, values that are `NaN` etc., are not allowed. +* A matrix either has column names for all columns or no column names at all. The same column name can appear for both $X_\mu$ and $X_\sigma$ but column names should be unique within each matrix. The intercept column that is added automatically by `lmvar` is called `(Intercept)` for $X_\mu$ and `(Intercept_s)` for $X_\sigma$. In case no column-names are specified, the second, third, etc. columns are called `v1`, `v2` etc. for $X_\mu$ and `v1_s`, `v2_s` etc. for $X_\sigma$. +* When the user-supplied matrix $X_\mu$ has column names, none of those should be `(Intercept)`. This is a reserved name, as we explained above. Likewise, a user-supplied matrix $X_\sigma$ must not have a column named `(Intercept_s)`. + +With each column in $X_\mu$ corresponds an element in $\beta_\mu$. +The name of that element is the corresponding column name. The same is true for $X_\sigma$ and $\beta_\sigma$. + +It can happen that `nleqslv` fails to solve the maximum-likelihood equations. Sometimes the problem can be traced back to columns in $X_\sigma$ with many zero's. I.e., covariates (or factor-levels) for $\sigma$ which affect only few observations. Removal of these columns may remedy the issue. + +An `lmvar` object is a list whose members are intended to be extracted with the supplied accessor and utility functions. The only members for which no such functions have been implemented are: + +* `y`: the user-supplied vector of observations +* `X_mu`: the actual, full-rank matrix $X_\mu$ including the intercept term that is used in the fit +* `X_sigma`: the actual, full-rank matrix $X_\sigma$ including the intercept term that is used in the fit + +Once `lmvar` has run and an `lmvar`-object created, one can obtain $\beta_\mu$ and $\beta_\sigma$ with the function `coef`. The function `fitted` allows one to obtain $\mu$ and $\sigma$. We refer to the package documentation (in particular the package index which can be viewed with `help(package = "lmvar")`) for a list of all available functions and function details. + +## Demonstration + +We demonstrate the package with the help of the dataframe `attenu` which can be found in the `datasets` package. +```{r} +library(lmvar) + +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) +``` +We have now created the object `fit` which is our object of class `lmvar`. To obtain a first impression of the fit, we look at the summary +```{r} +summary(fit) +``` +The first line shows the call that created `fit`. Next, we are told something about the distribution of the standardized residuals. Ideally, the first quarter (`1Q`) must be approximately -0.67, the `median` 0 and the third quarter (`3Q`) 0.67. + +Next, the summary shows the matrix with the coefficients $\beta_\mu$ and $\beta_\sigma$. The coefficients $\beta_\mu$ are `(Intercept)`, `mag` and `dist`. The coefficients $\beta_\sigma$ are `(Intercept_s)`, `mag_s` and `dist_inv_s`. They are called this way to distinguish them from the coefficients for $\beta_\mu$. In cases where there is no risk of confusion, their true names will be used, which are `(Intercept_s)`, `mag` and `dist_inv`. + +The matrix with coefficients shows that all coefficients are statistically significant at the 5% level. + +The next piece of information gives an impression of the distribution of the standard deviations. They range from 0.0631 to 42.0983. + +Finally the model is compared to a classical linear model with the same model matrix $X_\mu$ but a fixed standard deviation. The summary shows the difference in log-likelihood between the two models and the difference in degrees of freedom. Twice the difference in log-likelihood is the difference in deviance, for which a p-value is calculated. The fact that the p-value in the summary is nearly zero, indicates that the `lmvar` fit is a better fit than the classical linear model. I.e., it makes sense to let the variance vary instead of keeping it fixed. + +Let's see how the standard deviations are distributed +```{r} +sigma = fitted(fit, mu = FALSE) +hist(sigma) +``` + +To check the distribution of the residuals, we make another histogram. +```{r} +hist(residuals(fit)) +``` + +The rank of the matrix $X_\mu$ used in the fit is +```{r} +dfree(fit, sigma = FALSE) +``` +The value 3 is correct: the user-supplied matrix had 2 columns and `lmvar` added an intercept column. Apparently all columns are linearly independent so no column had to be removed. + +To see the number of observations in the fit, the log-likelihood and the AIC value, we run +```{r} +nobs(fit) +logLik(fit) +AIC(fit) +``` +The coefficients $\beta_\mu$ and $\beta_\sigma$ that were displayed in the summary-overview are obtained by +```{r} +coef(fit) +``` +If we only ask for $\beta_\sigma$,we see their real names +```{r} +coef(fit, mu = FALSE) +``` +We conclude this demonstration with the covariance matrix for the coefficients $\beta_\mu$ +```{r} +vcov(fit, sigma = FALSE) +``` +Hopefully this demonstration has given an idea of how to work with the package. The documentation of the individual fuctions contains further examples. + +## Functions in the package + +We refer to the package index for a list of all available functions. The index can be viewed with `help(package="lmvar")`. + +## Other packages + +The function `remlscore` in the package `statmod` fits precisely the same model as `lmvar`. However, `statmod` does not provide any utility function, which we believe are important to foster the acceptance of this model as a step beyond classical linear regression. + +Other functions that allow for a model of the dispersion are, e.g., `hglm` in the package `hglm` and `geese` in the package `geepack`. These models are more complicated though, and require a level of expertise not required by `lmvar`. + +## Acknowledgements + +We thank prof. dr. Eric Cator for his valuable comments and suggestions. + + diff --git a/inst/doc/Intro.html b/inst/doc/Intro.html new file mode 100644 index 0000000..6ff40c1 --- /dev/null +++ b/inst/doc/Intro.html @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + +A linear model with non-constant variances + + + + + + + + + + + + + + + + + +

A linear model with non-constant variances

+

Posthuma Partners

+

2017-02-16

+ + + +
+

The package

+

The ‘lmvar’ package fits a linear model in which the assumption of homoscedasticity (i.e., the variance is independent of the expectation value) is dropped. Instead, the variance has its own model, comparable to the model for the expectation value.

+

The fit results in an ‘lmvar’ object, which is a list of class ‘lmvar’. Accessor functions are provided to extract the list members such as the fitted betas and the log-likelihood for the model. Various utility functions such as residuals to calculate residuals, AIC to calculate the AIC, fitted to obtain expected values and standard deviations, etc., are also provided by the package.

+

The package lacks much of the sophistication of the ‘lm’ and ‘glm’ packages. On the bright side, this means it is simple to use. It is intended for people who run a classical linear model and want to see what happens if the restriction of a constant variance is dropped. Questions in this context are: does the allowance of heteroscedasticity result in a better fit, lower values for the AIC or BIC, smaller errors from a cross-validation, etc.?

+
+
+

The model

+

The package fits the following model. A vector \(Y\) of observations (sometimes called ‘responses’) of length \(n\) is a stochastic vector. It is distributed according to a multivariate Gaussian distribution:

+\[\begin{equation} +Y \sim \mathcal{N}_n( \mu, \Sigma), +\end{equation}\] +where \(\mu\) is the vector of expectation values and \(\Sigma\) the covariance matrix (also called the ‘variance-covariance matrix’). Just like in the standard linear model, the covariance is taken to be a \(n \times n\) diagonal matrix but contrary to the standard linear model, the diagonal entries need not be all the same: +\[\begin{equation} +\Sigma_{ij} = +\begin{cases} +0 & i \neq j\\ +\sigma_i^2 & i=j +\end{cases} +\end{equation}\] +
+

Model for the expectation values

+As in the classical linear model, the vector of expectation values \(\mu\) is given by +\[\begin{equation} +\mu = X_\mu \beta_\mu +\end{equation}\] +

where \(X_\mu\) is the ‘model matrix’ or ‘design matrix’ for \(\mu\) and \(\beta_\mu\) the parameter vector for \(\mu\). \(X_\mu\) is a \(n \times k_\mu\) matrix and \(\beta_\mu\) a vector of length \(k_\mu\).

+
+
+

Model for the variances

+Let \(\sigma\) denotes the vector \((\sigma_1, \dots, \sigma_n)\). The model for \(\sigma\) is +\[\begin{equation} +\log \sigma = X_\sigma \beta_\sigma +\end{equation}\] +

where \(\log \sigma\) stands for the vector \((\log\sigma_1, \dots, \log\sigma_n)\), \(X_\sigma\) is the ‘model matrix’ or ‘design matrix’ for \(\sigma\) and \(\beta_\sigma\) the parameter vector for \(\sigma\). The logarithm is taken to be the ‘natural logarithm’ with base \(e\). The dimensions of \(X_\sigma\) are \(n \times k_\sigma\) and \(\beta_\sigma\) is a vector of length \(k_\sigma\).

+
+
+

Also know that…

+

The vector of observations \(Y\) and the matrices \(X_\mu\) and \(X_\sigma\) are specified by the user. They must contain real values. The fit returns the maximum-likelihood estimators for \(\beta_\mu\) and \(\beta_\sigma\). They are also real-valued vectors.

+

The model for both \(\mu\) and \(\sigma\) contains an intercept term. That means that the first column of both matrices is a column in which each matrix-element equals 1. The package will add this column to the user-suppplied matrices to ensure that the intercept term is always present. There is no need for a user to include such a column in a user-supplied model-matrix.

+

After adding the intercept column, the package will check whether the resulting matrices are full rank. If not, columns will be removed from each matrix until it is full rank.

+

The addition of an intercept column and, possibly, the removal of columns to obtain a full-rank matrix, imply that the actual matrices used in the fit can be different from the user-specified matrices. The matrices that are actually used in the fit are returned as members of the lmvar object.

+

Carrying out the fit boils down to solving a set of non-linear equations. This is carried out by the function nleqslv from the package with the same name.

+

More mathematical details about the model can be found in the vignette ‘Math’ which comes with this package. It can be viewed with vignette("Math") or vignette("Math", package="lmvar").

+
+
+
+

Using the package

+

The main function in the package is lmvar. It carries out a fit and returns an lmvar object.

+

The user must specify a vector of observations and two model-matrices when calling lmvar. They must meet the following conditions:

+
    +
  • All observations and matrix elements must be real-valued.
  • +
  • Missing values, values that are NaN etc., are not allowed.
  • +
  • A matrix either has column names for all columns or no column names at all. The same column name can appear for both \(X_\mu\) and \(X_\sigma\) but column names should be unique within each matrix. The intercept column that is added automatically by lmvar is called (Intercept) for \(X_\mu\) and (Intercept_s) for \(X_\sigma\). In case no column-names are specified, the second, third, etc. columns are called v1, v2 etc. for \(X_\mu\) and v1_s, v2_s etc. for \(X_\sigma\).
  • +
  • When the user-supplied matrix \(X_\mu\) has column names, none of those should be (Intercept). This is a reserved name, as we explained above. Likewise, a user-supplied matrix \(X_\sigma\) must not have a column named (Intercept_s).
  • +
+

With each column in \(X_\mu\) corresponds an element in \(\beta_\mu\). The name of that element is the corresponding column name. The same is true for \(X_\sigma\) and \(\beta_\sigma\).

+

It can happen that nleqslv fails to solve the maximum-likelihood equations. Sometimes the problem can be traced back to columns in \(X_\sigma\) with many zero’s. I.e., covariates (or factor-levels) for \(\sigma\) which affect only few observations. Removal of these columns may remedy the issue.

+

An lmvar object is a list whose members are intended to be extracted with the supplied accessor and utility functions. The only members for which no such functions have been implemented are:

+
    +
  • y: the user-supplied vector of observations
  • +
  • X_mu: the actual, full-rank matrix \(X_\mu\) including the intercept term that is used in the fit
  • +
  • X_sigma: the actual, full-rank matrix \(X_\sigma\) including the intercept term that is used in the fit
  • +
+

Once lmvar has run and an lmvar-object created, one can obtain \(\beta_\mu\) and \(\beta_\sigma\) with the function coef. The function fitted allows one to obtain \(\mu\) and \(\sigma\). We refer to the package documentation (in particular the package index which can be viewed with help(package = "lmvar")) for a list of all available functions and function details.

+
+
+

Demonstration

+

We demonstrate the package with the help of the dataframe attenu which can be found in the datasets package.

+
library(lmvar)
+
+# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains
+# the response variable 'accel' and two explanatory variables 'mag'  and 'dist'.
+library(datasets)
+
+# Create the model matrix for the expected values
+X = cbind(attenu$mag, attenu$dist)
+colnames(X) = c("mag", "dist")
+
+# Create the model matrix for the standard deviations.
+X_s = cbind(attenu$mag, 1 / attenu$dist)
+colnames(X_s) = c("mag", "dist_inv")
+
+# Carry out the fit
+fit = lmvar(attenu$accel, X, X_s)
+

We have now created the object fit which is our object of class lmvar. To obtain a first impression of the fit, we look at the summary

+
summary(fit)
+
## Call: 
+##  lmvar(y = attenu$accel, X_mu = X, X_sigma = X_s)
+## 
+## Standardized residuals: 
+##     Min      1Q  Median      3Q     Max 
+## -1.4679 -0.6615 -0.1132  0.5736  2.9969 
+## 
+## Coefficients:
+##                  Estimate  Std. Error z value  Pr(>|z|)    
+## (Intercept)   -0.14518878  0.06367414 -2.2802    0.0226 *  
+## mag            0.05436925  0.01137133  4.7813 1.742e-06 ***
+## dist          -0.00129047  0.00014701 -8.7779 < 2.2e-16 ***
+## (Intercept_s) -4.33049620  0.44747494 -9.6776 < 2.2e-16 ***
+## mag_s          0.28918112  0.07286834  3.9685 7.231e-05 ***
+## dist_inv_s     3.14861277  0.23985317 13.1273 < 2.2e-16 ***
+## ---
+## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+## 
+## Standard deviations: 
+##     Min      1Q  Median      3Q     Max 
+##  0.0634  0.0775  0.0920  0.1095 46.8245 
+## 
+## Comparison to model with constant variance (i.e. classical linear model)
+## Log likelihood-ratio: 31.38197 
+## Additional degrees of freedom: 2 
+## p-value for difference in deviance: 2.35e-14
+

The first line shows the call that created fit. Next, we are told something about the distribution of the standardized residuals. Ideally, the first quarter (1Q) must be approximately -0.67, the median 0 and the third quarter (3Q) 0.67.

+

Next, the summary shows the matrix with the coefficients \(\beta_\mu\) and \(\beta_\sigma\). The coefficients \(\beta_\mu\) are (Intercept), mag and dist. The coefficients \(\beta_\sigma\) are (Intercept_s), mag_s and dist_inv_s. They are called this way to distinguish them from the coefficients for \(\beta_\mu\). In cases where there is no risk of confusion, their true names will be used, which are (Intercept_s), mag and dist_inv.

+

The matrix with coefficients shows that all coefficients are statistically significant at the 5% level.

+

The next piece of information gives an impression of the distribution of the standard deviations. They range from 0.0631 to 42.0983.

+

Finally the model is compared to a classical linear model with the same model matrix \(X_\mu\) but a fixed standard deviation. The summary shows the difference in log-likelihood between the two models and the difference in degrees of freedom. Twice the difference in log-likelihood is the difference in deviance, for which a p-value is calculated. The fact that the p-value in the summary is nearly zero, indicates that the lmvar fit is a better fit than the classical linear model. I.e., it makes sense to let the variance vary instead of keeping it fixed.

+

Let’s see how the standard deviations are distributed

+
sigma = fitted(fit, mu = FALSE)
+hist(sigma)
+

+

To check the distribution of the residuals, we make another histogram.

+
hist(residuals(fit))
+

+

The rank of the matrix \(X_\mu\) used in the fit is

+
dfree(fit, sigma = FALSE)
+
## [1] 3
+

The value 3 is correct: the user-supplied matrix had 2 columns and lmvar added an intercept column. Apparently all columns are linearly independent so no column had to be removed.

+

To see the number of observations in the fit, the log-likelihood and the AIC value, we run

+
nobs(fit)
+
## [1] 182
+
logLik(fit)
+
## 'log Lik.' 154.7313 (df=6)
+
AIC(fit)
+
## [1] -297.4625
+

The coefficients \(\beta_\mu\) and \(\beta_\sigma\) that were displayed in the summary-overview are obtained by

+
coef(fit)
+
##   (Intercept)           mag          dist (Intercept_s)         mag_s 
+##  -0.145188779   0.054369245  -0.001290472  -4.330496198   0.289181123 
+##    dist_inv_s 
+##   3.148612765
+

If we only ask for \(\beta_\sigma\),we see their real names

+
coef(fit, mu = FALSE)
+
## (Intercept_s)           mag      dist_inv 
+##    -4.3304962     0.2891811     3.1486128
+

We conclude this demonstration with the covariance matrix for the coefficients \(\beta_\mu\)

+
vcov(fit, sigma = FALSE)
+
##               (Intercept)           mag          dist
+## (Intercept)  4.054396e-03 -7.174215e-04  4.262834e-06
+## mag         -7.174215e-04  1.293072e-04 -8.916107e-07
+## dist         4.262834e-06 -8.916107e-07  2.161296e-08
+

Hopefully this demonstration has given an idea of how to work with the package. The documentation of the individual fuctions contains further examples.

+
+
+

Functions in the package

+

We refer to the package index for a list of all available functions. The index can be viewed with help(package="lmvar").

+
+
+

Other packages

+

The function remlscore in the package statmod fits precisely the same model as lmvar. However, statmod does not provide any utility function, which we believe are important to foster the acceptance of this model as a step beyond classical linear regression.

+

Other functions that allow for a model of the dispersion are, e.g., hglm in the package hglm and geese in the package geepack. These models are more complicated though, and require a level of expertise not required by lmvar.

+
+
+

Acknowledgements

+

We thank prof. dr. Eric Cator for his valuable comments and suggestions.

+ +
+ + + + + + + + diff --git a/inst/doc/Math.ltx b/inst/doc/Math.ltx new file mode 100644 index 0000000..a32de27 --- /dev/null +++ b/inst/doc/Math.ltx @@ -0,0 +1,328 @@ +%\VignetteIndexEntry{Math details} +%\VignetteEngine{R.rsp::tex} +%\VignetteKeyword{R} +%\VignetteKeyword{package} +%\VignetteKeyword{vignette} +%\VignetteKeyword{LaTeX} +%!TeX spellcheck = en_US +\documentclass{article} +\usepackage{amsmath,amsfonts} +\usepackage{mathtools} + +\newcommand{\vvec}[1]{\vec{\vec{#1}}} +\newcommand{\cov}{\text{cov}} +\newcommand{\Ker}{\text{Ker}} + +\newtheorem{lemma}{Lemma} + +\begin{document} +\section{LMVAR: a linear model with heteroscedasticity} +This vignette describes in more detail the mathematical aspects of the model with which the \texttt{lmvar} package is concerned. A short description can be found in the vignette 'Intro' of this package. + +Assume that a stochastic vector $Y \in \mathbb{R}^n$ has a multivariate normal distribution as +\begin{equation} +Y \sim \mathcal{N}_n(\mu^\star, \Sigma) +\end{equation} +in which $\mu^\star \in \mathbb{R}^n$ is the expected value and $\Sigma \in \mathbb{R}^{n,n}$ a diagonal covariance matrix +\begin{equation} +\Sigma_{ij} = +\begin{cases} +0 & i \neq j \\ +(\sigma_i^\star)^2 & i=j. +\end{cases} +\end{equation} +Assume that the vector of expectation values $\mu$ is linearly dependent on the values of the covariates in a model matrix $X_\mu$: +\begin{equation} +\mu^\star = X_\mu \beta_\mu^\star +\end{equation} +with $X_\mu \in \mathbb{R}^{n,k_\mu}$ and $\beta_\mu^\star \in \mathbb{R}^{k_\mu}$. + +Similarly, assume that the vector $\sigma^\star = (\sigma_1^\star, \dots, \sigma_n^\star)$ depends on the covariates in a model matrix $X_\sigma$ as +\begin{equation} +\log \sigma^\star = X_\sigma \beta_\sigma^\star +\end{equation} +where $\log \sigma^\star = (\log\sigma_1^\star, \dots, \log\sigma_n^\star)$, $X_\sigma \in \mathbb{R}^{n,k_\sigma}$ and $\beta_\sigma^\star \in \mathbb{R}^{k_\sigma}$. The logarithm is taken to be the 'natural logarithm', i.e., with base $e$. + +We assume $n \geq k_\mu + k_\sigma$ to avoid having an overdetermined system when we calculate estimators for $\beta_\mu^\star$ and $\beta_\sigma^\star$, as explained in the next section. + +If we take $X_\sigma$ a $n\times 1$ matrix in which each element is equal to 1, we have the standard linear model. + +The parameter vector $\beta_\mu^\star$ is defined uniquely only if $X_\mu$ is full-rank. If not, the space $\mathbb{R}^{k_\mu}$ can be split into subspaces such that there is a uniquely defined $\beta_\mu^\star$ in each subspace. The way \texttt{lmvar} treats this is as follows. If the user-supplied $X_\mu$ is not full-rank, \texttt{lmvar} removes just enough columns from the matrix to make it full-rank. This amounts to selecting $\beta_\mu^\star$ from the subspace in which all vector elements corresponding to the removed columns, are set to zero. + +In the same way, if the user-supplied $X_\sigma$ is not full-rank, just enough columns are removed to make it so. This defines a subspace in which $\beta_\sigma^\star$ is defined uniquely. + +In what follows we assume that $X_\mu$ and $X_\sigma$ are the matrices after the columns have been removed, i.e., they are full-rank matrices. The vector elements that are set to zero, drop out of $\beta_\mu^\star$ and $\beta_\sigma^\star$ and the dimensions $k_\mu$ and $k_\sigma$ are reduced accordingly. These reduced dimensions are returned by the function \texttt{dfree} in the \texttt{lmvar} package. + +\section{Maximum-likelihood equations} +A vector element $Y_i$ is distributed as +\begin{equation} +Y_i \sim \frac{1}{\sqrt{2\pi}\sigma_i^\star} \exp \left( -\frac{(Y_i - \mu_i^\star)^2}{2 (\sigma_i^\star)^2} \right). +\end{equation} +The logarithm of the likelihood $\mathcal L$ is defined as +\begin{equation} +\log \mathcal{L}(\beta_\mu, \beta_\sigma) = - \frac{n}{2} \log(2\pi) - \sum_{k=1}^n ( \log \sigma_k + \frac{(y_k - \mu_k)^2}{2 \sigma_k^2}). +\end{equation} +for all vectors $\beta_\mu \in \mathbb{R}^{k_\mu}$ and $\beta_\sigma \in \mathbb{R}^{k_\sigma}$ and $\mu$ and $\sigma$ defined as +\begin{equation} +\begin{split} +\mu & = X_\mu \beta_\mu \\ +\log \sigma & = X_\sigma \beta_\sigma. +\end{split} +\end{equation} + +We are looking for $\hat{\beta_\mu} \in \mathbb{R}^{k_\mu}$ and $\hat{\beta_\sigma} \in \mathbb{R}^{k_\sigma}$ that maximize the log-likelihood: +\begin{equation} \label{eq:mle def} +(\hat{\beta}_\mu, \, \hat{\beta}_\sigma) = \underset{(\beta_\mu, \beta_\sigma) \in \mathbb{R}^{k_\mu} \times \mathbb{R}^{k_\sigma}} {\text{argmax}} \log \mathcal{L} (\beta_\mu, \beta_\sigma). +\end{equation} +These maximum likelihood estimators are taken to be the estimators of $\beta_\mu^\star$ and $\beta_\sigma^\star$. +We assume that $\hat{\beta}_{\mu}$ and $\hat{\beta}_\sigma$ thus defined, exist and are unique. + +Given $\hat{\beta}_\sigma$, this is true for $\hat{\beta}_\mu$. Namely, given any $\beta_\sigma$, $\log \mathcal{L}$ is maximized by the $\beta_\mu$ which is the solution of +\begin{equation} \label{eq:mle mu} +\nabla_{\beta_\mu} \log \mathcal{L} = 0 +\end{equation} +where $\nabla_{\beta_\mu}$ stands for the gradient $(\frac{\partial}{\partial \beta_{\mu,1}}, \dots, \frac{\partial}{\partial \beta_{\mu,n}})$. + +The derivatives are +\begin{align} +\frac{\partial \log \mathcal{L}}{\partial \beta_{\mu,i}} & = \sum_{k=1}^n ( \frac{(y_k - \mu_k)}{\sigma_k^2}) (X_\mu)_{ki} \label{eq:dll dbmu}\\ +& = \left( X_\mu^T \Lambda (y -\mu) \right)_i +\end{align} +with $\Lambda$ a diagonal matrix given by +\begin{equation} \label{eq:Lambda def} +\Lambda_{ij} = \frac{1}{\sigma_i^2} \delta_{ij}. +\end{equation} +Hence +\begin{equation} +\nabla_{\beta_\mu} \log \mathcal{L} = X_\mu^T \Lambda (y -\mu) +\end{equation} +and the maximum-likelihood equation \eqref{eq:mle mu} becomes +\begin{equation} +X_\mu^T \Lambda X_\mu \beta_\mu = X_\mu^T \Lambda y +\end{equation} +which has the solution +\begin{equation} +\beta_\mu = \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda y . \label{eq:bmustar} +\end{equation} +Because of our assumption that $X_\mu$ is full rank, the inverse of the matrix $X_\mu^T \Lambda X_\mu$ can be taken. + +It is easy to see that the solution \eqref{eq:bmustar} represents a maximum in the log-likelihood. The matrix $H_{\mu \mu}$ of second-order derivatives +\begin{equation} +\left( H_{\mu \mu} \right)_{ij} = \frac{\partial^2 \log L}{\partial \beta_{\mu i} \partial \beta_{\mu j}} +\end{equation} +is given by +\begin{equation} \label{eq:Hmumu} +H_{\mu \mu} = - X_\mu^T \Lambda X_\mu, +\end{equation} +which is negative-definite for any $\beta_\sigma$. + +Our maximization search can now be carried out in a smaller space: +\begin{equation} \label{eq:mle sigma} +\hat{\beta_\sigma} = \underset{\beta_\sigma \in \mathbb{R}^{k_\sigma}} {\text{argmax}} \; \log \mathcal{L}_P ( \beta_\sigma) +\end{equation} +where $\mathcal{L}_P$ is the so-called profile-likelihood +\begin{equation} +\mathcal{L}_P ( \beta_\sigma) = \mathcal{L} (\beta_\mu (\beta_\sigma), \beta_\sigma). +\end{equation} +with $\beta_\mu$ depending on $\beta_\sigma$ as in \eqref{eq:bmustar}. + +To find $\hat{\beta}_\sigma$ from \eqref{eq:mle sigma}, we must solve +\begin{equation} \label{eq:mle sigma 2} +(\nabla_{\beta_\mu} \log \mathcal{L}) \, (\nabla_{\beta_\sigma} \beta_\mu) + \nabla_{\beta_\sigma} \log \mathcal{L} = 0 +\end{equation} +evaluated at $\beta_\mu = \beta_\mu(\beta_\sigma)$, and $(\nabla_{\beta_\sigma} \beta_\mu)$ the matrix +\begin{equation} +(\nabla_{\beta_\sigma} \beta_\mu)_{ij} = \frac{\partial \beta_{\mu i}}{\partial \beta_{\sigma j}}. +\end{equation} +However, because of \eqref{eq:mle mu}, the first term in \eqref{eq:mle sigma 2} vanishes and we are left to solve +\begin{equation} \label{eq:mle sigma 3} +\nabla_{\beta_\sigma} \log \mathcal{L} = 0. +\end{equation} +The derivatives that are the elements of this gradient are given by +\begin{align} +\frac{\partial \log \mathcal{L}}{\partial \beta_{\sigma i}} & = \sum_{k=1}^n ( - (X_\sigma)_{ki} + \frac{(y_k - \mu_k)^2}{\sigma_k^2} (X_\sigma)_{ki}) \nonumber\\ +& = \sum_{k=1}^n (\frac{(y_k - \mu_k)^2}{\sigma_k^2} -1) (X_\sigma)_{ki}. \label{eq:mle sigma 4} +\end{align} +The entire gradient can be written as a matrix-product as +\begin{equation} \label{eq:mle 2} +\nabla_{\beta_\sigma} \log \mathcal{L} = X_\sigma^T \lambda_\sigma +\end{equation} +with $\lambda_\sigma$ a vector of length $n$ whose elements $\lambda_{\sigma i}$ are +\begin{equation} +\lambda_{\sigma i} = \left( \frac{y_i - \mu_i}{\sigma_i} \right)^2 -1. +\end{equation} +The maximum-likelihood equations \eqref{eq:mle sigma 3} take the form +\begin{equation} +X_\sigma^T \lambda_\sigma = 0. +\end{equation} + +The estimate $\mu$ of the expectation value that appears in $\lambda_\sigma$ depends on $\beta_\sigma$ as +\begin{align} +\mu & = X_\mu \beta_\mu \nonumber\\ +& = X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda y \nonumber\\ +& = \Lambda^{1/2} X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda^{1/2} y +\end{align} +where the latter form is the more symmetric, with +\begin{equation} +\left( \Lambda^{1/2} \right)_{ij} = \frac{1}{\sigma_i} \delta_{ij}. +\end{equation} +The vector $(y - \mu) / \sigma$ can be written as +\begin{equation} +\frac{y-\mu}{\sigma} = \Lambda^{1/2} \left[ I - \Lambda^{1/2} X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda^{1/2} \right] y +\end{equation} +in which $I \in \mathbb{R}^{n,n}$ is the identity matrix. + +\subsection{Profile-likelihood Hessian} +Numerical procedures to solve the maximum-likelihood equations $X_\sigma^T \lambda_\sigma=0$ involve the calculation of the Hessian $H_P$ of the profile log-likelihood. $H_P$ is the matrix of second-order derivatives of $\log \mathcal{L}_P$: +\begin{equation} +\left( H_P \right)_{ij} = \frac{\partial^2 \log \mathcal{L}_P}{\partial \beta_{\sigma j} \partial \beta_{\sigma i}} +\end{equation} +Differentiation of \eqref{eq:mle sigma 4} gives for the second-order derivatives +\begin{equation} \label{eq:hess} +\left( H_P \right)_{ij} = -2 \sum_{k=1}^n (X_\sigma^T)_{ik} \frac{y_k - \mu_k}{\sigma_k^2} \left\lbrace \frac{\partial \mu_k}{\partial \beta_{\sigma j}} + (y_k - \mu_k) (X_\sigma)_{kj} \right\rbrace +\end{equation} +with +$\partial \mu_k / (\partial \beta_{\sigma j})$ the element at row $k$ and column $j$ of the matrix $(\nabla_{\beta_\sigma} \mu)$. Given that $\mu = X_\mu \beta_\mu$ and $\beta_\mu$ is given by \eqref{eq:bmustar}, the {\em j}-th column vector of the matrix is +\begin{align} +\frac{\partial \mu}{\partial \beta_{\sigma j}} & = X_\mu \frac{\partial \beta_\mu}{\partial \beta_{\sigma j}} \nonumber\\ +& = X_\mu \left\lbrace \frac{\partial \left( X_\mu^T \Lambda X_\mu \right)^{-1}}{\partial \beta_{\sigma j}} X_\mu^T \Lambda + \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} \right\rbrace y \nonumber\\ +& = X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} \left\lbrace - X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda + X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} \right\rbrace y \nonumber\\ +& = X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} \left\lbrace - X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda + I \right\rbrace y \nonumber\\ +& = X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} (y - \mu) +\end{align} +The matrix $\partial \Lambda / (\partial \beta_{\sigma j})$ takes the form +\begin{align} +\frac{\partial \Lambda}{\partial \beta_{\sigma j}} & = \sum_{i=1}^n \frac{\partial \Lambda}{\partial \sigma_i} \frac{\partial \sigma_i}{\partial \beta_{\sigma j}}\\ +& = -2 +\begin{pmatrix} +(X_\sigma)_{1j} & & 0 \nonumber\\ +& \ddots & \\ +0 & & (X_\sigma)_{nj} +\end{pmatrix} \Lambda +\end{align} +The {\em j}-th column vector of the matrix is +\begin{equation} +\frac{\partial \mu}{\partial \beta_{\sigma j}} = -2 X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T +\begin{pmatrix} +\frac{y_1 - \mu_1}{\sigma_1^2} \left( X_\sigma \right)_{1j} \\ +\vdots \\ +\frac{y_n - \mu_n}{\sigma_n^2} \left( X_\sigma \right)_{nj} +\end{pmatrix} +\end{equation} +and the element $(\nabla_{\beta_\sigma} \mu)_{kj}$ of the matrix $(\nabla_{\beta_\sigma} \mu)$ is given by +\begin{equation} +\frac{\partial \mu_k}{\partial \beta_{\sigma j}} = -2 \sum_{l=1}^n \left( X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \right)_{kl} \frac{y_l - \mu_l}{\sigma_l^2} \left( X_\sigma \right)_{lj}. +\end{equation} +If we substitute this result in \eqref{eq:hess}, we obtain for the element at row $i$ and column $j$ of the Hessian: +\begin{align} +& \left( H_P \right)_{ij} = \nonumber \\ +& \quad 4 \sum_{k,l=1}^n (X_\sigma^T)_{ik} \frac{y_k - \mu_k}{\sigma_k^2} \left( X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \right)_{kl} \frac{y_l - \mu_l}{\sigma_l^2} \left( X_\sigma \right)_{lj} + \nonumber\\ +& \quad -2 \sum_{k=1}^n (X_\sigma^T)_{ik} \left( \frac{y_k - \mu_k}{\sigma_k} \right)^2 (X_\sigma)_{kj}. +\end{align} +We can write the Hessian as a matrix-product as +\begin{equation} +\begin{split} +H_P = X_\sigma^T \tilde{\Lambda}_1 X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \tilde{\Lambda}_1 X_\sigma + X_\sigma^T \tilde{\Lambda}_2 X_\sigma +\end{split} +\end{equation} +with two $n \times n$ diagonal matrices +\begin{equation} +\begin{split} +\left(\tilde{\Lambda}_1 \right)_{ij} & = 2 \, \frac{y_i - \mu_i}{\sigma_i^2} \, \delta_{ij} \\ +\left( \tilde{\Lambda}_2 \right)_{ij} & = -2 \left( \frac{y_i - \mu_i}{\sigma_i} \right)^2 \, \delta_{ij}. +\end{split} +\end{equation} + +\section{Distributions for estimators} +Asymptotic theory of maximum-likelihood estimators tells that the vector of the combined estimators $(\hat{\beta}_\mu, \hat{\beta}_\sigma)$ as defined in \eqref{eq:mle def}, is distributed approximately as +\begin{equation} +(\hat{\beta}_\mu, \hat{\beta}_\sigma) \sim \mathcal{N}_{k_\mu + k_\sigma} \left((\beta_\mu^\star, \beta_\sigma^\star), \Sigma_{\beta \beta} \right) \qquad \text{for } n \text{ large.} +\end{equation} +This distribution is valid in the limit of a large number of observations $n$. + +The covariance matrix $\Sigma_{\beta \beta}$ is given in terms of the inverse Fisher information matrix $I_n$: +\begin{equation} +\Sigma_{\beta \beta} = \frac{1}{n} I_n^{-1}. +\end{equation} +The Fisher information matrix is given in terms of the expected value of the Hessian: +\begin{equation} +I_n = - \frac{1}{n} E[H]. +\end{equation} +The Hessian $H$ is the Hessian of the full log-likelihood, in contrast to the profile-likelihood Hessian: +\begin{equation} +H = +\begin{pmatrix} +H_{\mu\mu} & H_{\mu\sigma} \\ +H_{\mu\sigma}^T & H_{\sigma\sigma} +\end{pmatrix} +\end{equation} +with the three block-matrices defined as +\begin{equation} +\left( H_{\mu\mu} \right)_{ij} = \frac{\partial^2 \log L}{\partial \beta_{\mu i} \partial \beta_{\mu j}}, \; \left( H_{\mu\sigma} \right)_{ij} = \frac{\partial^2 \log L}{\partial \beta_{\mu i} \partial \beta_{\sigma j}}, \; \left( H_{\sigma\sigma} \right)_{ij} = \frac{\partial^2 \log L}{\partial \beta_{\sigma i} \partial \beta_{\sigma j}}. +\end{equation} +We have already calculated $H_{\mu\mu}$ in \eqref{eq:Hmumu}. Differentiation of \eqref{eq:dll dbmu} and \eqref{eq:mle sigma 4} respectively gives +\begin{align*} +\left( H_{\mu\sigma} \right)_{ij} & = -2 \sum_{k=1}^n \frac{y_k - \mu_k}{\sigma_k^2} \left( X_\mu \right)_{ki} \left( X_\sigma \right)_{kj} \\ +\left( H_{\sigma\sigma} \right)_{ij} & = -2 \sum_{k=1}^n \left( \frac{y_k - \mu_k}{\sigma_k} \right)^2 \left( X_\sigma \right)_{ki} \left( X_\sigma \right)_{kj}. +\end{align*} +In matrix notation: +\begin{equation} +H_{\mu\sigma} = X_\mu^T \Lambda_1 X_\sigma, \qquad H_{\sigma\sigma} = X_\sigma^T \Lambda_2 X_\sigma, +\end{equation} +with the diagonal matrices +\begin{equation} +\left( \Lambda_1 \right)_{ij} = -2 \, \frac{y_i - \mu_i}{\sigma_i^2} \, \delta_{ij}, \qquad \left( \Lambda_2 \right)_{ij} = -2 \left( \frac{y_i - \mu_i}{\sigma_i} \right)^2 \delta_{ij}. +\end{equation} +When we take expected values, we have to take $\beta_\mu = \beta_\mu^\star$ and $\beta_\sigma = \beta_\sigma^\star$. Keeping in mind that +\begin{align*} +E[Y - \mu^\star] & = 0 \\ +E[(Y_i-\mu_i^\star)(Y_j - \mu_j^\star)] & = {\sigma_i^\star}^2 \delta_{ij}, +\end{align*} +we have +\begin{equation} +E[H_{\mu\mu}] = - X_\mu^T \Lambda^\star X_\mu, \; E[H_{\mu\sigma}] = 0, \; E[H_{\sigma\sigma}] = -2 X_\sigma^T X_\sigma +\end{equation} +where $\Lambda^\star$ is $\Lambda$ with $\sigma$ taken to be $\sigma^\star$. This brings the expected value of the Hessian in the form +\begin{equation} \label{eq:exp H} +E[H] = - +\begin{pmatrix} +X_\mu^T \Lambda^\star X_\mu & 0 \\ +0 & 2 X_\sigma^T X_\sigma +\end{pmatrix}. +\end{equation} +The function \texttt{fisher} in the \texttt{lmvar} package calculates the Fisher information matrix. It estimates $E[H]$ by replacing the true but unknown $\sigma^\star$ by its maximum-likelihood estimator $\hat{\sigma}$ in $\Lambda^\star$. + +The expectation value \eqref{eq:exp H} brings the covariance matrix $\Sigma_{\beta\beta}$ in the form +\begin{equation} +\Sigma_{\beta\beta} = +\begin{pmatrix} +\left( X_\mu^T \Lambda^\star X_\mu \right)^{-1} & 0 \\ +0 & \frac{1}{2} \left( X_\sigma^T X_\sigma \right)^{-1} +\end{pmatrix}. +\end{equation} +This implies +\begin{equation} +\begin{aligned} +\hat{\beta}_\mu & \sim \mathcal{N}_{k_\mu}( \beta_\mu^\star, \, \left( X_\mu^T \Lambda^\star X_\mu \right)^{-1}) \\ +\hat{\beta}_\sigma & \sim \mathcal{N}_{k_\sigma}( \beta_\sigma^\star, \,\tfrac{1}{2} \left( X_\sigma^T X_\sigma \right)^{-1}) +\end{aligned} \qquad \text{ for } n \text{ large.} +\end{equation} +We obtain for the asymptotic distribution of the maximum-likelihood estimators of $\mu^\star$ and $\sigma^\star$ +\begin{equation} +\begin{aligned} +\hat{\mu} & \sim \mathcal{N}_n (\mu^\star, \, X_\mu \left( X_\mu^T \Lambda^\star X_\mu \right)^{-1} X_\mu^T) \\ +\log \hat{\sigma} & \sim \mathcal{N}_n (\log \sigma^\star, \, \tfrac{1}{2} X_\sigma \left( X_\sigma^T X_\sigma \right)^{-1} X_\sigma^T) +\end{aligned} +\qquad \text{ for } n \text{ large.} +\end{equation} +The expectation value and the variance for an element $\hat{\sigma}_i$ of $\hat{\sigma}$ are +\begin{equation} +\begin{aligned} +E[\hat{\sigma}_i] & = \sigma_i^\star \exp\left( \frac{(X_\sigma \left( X_\sigma^T X_\sigma \right)^{-1} X_\sigma^T)_{ii}}{4} \right) \\ +\text{var}(\hat{\sigma}_i) & = \left( E[\hat{\sigma}_i] \right)^2 \left(\exp (\frac{(X_\sigma \left( X_\sigma^T X_\sigma \right)^{-1} X_\sigma^T)_{ii}}{2}) - 1 \right) +\end{aligned} +\qquad \text{ for } n \text{ large}. +\end{equation} +The function \texttt{fitted.lmvar} (with the option \texttt{log = FALSE}) returns $\hat{\mu}$ and $\hat{\sigma}$. + +\end{document} diff --git a/inst/doc/Math.pdf b/inst/doc/Math.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bad4ff4581ef2089e8ac6cd3c55b61d4a3b751fc GIT binary patch literal 165927 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

=+^gC@^9)+!7qHp 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 p-value of the t-statistic, calculated from the normal distribution. +} +\item \code{residuals} A numeric vector with the minimum, the 25\% quartile, the median, the 75\% quartile and the maximum +standardized residual. The standardized residual of an observation is defined as \eqn{(y - \mu) / \sigma} where \eqn{y} is the value +of the observation, \eqn{\mu} the expectation value and \eqn{\sigma} +the standard deviation of the observation. +\item \code{sigma} A numeric vector with the minimum, the 25\% quartile, the median, the 75\% quartile and the maximum +standard deviation \eqn{\sigma} of all observations. +\item \code{aliased_mu} A named logical vector. The names are the column names of the user-supplied model matrix +\eqn{X_\mu}. The values (\code{TRUE} or \code{FALSE}) tell whether or not the column +has removed by \code{lmvar} to make the matrix full-rank. +\item \code{aliased_sigma} As \code{aliased_mu} but for the user-supplied model matrix \eqn{X_\sigma}. +\item \code{logLik_ratio} The difference in log-likelihood between the model in \code{object} and a classical linear +model with model matrix \eqn{X_\mu} and a constant variance for all observations. +\item \code{df} The difference in degrees in freedom between the model in \code{object} and a classical linear +model with model matrix \eqn{X_\mu} and a constant variance for all observations. +\item \code{p_value} The p-value of \code{2 loglik_ratio}, calculated from a chi-squared distribution with \code{df} +degrees of freedom. +} +} +\description{ +Summary overview for an object of class 'lmvar'. +} +\details{ +Standard errors and t-statistics are calculated from the estimated covariance matrix and may not +be reliable when the number of observations in \code{object} is small. +} +\examples{ +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) + +# Print a summary of the fit +summary(fit) + +# Extract the matrix of coefficients from the summary +coef(summary(fit)) +} +\seealso{ +\code{\link[stats]{coef}} to extract the matrix with estimates, standard-errors, t-statistics and +p-values for \eqn{\beta_\mu} and \eqn{\beta_\sigma} from a 'summary_lmvar' object. + +\code{\link{vcov.lmvar}} for the covariance matrix of the \eqn{\beta_\mu} and \eqn{\beta_\sigma} in an object of class +'lmvar'. + +\code{\link{print.summary_lmvar}} for a print method for a 'summary_lmvar' object. + +\code{\link{fitted.lmvar}} for the expected values and standard deviations +of the observations in an object of class 'lmvar'. + +\code{\link{logLik.lmvar}} for the log-likelihood of a fit in an object of class 'lmvar'. + +\code{\link{alias.lmvar}} to obtain the aliased columns of the user-supplied model matrices in the call of \code{\link{lmvar}}. +} diff --git a/man/vcov.lmvar.Rd b/man/vcov.lmvar.Rd new file mode 100644 index 0000000..97b23e8 --- /dev/null +++ b/man/vcov.lmvar.Rd @@ -0,0 +1,47 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/vcov.lmvar.R +\name{vcov.lmvar} +\alias{vcov.lmvar} +\title{Variance-covarience matrix of the coefficients beta for an object of class 'lmvar'} +\usage{ +\method{vcov}{lmvar}(object, mu = TRUE, sigma = TRUE, ...) +} +\arguments{ +\item{object}{Object of class 'lmvar'} + +\item{mu}{Specifies whether or not the covariance matrix for \eqn{\beta_\mu} is included in the returned matrix} + +\item{sigma}{Specifies whether or not the covariance matrix for \eqn{\beta_\sigma} is included in the returned matrix} + +\item{...}{For compatibility with \code{\link[stats]{vcov}} generic} +} +\value{ +A 'matrix' object containing the (approximate) variance-covariance matrix of the maximum-likelihood estimators +of \eqn{\beta_\mu} and \eqn{\beta_\sigma} in \code{object}. +} +\description{ +Variance-covarience matrix (also simply called the 'covariance matrix') for the +maximum-likelihood estimators of \eqn{\beta_\mu} and \eqn{\beta_\sigma}. +The matrix is calculated using an expression which is only valid in the limit of a large number of +observations. +} +\details{ +The variance-covariance matrix is calculated as \eqn{I^{-1} / n} where \eqn{I} is the Fisher +information matrix and \eqn{n} the number of observations. + +When \code{mu = TRUE} and \code{sigma = TRUE}, the full covariance matrix for the combined vector +\eqn{(\beta_\mu, \beta_\sigma)} is returned. + +When \code{mu = TRUE} and \code{sigma = FALSE}, only the covariance matrix for \eqn{\beta_\mu} is returned. + +When \code{mu = FALSE} and \code{sigma = TRUE}, only the covariance matrix for \eqn{\beta_\sigma} is returned. +} +\seealso{ +\code{\link{summary.lmvar}} for standard errors for \eqn{\beta_\mu} and \eqn{\beta_\mu}. + +\code{\link{nobs.lmvar}} for the number of observations in an object of class 'lmvar'. + +\code{\link{fisher}} for the Fisher information matrix of an object of class 'lmvar'. + +See the vignette "Math" (to be viewed with \code{vignette("Math", "lmvar")}) for details. +} diff --git a/tests/create_test_data.R b/tests/create_test_data.R new file mode 100644 index 0000000..34ef654 --- /dev/null +++ b/tests/create_test_data.R @@ -0,0 +1,55 @@ +library(lmvar) + +# Set RNG seed +set.seed(345981) + +# Set number of observations +n_obs = 5000 + +# Set betas +beta = c(-2,1,3,-1.5) +beta_sigma = c(-1.1,0.8,-0.5) + +# Generate design matrices +intercept = rep.int( 1, n_obs) +l = length(beta) - 1 +X = matrix( sample(-9:9, n_obs*l, replace = TRUE), nrow = n_obs, ncol = l) +X = as.matrix(cbind( intercept, X)) + +l = length(beta_sigma) - 1 +X_sigma = matrix( sample(-1:1, n_obs*l, replace = TRUE), nrow = n_obs, ncol = l) +X_sigma = as.matrix(cbind( intercept, X_sigma)) + +rm( intercept, l) + +X_col_names = sapply( 1:ncol(X), function(x){paste( "v", as.character(x), sep="")}) +X_sigma_col_names = sapply( 1:ncol(X_sigma), function(x){paste( "v", as.character(x), sep="")}) + +colnames(X) = X_col_names +colnames(X_sigma) = X_sigma_col_names + +# Generate response vector +mu = X %*% beta +sigma = exp( X_sigma %*% beta_sigma) +y = rnorm( n_obs, mu, sigma) +y_log = rlnorm( n_obs, meanlog = 0.1*mu, sdlog = sigma^0.1) + +rm( mu, sigma, beta, beta_sigma) + +# Remove intercept terms +X_col_names = X_col_names[-1] +X_sigma_col_names = X_sigma_col_names[-1] + +X = as.matrix( X[,-1]) +X_sigma = as.matrix( X_sigma[,-1]) + +colnames(X) = X_col_names +colnames(X_sigma) = X_sigma_col_names + +rm( X_col_names, X_sigma_col_names) + +# Fit model +fit = suppressWarnings(lmvar( y, X, X_sigma)) +fit_log = suppressWarnings(lmvar( log(y_log), X, X_sigma)) + +rm( X, y, y_log, X_sigma , n_obs) diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..c3c1b21 --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,6 @@ +library(testthat) +library(lmvar) + +source("create_test_data.R") + +test_check("lmvar") diff --git a/tests/testthat/test_extractors.R b/tests/testthat/test_extractors.R new file mode 100644 index 0000000..309d081 --- /dev/null +++ b/tests/testthat/test_extractors.R @@ -0,0 +1,26 @@ +context("lmvar extractors") + +test_that("logLik works correctly", { + n = nobs(fit) + mu = fitted( fit, sigma=FALSE) + sigma = as.numeric(exp(fit$X_sigma %*% coef(fit, mu=FALSE))) + res = (fit$y - mu) / sigma + logL = -0.5 * n * log(2 * pi) - sum(log(sigma)) - 0.5 * sum(res * res) + + expect_equal( logLik(fit)[1], logL) + expect_identical( names(attributes(logLik(fit))), c( "df", "class")) + expect_equal( attr(logLik(fit), "df"), 7) +}) + +test_that("coef works correctly", { + expect_equivalent( coef(fit), c( fit$coefficients_mu, fit$coefficients_sigma)) + expect_identical( coef( fit, mu = FALSE), fit$coefficients_sigma) + expect_identical( coef( fit, sigma = FALSE), fit$coefficients_mu) + expect_equivalent( coef( fit, mu = FALSE, sigma = FALSE), numeric()) +}) + +test_that("dfree works correctly", { + expect_identical( dfree(fit), ncol(fit$X_mu) + ncol(fit$X_sigma)) + expect_identical( dfree( fit, sigma = FALSE), ncol(fit$X_mu)) + expect_identical( dfree( fit, mu = FALSE), ncol(fit$X_sigma)) +}) diff --git a/tests/testthat/test_lmvar.R b/tests/testthat/test_lmvar.R new file mode 100644 index 0000000..be2bc22 --- /dev/null +++ b/tests/testthat/test_lmvar.R @@ -0,0 +1,74 @@ +context("lmvar constructor") + +test_that("missing arguments are handled correctly", { + + y = fit$y + fittest = suppressWarnings(lmvar(y)) + fitlm = lm( y~1, as.data.frame(fit$X_mu)) + expect_equal( coef(fittest)[1], coef(fitlm)) + expect_lt( abs(as.numeric(exp(coef(fittest)[2])) - summary(fitlm)$sigma), 0.002) + +}) + +test_that("no errors occur when working with class Matrix",{ + + M_mu = Matrix::Matrix(fit$X_mu) + M_mu = M_mu[, -1] + M_sigma = Matrix::Matrix(fit$X_sigma) + M_sigma = M_sigma[, -1] + fittest = suppressWarnings(lmvar( fit$y, M_mu, M_sigma)) + expect_equal( coef(fittest), coef(fit)) + + expect_error( summary(fittest), NA) + +}) + +test_that("results compare with standard linear regression",{ + + y = fit$y + M_mu = fit$X_mu + M_mu = M_mu[, 2:ncol(M_mu)] + + fitlm = lm( y~., as.data.frame(as.matrix(M_mu))) + fitlmvar = lmvar( y, M_mu) + + # compare betas and standard errors + coeflm = coef(summary(fitlm)) + coeflmvar = as.matrix(coef(summary(fitlmvar))) + coeflmvar = coeflmvar[ rownames(coeflm),] + + expect_equal( coeflm[,1], coeflmvar[,1]) + expect_equal( signif( coeflm[,2], 2), signif( coeflmvar[,2], 2)) + + # Compare sigmas + sigmalmvar = predict( fitlmvar, mu = FALSE)[1] + variance = vcov( fitlmvar, mu = FALSE)[1,1] + sdev = sigmalmvar * sqrt(exp(variance) - 1) + sigmalm = summary(fitlm)$sigma + expect_lt( sigmalmvar - sdev, sigmalm) + expect_gt( sigmalmvar + sdev, sigmalm) +}) + +test_that("betas are as expected", { + + coeff = coef(summary(fit)) + + beta = c( -2, 1, 3, -1.5, -1.1, 0.8, -0.5) + + v = sapply( 1:nrow(coeff), function(i){ + + beta_f = coeff[i,1] + sterr_f = coeff[i,2] + expect_lt( beta_f - 1.5 * sterr_f, beta[i]) + expect_gt( beta_f + 1.5 * sterr_f, beta[i]) + }) +}) + +test_that("no errors occur when matrix becomes vector", { + + M_mu = fit$X_mu[,2] + M_sigma = fit$X_sigma[,2] + + expect_error( suppressWarnings(lmvar( fit$y, M_mu, M_sigma)), NA) + +}) diff --git a/tests/testthat/test_predict.R b/tests/testthat/test_predict.R new file mode 100644 index 0000000..3db3da6 --- /dev/null +++ b/tests/testthat/test_predict.R @@ -0,0 +1,336 @@ +context("lmvar predict") + +test_that("predict works correctly", { + + # Construct prediction matrices + n = 10 + v1 = rep.int( 1, n) + v2 = rep.int( -1, n) + v3 = rep.int( 0, n) + c1 = c( v1, v1, v3) + c2 = c( v3, v2, v2) + c3 = c( v3, v1, v1) + M = as.matrix( cbind( c1, c2, c3)) + M_sigma = as.matrix( cbind( c1, c2)) + beta = coef( fit, sigma = FALSE) + beta_sigma = coef( fit, mu = FALSE) + colnames(M) = names(beta)[2:4] + colnames(M_sigma) = names(beta_sigma)[2:3] + + # Calculate predictions + intercept = rep.int( 1, 3*n) + predict_mu = as.numeric(cbind( intercept, M) %*% beta) + predict_sigma = as.numeric(exp( cbind( intercept, M_sigma) %*% beta_sigma)) + + # Construct predicted result + resultM = matrix( c(predict_mu, predict_sigma), ncol = 2) + colnames(resultM) = c( "mu", "sigma") + + # Basic prediction + expect_equal( predict( fit, M, M_sigma), resultM) +}) + +test_that("predict with more/less/re-ordered columns works correctly",{ + + M = fit$X_mu + M_sigma = fit$X_sigma + + beta = coef( fit, sigma = FALSE) + beta_sigma = coef( fit, mu = FALSE) + + predict_y_from_model = as.numeric(M %*% beta) + predict_sigma_from_model = as.numeric(exp( M_sigma %*% beta_sigma)) + + expected = matrix( c( predict_y_from_model, predict_sigma_from_model), ncol = 2) + colnames(expected) = c( "mu", "sigma") + + expect_equal( predict(fit), expected) + + # Re-order columns (and leave out intercept term) + M_m = M[, c(4,3,2)] + M_sigma_m = M_sigma[,c(3,2)] + expect_equal( predict( fit, M_m, M_sigma_m), predict(fit)) + + # Leave out a column + M_m = M[,1:3] + M_sigma_m = as.matrix(M_sigma[,1:2]) + + beta_m = beta[colnames(M_m)] + beta_sigma_m = beta_sigma[colnames(M_sigma_m)] + + predict_y = as.numeric(M_m %*% beta_m) + predict_sigma = as.numeric(exp( M_sigma_m %*% beta_sigma_m)) + + M_m = M_m[,2:3] + M_sigma_m = as.matrix(M_sigma_m[,2]) + colnames(M_sigma_m) = names(beta_sigma_m)[2] + + expect_warning( predict(fit, M_m, M_sigma[,-1])) + expect_warning( predict(fit, M[,-1], M_sigma_m)) + expect_warning( predict(fit, M_m, M_sigma_m)) + + expected = matrix( c( predict_y, predict_sigma), ncol = 2) + colnames(expected) = c( "mu", "sigma") + + expect_equal( suppressWarnings(predict( fit, M_m, M_sigma_m)), expected) + + # Add non-existing covariates + M_m = cbind( M, M[,2]) + M_sigma_m = cbind( M_sigma, M_sigma[,2]) + colnames(M_m)[ncol(M_m)] = "non-existing" + colnames(M_sigma_m)[ncol(M_sigma_m)] = "non-existing" + + # Remove intercept terms + M_m = M_m[, -1] + M_sigma_m = M_sigma_m[, -1] + + expect_equal( predict( fit, M_m, M_sigma_m), predict(fit)) + +}) + +test_that("predict with missing matrices works correctly", { + + # Predictions for model in fit + M = fit$X_mu + M_sigma = fit$X_sigma + + beta = coef( fit, sigma = FALSE) + beta_sigma = coef( fit, mu = FALSE) + + predict_y_from_model = as.numeric(M %*% beta) + predict_sigma_from_model = as.numeric(exp( M_sigma %*% beta_sigma)) + + expect_equal( predict( fit, sigma = FALSE), predict_y_from_model) + + expected = matrix( c( predict_y_from_model, predict_sigma_from_model), ncol = 2) + colnames(expected) = c( "mu", "sigma") + + expect_identical( predict(fit), expected) + + # Model matrices for new model + nobs = nobs(fit) + n1 = trunc(nobs / 3) + n2 = n1 + n3 = nobs - n1 - n2 + v1 = rep.int( 1, n1) + v2 = rep.int( -1, n2) + v3 = rep.int( 0, n3) + c1 = c( v1, v1, v3) + c2 = c( v3, v2, v2) + c3 = c( v3, v1, v1) + M_m = as.matrix( cbind( c1, c2, c3)) + M_sigma_m = as.matrix( cbind( c1, c2)) + colnames(M_m) = names(beta)[2:4] + colnames(M_sigma_m) = names(beta_sigma)[2:3] + + # Predictions for new model + intercept = rep.int( 1, nobs) + predict_y = as.numeric(cbind( intercept, M_m) %*% beta) + predict_sigma = as.numeric(exp(cbind( intercept, M_sigma_m) %*% beta_sigma)) + + # mu for fit and sigma for new model + expected = matrix( c( predict_y_from_model, predict_sigma), ncol = 2) + colnames(expected) = c( "mu", "sigma") + + expect_equal( predict( fit, X_sigma = M_sigma_m), expected) + + # mu for new model and sigma for fit + expected = matrix( c( predict_y, predict_sigma_from_model), ncol = 2) + colnames(expected) = c( "mu", "sigma") + + expect_equal( predict( fit, M_m), expected) + + # mu and sigma for new model + expected = matrix( c( predict_y, predict_sigma), ncol = 2) + colnames(expected) = c( "mu", "sigma") + + expect_equal( predict( fit, M_m, M_sigma_m), expected) +}) + +test_that("predict with different output formats works correctly", { + + # Predictions from model + M = fit$X_mu + M_sigma = fit$X_sigma + + beta = coef( fit, sigma = FALSE) + beta_sigma = coef( fit, mu = FALSE) + + # cov_sigma = vcov( fit, mu = FALSE) + # cov_sigma = M_sigma %*% cov_sigma %*% Matrix::t(M_sigma) + # variances = diag(cov_sigma) + + predict_y_from_model = as.numeric(M %*% beta) + predict_sigma_from_model = as.numeric(exp( M_sigma %*% beta_sigma)) + + # Different output formats + expect_identical( predict( fit, sigma=FALSE), predict_y_from_model) + expect_identical( predict( fit, mu=FALSE), predict_sigma_from_model) + + M_out = matrix( c( predict_y_from_model, predict_sigma_from_model), ncol = 2) + colnames(M_out) = c( "mu", "sigma") + expect_identical( predict( fit, matrix=TRUE), M_out) + +}) + +test_that("predict catches difference in number of rows", { + + nobs = nobs(fit) + M = fit$X_mu + M_sigma = fit$X_sigma + + M_e = M[ 1:(nobs-1),] + M_sigma_e = M_sigma[ 1:(nobs-1),] + + expect_error( predict(fit, M_e)) + expect_error( predict(fit, X_sigma = M_sigma_e)) + expect_error( predict(fit, M, M_sigma_e)) + +}) + +test_that("predict works with matrices having only intercept", { + + y = fit$y + M_mu = fit$X_mu + M_sigma = fit$X_sigma + + # Model matrix for sigma has intercept term only + fitlmvar = lmvar( y, M_mu[,-1]) + + X_sigma = fitlmvar$X_sigma + + predict_y = as.numeric(M_mu %*% coef( fitlmvar, sigma = FALSE)) + predict_sigma = as.numeric(exp( X_sigma %*% coef( fitlmvar, mu = FALSE))) + + expected = matrix( c( predict_y, predict_sigma), ncol = 2) + colnames(expected) = c( "mu", "sigma") + + expect_equal( predict(fitlmvar), expected) + expect_equal( predict( fitlmvar, M_mu[,-1]), expected) + + # Model matrix for mu has intercept term only + fitlmvar = suppressWarnings(lmvar( y, X_sigma = M_sigma[,-1])) + + X_mu = fitlmvar$X_mu + + predict_y = as.numeric(X_mu %*% coef( fitlmvar, sigma = FALSE)) + predict_sigma = as.numeric(exp( M_sigma %*% coef( fitlmvar, mu = FALSE))) + + expected = matrix( c( predict_y, predict_sigma), ncol = 2) + colnames(expected) = c( "mu", "sigma") + + expect_equal( predict(fitlmvar), expected) + expect_equal( predict( fitlmvar, X_sigma = M_sigma[,-1]), expected) +}) + +test_that("predict calculates confidence intervals", { + + X_mu = fit$X_mu + X_sigma = fit$X_sigma + + mu = fitted( fit, sigma = FALSE) + sigma = fitted( fit, mu = FALSE) + + # Confidence intervals for mu + S = vcov( fit, sigma = FALSE) + S = X_mu %*% S %*% t(X_mu) + delta_mu = sqrt(diag(S)) + + z = stats::qnorm(0.5 + 0.95/2) + mu_upr = mu + z * delta_mu + mu_lwr = mu - z * delta_mu + + # Construct expected results + expected = cbind( mu, mu_lwr, mu_upr) + colnames(expected) = c( "mu", "mu_lwr", "mu_upr") + + expect_equal( predict(fit, sigma = FALSE, interval = "confidence"), expected) + + # Confidence intervals for sigma + S = vcov( fit, mu = FALSE) + S = X_sigma %*% S %*% t(X_sigma) + delta_sigma = sigma * sqrt(diag(S)) + + sigma_upr = sigma + z * delta_sigma + sigma_lwr = sigma - z * delta_sigma + + # Construct expected results + expected = cbind( sigma, sigma_lwr, sigma_upr) + colnames(expected) = c( "sigma", "sigma_lwr", "sigma_upr") + + expect_equal( predict(fit, mu = FALSE, interval = "confidence"), expected) + + # Confidence intervals with different confidence level + z = stats::qnorm(0.5 + 0.5/2) + mu_upr = mu + z * delta_mu + mu_lwr = mu - z * delta_mu + sigma_upr = sigma + z * delta_sigma + sigma_lwr = sigma - z * delta_sigma + + # Construct expected results + expected = cbind( mu, mu_lwr, mu_upr, sigma, sigma_lwr, sigma_upr) + colnames(expected) = c( "mu", "mu_lwr", "mu_upr", "sigma", "sigma_lwr", "sigma_upr") + + expect_equal( predict(fit, interval = "confidence", level = 0.5), expected) +}) + +test_that("predict calculates confidence intervals with log=TRUE", { + + X_mu = fit$X_mu + X_sigma = fit$X_sigma + + mu = fitted( fit, sigma = FALSE, log = TRUE) + sigma = fitted( fit, mu = FALSE, log = TRUE) + sigma_not_log = fitted( fit, mu = FALSE) + + # Variance for mu + S = vcov( fit, sigma = FALSE) + S = X_mu %*% S %*% t(X_mu) + variance_mu = diag(S) + + # Variance for log sigma + S = vcov( fit, mu = FALSE) + S = X_sigma %*% S %*% t(X_sigma) + variance_log_sigma = diag(S) + + # Standard deviations for mu + delta_mu = variance_mu + sigma_not_log^4 * variance_log_sigma + delta_mu = mu * sqrt(delta_mu) + + # Standard deviations for sigma + delta_sigma = sigma^2 * variance_mu + sigma_not_log^4 * (2 * sigma + mu^2 / sigma)^2 * variance_log_sigma + delta_sigma = sqrt(delta_sigma) + + # Confidence intervals + z = stats::qnorm(0.5 + 0.95/2) + mu_upr = mu + z * delta_mu + mu_lwr = mu - z * delta_mu + sigma_upr = sigma + z * delta_sigma + sigma_lwr = sigma - z * delta_sigma + + # Construct expected results for mu + expected = cbind( mu, mu_lwr, mu_upr) + colnames(expected) = c( "mu", "mu_lwr", "mu_upr") + + expect_equal( predict(fit, sigma = FALSE, interval = "confidence", log = TRUE), expected) + + # Construct expected results for sigma + expected = cbind( sigma, sigma_lwr, sigma_upr) + colnames(expected) = c( "sigma", "sigma_lwr", "sigma_upr") + + expect_equal( predict(fit, mu = FALSE, interval = "confidence", log = TRUE), expected) + + # Confidence intervals with different confidence level + z = stats::qnorm(0.5 + 0.5/2) + mu_upr = mu + z * delta_mu + mu_lwr = mu - z * delta_mu + sigma_upr = sigma + z * delta_sigma + sigma_lwr = sigma - z * delta_sigma + + # Construct expected results + expected = cbind( mu, mu_lwr, mu_upr, sigma, sigma_lwr, sigma_upr) + colnames(expected) = c( "mu", "mu_lwr", "mu_upr", "sigma", "sigma_lwr", "sigma_upr") + + expect_equal( predict(fit, interval = "confidence", level = 0.5, log = TRUE), expected) + +}) diff --git a/vignettes/Intro.Rmd b/vignettes/Intro.Rmd new file mode 100644 index 0000000..6216d38 --- /dev/null +++ b/vignettes/Intro.Rmd @@ -0,0 +1,176 @@ +--- +title: "A linear model with non-constant variances" +author: "Posthuma Partners" +date: "`r Sys.Date()`" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Introduction to the package} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +## The package +The 'lmvar' package fits a linear model in which the assumption of homoscedasticity (i.e., the variance is independent of the expectation value) is dropped. Instead, the variance has its own model, comparable to the model for the expectation value. + +The fit results in an 'lmvar' object, which is a list of class 'lmvar'. Accessor functions are provided to extract the list members such as the fitted betas and the log-likelihood for the model. Various utility functions such as `residuals` to calculate residuals, `AIC` to calculate the AIC, `fitted` to obtain expected values and standard deviations, etc., are also provided by the package. + +The package lacks much of the sophistication of the 'lm' and 'glm' packages. On the bright side, this means it is simple to use. It is intended for people who run a classical linear model and want to see what happens if the restriction of a constant variance is dropped. Questions in this context are: does the allowance of heteroscedasticity result in a better fit, lower values for the AIC or BIC, smaller errors from a cross-validation, etc.? + +## The model +The package fits the following model. A vector $Y$ of observations (sometimes called 'responses') of length $n$ is a stochastic vector. It is distributed according to a multivariate Gaussian distribution: + +\begin{equation} +Y \sim \mathcal{N}_n( \mu, \Sigma), +\end{equation} +where $\mu$ is the vector of expectation values and $\Sigma$ the covariance matrix (also called the 'variance-covariance matrix'). Just like in the standard linear model, the covariance is taken to be a $n \times n$ diagonal matrix but contrary to the standard linear model, the diagonal entries need not be all the same: +\begin{equation} +\Sigma_{ij} = +\begin{cases} +0 & i \neq j\\ +\sigma_i^2 & i=j +\end{cases} +\end{equation} + +### Model for the expectation values + +As in the classical linear model, the vector of expectation values $\mu$ is given by +\begin{equation} +\mu = X_\mu \beta_\mu +\end{equation} +where $X_\mu$ is the 'model matrix' or 'design matrix' for $\mu$ and $\beta_\mu$ the parameter vector for $\mu$. $X_\mu$ is a $n \times k_\mu$ matrix and $\beta_\mu$ a vector of length $k_\mu$. + +### Model for the variances + +Let $\sigma$ denotes the vector $(\sigma_1, \dots, \sigma_n)$. The model for $\sigma$ is +\begin{equation} +\log \sigma = X_\sigma \beta_\sigma +\end{equation} +where $\log \sigma$ stands for the vector $(\log\sigma_1, \dots, \log\sigma_n)$, $X_\sigma$ is the 'model matrix' or 'design matrix' for $\sigma$ and $\beta_\sigma$ the parameter vector for $\sigma$. The logarithm is taken to be the 'natural logarithm' with base $e$. The dimensions of $X_\sigma$ are $n \times k_\sigma$ and $\beta_\sigma$ is a vector of length $k_\sigma$. + +### Also know that... + +The vector of observations $Y$ and the matrices $X_\mu$ and $X_\sigma$ are specified by the user. They must contain real values. The fit returns the maximum-likelihood estimators for $\beta_\mu$ and $\beta_\sigma$. They are also real-valued vectors. + +The model for both $\mu$ and $\sigma$ contains an intercept term. That means that the first column of both matrices is a column in which each matrix-element equals 1. The package will add this column to the user-suppplied matrices to ensure that the intercept term is always present. There is no need for a user to include such a column in a user-supplied model-matrix. + +After adding the intercept column, the package will check whether the resulting matrices are full rank. If not, columns will be removed from each matrix until it is full rank. + +The addition of an intercept column and, possibly, the removal of columns to obtain a full-rank matrix, imply that the actual matrices used in the fit can be different from the user-specified matrices. The matrices that are actually used in the fit are returned as members of the `lmvar` object. + +Carrying out the fit boils down to solving a set of non-linear equations. This is carried out by the function `nleqslv` from the package with the same name. + +More mathematical details about the model can be found in the vignette 'Math' which comes with this package. It can be viewed with `vignette("Math")` or `vignette("Math", package="lmvar")`. + +## Using the package + +The main function in the package is `lmvar`. It carries out a fit and returns an `lmvar` object. + +The user must specify a vector of observations and two model-matrices when calling `lmvar`. They must meet the following conditions: + +* All observations and matrix elements must be real-valued. +* Missing values, values that are `NaN` etc., are not allowed. +* A matrix either has column names for all columns or no column names at all. The same column name can appear for both $X_\mu$ and $X_\sigma$ but column names should be unique within each matrix. The intercept column that is added automatically by `lmvar` is called `(Intercept)` for $X_\mu$ and `(Intercept_s)` for $X_\sigma$. In case no column-names are specified, the second, third, etc. columns are called `v1`, `v2` etc. for $X_\mu$ and `v1_s`, `v2_s` etc. for $X_\sigma$. +* When the user-supplied matrix $X_\mu$ has column names, none of those should be `(Intercept)`. This is a reserved name, as we explained above. Likewise, a user-supplied matrix $X_\sigma$ must not have a column named `(Intercept_s)`. + +With each column in $X_\mu$ corresponds an element in $\beta_\mu$. +The name of that element is the corresponding column name. The same is true for $X_\sigma$ and $\beta_\sigma$. + +It can happen that `nleqslv` fails to solve the maximum-likelihood equations. Sometimes the problem can be traced back to columns in $X_\sigma$ with many zero's. I.e., covariates (or factor-levels) for $\sigma$ which affect only few observations. Removal of these columns may remedy the issue. + +An `lmvar` object is a list whose members are intended to be extracted with the supplied accessor and utility functions. The only members for which no such functions have been implemented are: + +* `y`: the user-supplied vector of observations +* `X_mu`: the actual, full-rank matrix $X_\mu$ including the intercept term that is used in the fit +* `X_sigma`: the actual, full-rank matrix $X_\sigma$ including the intercept term that is used in the fit + +Once `lmvar` has run and an `lmvar`-object created, one can obtain $\beta_\mu$ and $\beta_\sigma$ with the function `coef`. The function `fitted` allows one to obtain $\mu$ and $\sigma$. We refer to the package documentation (in particular the package index which can be viewed with `help(package = "lmvar")`) for a list of all available functions and function details. + +## Demonstration + +We demonstrate the package with the help of the dataframe `attenu` which can be found in the `datasets` package. +```{r} +library(lmvar) + +# As example we use the dataset 'attenu' from the library 'datasets'. The dataset contains +# the response variable 'accel' and two explanatory variables 'mag' and 'dist'. +library(datasets) + +# Create the model matrix for the expected values +X = cbind(attenu$mag, attenu$dist) +colnames(X) = c("mag", "dist") + +# Create the model matrix for the standard deviations. +X_s = cbind(attenu$mag, 1 / attenu$dist) +colnames(X_s) = c("mag", "dist_inv") + +# Carry out the fit +fit = lmvar(attenu$accel, X, X_s) +``` +We have now created the object `fit` which is our object of class `lmvar`. To obtain a first impression of the fit, we look at the summary +```{r} +summary(fit) +``` +The first line shows the call that created `fit`. Next, we are told something about the distribution of the standardized residuals. Ideally, the first quarter (`1Q`) must be approximately -0.67, the `median` 0 and the third quarter (`3Q`) 0.67. + +Next, the summary shows the matrix with the coefficients $\beta_\mu$ and $\beta_\sigma$. The coefficients $\beta_\mu$ are `(Intercept)`, `mag` and `dist`. The coefficients $\beta_\sigma$ are `(Intercept_s)`, `mag_s` and `dist_inv_s`. They are called this way to distinguish them from the coefficients for $\beta_\mu$. In cases where there is no risk of confusion, their true names will be used, which are `(Intercept_s)`, `mag` and `dist_inv`. + +The matrix with coefficients shows that all coefficients are statistically significant at the 5% level. + +The next piece of information gives an impression of the distribution of the standard deviations. They range from 0.0631 to 42.0983. + +Finally the model is compared to a classical linear model with the same model matrix $X_\mu$ but a fixed standard deviation. The summary shows the difference in log-likelihood between the two models and the difference in degrees of freedom. Twice the difference in log-likelihood is the difference in deviance, for which a p-value is calculated. The fact that the p-value in the summary is nearly zero, indicates that the `lmvar` fit is a better fit than the classical linear model. I.e., it makes sense to let the variance vary instead of keeping it fixed. + +Let's see how the standard deviations are distributed +```{r} +sigma = fitted(fit, mu = FALSE) +hist(sigma) +``` + +To check the distribution of the residuals, we make another histogram. +```{r} +hist(residuals(fit)) +``` + +The rank of the matrix $X_\mu$ used in the fit is +```{r} +dfree(fit, sigma = FALSE) +``` +The value 3 is correct: the user-supplied matrix had 2 columns and `lmvar` added an intercept column. Apparently all columns are linearly independent so no column had to be removed. + +To see the number of observations in the fit, the log-likelihood and the AIC value, we run +```{r} +nobs(fit) +logLik(fit) +AIC(fit) +``` +The coefficients $\beta_\mu$ and $\beta_\sigma$ that were displayed in the summary-overview are obtained by +```{r} +coef(fit) +``` +If we only ask for $\beta_\sigma$,we see their real names +```{r} +coef(fit, mu = FALSE) +``` +We conclude this demonstration with the covariance matrix for the coefficients $\beta_\mu$ +```{r} +vcov(fit, sigma = FALSE) +``` +Hopefully this demonstration has given an idea of how to work with the package. The documentation of the individual fuctions contains further examples. + +## Functions in the package + +We refer to the package index for a list of all available functions. The index can be viewed with `help(package="lmvar")`. + +## Other packages + +The function `remlscore` in the package `statmod` fits precisely the same model as `lmvar`. However, `statmod` does not provide any utility function, which we believe are important to foster the acceptance of this model as a step beyond classical linear regression. + +Other functions that allow for a model of the dispersion are, e.g., `hglm` in the package `hglm` and `geese` in the package `geepack`. These models are more complicated though, and require a level of expertise not required by `lmvar`. + +## Acknowledgements + +We thank prof. dr. Eric Cator for his valuable comments and suggestions. + + diff --git a/vignettes/Math.ltx b/vignettes/Math.ltx new file mode 100644 index 0000000..a32de27 --- /dev/null +++ b/vignettes/Math.ltx @@ -0,0 +1,328 @@ +%\VignetteIndexEntry{Math details} +%\VignetteEngine{R.rsp::tex} +%\VignetteKeyword{R} +%\VignetteKeyword{package} +%\VignetteKeyword{vignette} +%\VignetteKeyword{LaTeX} +%!TeX spellcheck = en_US +\documentclass{article} +\usepackage{amsmath,amsfonts} +\usepackage{mathtools} + +\newcommand{\vvec}[1]{\vec{\vec{#1}}} +\newcommand{\cov}{\text{cov}} +\newcommand{\Ker}{\text{Ker}} + +\newtheorem{lemma}{Lemma} + +\begin{document} +\section{LMVAR: a linear model with heteroscedasticity} +This vignette describes in more detail the mathematical aspects of the model with which the \texttt{lmvar} package is concerned. A short description can be found in the vignette 'Intro' of this package. + +Assume that a stochastic vector $Y \in \mathbb{R}^n$ has a multivariate normal distribution as +\begin{equation} +Y \sim \mathcal{N}_n(\mu^\star, \Sigma) +\end{equation} +in which $\mu^\star \in \mathbb{R}^n$ is the expected value and $\Sigma \in \mathbb{R}^{n,n}$ a diagonal covariance matrix +\begin{equation} +\Sigma_{ij} = +\begin{cases} +0 & i \neq j \\ +(\sigma_i^\star)^2 & i=j. +\end{cases} +\end{equation} +Assume that the vector of expectation values $\mu$ is linearly dependent on the values of the covariates in a model matrix $X_\mu$: +\begin{equation} +\mu^\star = X_\mu \beta_\mu^\star +\end{equation} +with $X_\mu \in \mathbb{R}^{n,k_\mu}$ and $\beta_\mu^\star \in \mathbb{R}^{k_\mu}$. + +Similarly, assume that the vector $\sigma^\star = (\sigma_1^\star, \dots, \sigma_n^\star)$ depends on the covariates in a model matrix $X_\sigma$ as +\begin{equation} +\log \sigma^\star = X_\sigma \beta_\sigma^\star +\end{equation} +where $\log \sigma^\star = (\log\sigma_1^\star, \dots, \log\sigma_n^\star)$, $X_\sigma \in \mathbb{R}^{n,k_\sigma}$ and $\beta_\sigma^\star \in \mathbb{R}^{k_\sigma}$. The logarithm is taken to be the 'natural logarithm', i.e., with base $e$. + +We assume $n \geq k_\mu + k_\sigma$ to avoid having an overdetermined system when we calculate estimators for $\beta_\mu^\star$ and $\beta_\sigma^\star$, as explained in the next section. + +If we take $X_\sigma$ a $n\times 1$ matrix in which each element is equal to 1, we have the standard linear model. + +The parameter vector $\beta_\mu^\star$ is defined uniquely only if $X_\mu$ is full-rank. If not, the space $\mathbb{R}^{k_\mu}$ can be split into subspaces such that there is a uniquely defined $\beta_\mu^\star$ in each subspace. The way \texttt{lmvar} treats this is as follows. If the user-supplied $X_\mu$ is not full-rank, \texttt{lmvar} removes just enough columns from the matrix to make it full-rank. This amounts to selecting $\beta_\mu^\star$ from the subspace in which all vector elements corresponding to the removed columns, are set to zero. + +In the same way, if the user-supplied $X_\sigma$ is not full-rank, just enough columns are removed to make it so. This defines a subspace in which $\beta_\sigma^\star$ is defined uniquely. + +In what follows we assume that $X_\mu$ and $X_\sigma$ are the matrices after the columns have been removed, i.e., they are full-rank matrices. The vector elements that are set to zero, drop out of $\beta_\mu^\star$ and $\beta_\sigma^\star$ and the dimensions $k_\mu$ and $k_\sigma$ are reduced accordingly. These reduced dimensions are returned by the function \texttt{dfree} in the \texttt{lmvar} package. + +\section{Maximum-likelihood equations} +A vector element $Y_i$ is distributed as +\begin{equation} +Y_i \sim \frac{1}{\sqrt{2\pi}\sigma_i^\star} \exp \left( -\frac{(Y_i - \mu_i^\star)^2}{2 (\sigma_i^\star)^2} \right). +\end{equation} +The logarithm of the likelihood $\mathcal L$ is defined as +\begin{equation} +\log \mathcal{L}(\beta_\mu, \beta_\sigma) = - \frac{n}{2} \log(2\pi) - \sum_{k=1}^n ( \log \sigma_k + \frac{(y_k - \mu_k)^2}{2 \sigma_k^2}). +\end{equation} +for all vectors $\beta_\mu \in \mathbb{R}^{k_\mu}$ and $\beta_\sigma \in \mathbb{R}^{k_\sigma}$ and $\mu$ and $\sigma$ defined as +\begin{equation} +\begin{split} +\mu & = X_\mu \beta_\mu \\ +\log \sigma & = X_\sigma \beta_\sigma. +\end{split} +\end{equation} + +We are looking for $\hat{\beta_\mu} \in \mathbb{R}^{k_\mu}$ and $\hat{\beta_\sigma} \in \mathbb{R}^{k_\sigma}$ that maximize the log-likelihood: +\begin{equation} \label{eq:mle def} +(\hat{\beta}_\mu, \, \hat{\beta}_\sigma) = \underset{(\beta_\mu, \beta_\sigma) \in \mathbb{R}^{k_\mu} \times \mathbb{R}^{k_\sigma}} {\text{argmax}} \log \mathcal{L} (\beta_\mu, \beta_\sigma). +\end{equation} +These maximum likelihood estimators are taken to be the estimators of $\beta_\mu^\star$ and $\beta_\sigma^\star$. +We assume that $\hat{\beta}_{\mu}$ and $\hat{\beta}_\sigma$ thus defined, exist and are unique. + +Given $\hat{\beta}_\sigma$, this is true for $\hat{\beta}_\mu$. Namely, given any $\beta_\sigma$, $\log \mathcal{L}$ is maximized by the $\beta_\mu$ which is the solution of +\begin{equation} \label{eq:mle mu} +\nabla_{\beta_\mu} \log \mathcal{L} = 0 +\end{equation} +where $\nabla_{\beta_\mu}$ stands for the gradient $(\frac{\partial}{\partial \beta_{\mu,1}}, \dots, \frac{\partial}{\partial \beta_{\mu,n}})$. + +The derivatives are +\begin{align} +\frac{\partial \log \mathcal{L}}{\partial \beta_{\mu,i}} & = \sum_{k=1}^n ( \frac{(y_k - \mu_k)}{\sigma_k^2}) (X_\mu)_{ki} \label{eq:dll dbmu}\\ +& = \left( X_\mu^T \Lambda (y -\mu) \right)_i +\end{align} +with $\Lambda$ a diagonal matrix given by +\begin{equation} \label{eq:Lambda def} +\Lambda_{ij} = \frac{1}{\sigma_i^2} \delta_{ij}. +\end{equation} +Hence +\begin{equation} +\nabla_{\beta_\mu} \log \mathcal{L} = X_\mu^T \Lambda (y -\mu) +\end{equation} +and the maximum-likelihood equation \eqref{eq:mle mu} becomes +\begin{equation} +X_\mu^T \Lambda X_\mu \beta_\mu = X_\mu^T \Lambda y +\end{equation} +which has the solution +\begin{equation} +\beta_\mu = \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda y . \label{eq:bmustar} +\end{equation} +Because of our assumption that $X_\mu$ is full rank, the inverse of the matrix $X_\mu^T \Lambda X_\mu$ can be taken. + +It is easy to see that the solution \eqref{eq:bmustar} represents a maximum in the log-likelihood. The matrix $H_{\mu \mu}$ of second-order derivatives +\begin{equation} +\left( H_{\mu \mu} \right)_{ij} = \frac{\partial^2 \log L}{\partial \beta_{\mu i} \partial \beta_{\mu j}} +\end{equation} +is given by +\begin{equation} \label{eq:Hmumu} +H_{\mu \mu} = - X_\mu^T \Lambda X_\mu, +\end{equation} +which is negative-definite for any $\beta_\sigma$. + +Our maximization search can now be carried out in a smaller space: +\begin{equation} \label{eq:mle sigma} +\hat{\beta_\sigma} = \underset{\beta_\sigma \in \mathbb{R}^{k_\sigma}} {\text{argmax}} \; \log \mathcal{L}_P ( \beta_\sigma) +\end{equation} +where $\mathcal{L}_P$ is the so-called profile-likelihood +\begin{equation} +\mathcal{L}_P ( \beta_\sigma) = \mathcal{L} (\beta_\mu (\beta_\sigma), \beta_\sigma). +\end{equation} +with $\beta_\mu$ depending on $\beta_\sigma$ as in \eqref{eq:bmustar}. + +To find $\hat{\beta}_\sigma$ from \eqref{eq:mle sigma}, we must solve +\begin{equation} \label{eq:mle sigma 2} +(\nabla_{\beta_\mu} \log \mathcal{L}) \, (\nabla_{\beta_\sigma} \beta_\mu) + \nabla_{\beta_\sigma} \log \mathcal{L} = 0 +\end{equation} +evaluated at $\beta_\mu = \beta_\mu(\beta_\sigma)$, and $(\nabla_{\beta_\sigma} \beta_\mu)$ the matrix +\begin{equation} +(\nabla_{\beta_\sigma} \beta_\mu)_{ij} = \frac{\partial \beta_{\mu i}}{\partial \beta_{\sigma j}}. +\end{equation} +However, because of \eqref{eq:mle mu}, the first term in \eqref{eq:mle sigma 2} vanishes and we are left to solve +\begin{equation} \label{eq:mle sigma 3} +\nabla_{\beta_\sigma} \log \mathcal{L} = 0. +\end{equation} +The derivatives that are the elements of this gradient are given by +\begin{align} +\frac{\partial \log \mathcal{L}}{\partial \beta_{\sigma i}} & = \sum_{k=1}^n ( - (X_\sigma)_{ki} + \frac{(y_k - \mu_k)^2}{\sigma_k^2} (X_\sigma)_{ki}) \nonumber\\ +& = \sum_{k=1}^n (\frac{(y_k - \mu_k)^2}{\sigma_k^2} -1) (X_\sigma)_{ki}. \label{eq:mle sigma 4} +\end{align} +The entire gradient can be written as a matrix-product as +\begin{equation} \label{eq:mle 2} +\nabla_{\beta_\sigma} \log \mathcal{L} = X_\sigma^T \lambda_\sigma +\end{equation} +with $\lambda_\sigma$ a vector of length $n$ whose elements $\lambda_{\sigma i}$ are +\begin{equation} +\lambda_{\sigma i} = \left( \frac{y_i - \mu_i}{\sigma_i} \right)^2 -1. +\end{equation} +The maximum-likelihood equations \eqref{eq:mle sigma 3} take the form +\begin{equation} +X_\sigma^T \lambda_\sigma = 0. +\end{equation} + +The estimate $\mu$ of the expectation value that appears in $\lambda_\sigma$ depends on $\beta_\sigma$ as +\begin{align} +\mu & = X_\mu \beta_\mu \nonumber\\ +& = X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda y \nonumber\\ +& = \Lambda^{1/2} X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda^{1/2} y +\end{align} +where the latter form is the more symmetric, with +\begin{equation} +\left( \Lambda^{1/2} \right)_{ij} = \frac{1}{\sigma_i} \delta_{ij}. +\end{equation} +The vector $(y - \mu) / \sigma$ can be written as +\begin{equation} +\frac{y-\mu}{\sigma} = \Lambda^{1/2} \left[ I - \Lambda^{1/2} X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda^{1/2} \right] y +\end{equation} +in which $I \in \mathbb{R}^{n,n}$ is the identity matrix. + +\subsection{Profile-likelihood Hessian} +Numerical procedures to solve the maximum-likelihood equations $X_\sigma^T \lambda_\sigma=0$ involve the calculation of the Hessian $H_P$ of the profile log-likelihood. $H_P$ is the matrix of second-order derivatives of $\log \mathcal{L}_P$: +\begin{equation} +\left( H_P \right)_{ij} = \frac{\partial^2 \log \mathcal{L}_P}{\partial \beta_{\sigma j} \partial \beta_{\sigma i}} +\end{equation} +Differentiation of \eqref{eq:mle sigma 4} gives for the second-order derivatives +\begin{equation} \label{eq:hess} +\left( H_P \right)_{ij} = -2 \sum_{k=1}^n (X_\sigma^T)_{ik} \frac{y_k - \mu_k}{\sigma_k^2} \left\lbrace \frac{\partial \mu_k}{\partial \beta_{\sigma j}} + (y_k - \mu_k) (X_\sigma)_{kj} \right\rbrace +\end{equation} +with +$\partial \mu_k / (\partial \beta_{\sigma j})$ the element at row $k$ and column $j$ of the matrix $(\nabla_{\beta_\sigma} \mu)$. Given that $\mu = X_\mu \beta_\mu$ and $\beta_\mu$ is given by \eqref{eq:bmustar}, the {\em j}-th column vector of the matrix is +\begin{align} +\frac{\partial \mu}{\partial \beta_{\sigma j}} & = X_\mu \frac{\partial \beta_\mu}{\partial \beta_{\sigma j}} \nonumber\\ +& = X_\mu \left\lbrace \frac{\partial \left( X_\mu^T \Lambda X_\mu \right)^{-1}}{\partial \beta_{\sigma j}} X_\mu^T \Lambda + \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} \right\rbrace y \nonumber\\ +& = X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} \left\lbrace - X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda + X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} \right\rbrace y \nonumber\\ +& = X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} \left\lbrace - X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \Lambda + I \right\rbrace y \nonumber\\ +& = X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \frac{\partial \Lambda}{\partial \beta_{\sigma j}} (y - \mu) +\end{align} +The matrix $\partial \Lambda / (\partial \beta_{\sigma j})$ takes the form +\begin{align} +\frac{\partial \Lambda}{\partial \beta_{\sigma j}} & = \sum_{i=1}^n \frac{\partial \Lambda}{\partial \sigma_i} \frac{\partial \sigma_i}{\partial \beta_{\sigma j}}\\ +& = -2 +\begin{pmatrix} +(X_\sigma)_{1j} & & 0 \nonumber\\ +& \ddots & \\ +0 & & (X_\sigma)_{nj} +\end{pmatrix} \Lambda +\end{align} +The {\em j}-th column vector of the matrix is +\begin{equation} +\frac{\partial \mu}{\partial \beta_{\sigma j}} = -2 X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T +\begin{pmatrix} +\frac{y_1 - \mu_1}{\sigma_1^2} \left( X_\sigma \right)_{1j} \\ +\vdots \\ +\frac{y_n - \mu_n}{\sigma_n^2} \left( X_\sigma \right)_{nj} +\end{pmatrix} +\end{equation} +and the element $(\nabla_{\beta_\sigma} \mu)_{kj}$ of the matrix $(\nabla_{\beta_\sigma} \mu)$ is given by +\begin{equation} +\frac{\partial \mu_k}{\partial \beta_{\sigma j}} = -2 \sum_{l=1}^n \left( X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \right)_{kl} \frac{y_l - \mu_l}{\sigma_l^2} \left( X_\sigma \right)_{lj}. +\end{equation} +If we substitute this result in \eqref{eq:hess}, we obtain for the element at row $i$ and column $j$ of the Hessian: +\begin{align} +& \left( H_P \right)_{ij} = \nonumber \\ +& \quad 4 \sum_{k,l=1}^n (X_\sigma^T)_{ik} \frac{y_k - \mu_k}{\sigma_k^2} \left( X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \right)_{kl} \frac{y_l - \mu_l}{\sigma_l^2} \left( X_\sigma \right)_{lj} + \nonumber\\ +& \quad -2 \sum_{k=1}^n (X_\sigma^T)_{ik} \left( \frac{y_k - \mu_k}{\sigma_k} \right)^2 (X_\sigma)_{kj}. +\end{align} +We can write the Hessian as a matrix-product as +\begin{equation} +\begin{split} +H_P = X_\sigma^T \tilde{\Lambda}_1 X_\mu \left( X_\mu^T \Lambda X_\mu \right)^{-1} X_\mu^T \tilde{\Lambda}_1 X_\sigma + X_\sigma^T \tilde{\Lambda}_2 X_\sigma +\end{split} +\end{equation} +with two $n \times n$ diagonal matrices +\begin{equation} +\begin{split} +\left(\tilde{\Lambda}_1 \right)_{ij} & = 2 \, \frac{y_i - \mu_i}{\sigma_i^2} \, \delta_{ij} \\ +\left( \tilde{\Lambda}_2 \right)_{ij} & = -2 \left( \frac{y_i - \mu_i}{\sigma_i} \right)^2 \, \delta_{ij}. +\end{split} +\end{equation} + +\section{Distributions for estimators} +Asymptotic theory of maximum-likelihood estimators tells that the vector of the combined estimators $(\hat{\beta}_\mu, \hat{\beta}_\sigma)$ as defined in \eqref{eq:mle def}, is distributed approximately as +\begin{equation} +(\hat{\beta}_\mu, \hat{\beta}_\sigma) \sim \mathcal{N}_{k_\mu + k_\sigma} \left((\beta_\mu^\star, \beta_\sigma^\star), \Sigma_{\beta \beta} \right) \qquad \text{for } n \text{ large.} +\end{equation} +This distribution is valid in the limit of a large number of observations $n$. + +The covariance matrix $\Sigma_{\beta \beta}$ is given in terms of the inverse Fisher information matrix $I_n$: +\begin{equation} +\Sigma_{\beta \beta} = \frac{1}{n} I_n^{-1}. +\end{equation} +The Fisher information matrix is given in terms of the expected value of the Hessian: +\begin{equation} +I_n = - \frac{1}{n} E[H]. +\end{equation} +The Hessian $H$ is the Hessian of the full log-likelihood, in contrast to the profile-likelihood Hessian: +\begin{equation} +H = +\begin{pmatrix} +H_{\mu\mu} & H_{\mu\sigma} \\ +H_{\mu\sigma}^T & H_{\sigma\sigma} +\end{pmatrix} +\end{equation} +with the three block-matrices defined as +\begin{equation} +\left( H_{\mu\mu} \right)_{ij} = \frac{\partial^2 \log L}{\partial \beta_{\mu i} \partial \beta_{\mu j}}, \; \left( H_{\mu\sigma} \right)_{ij} = \frac{\partial^2 \log L}{\partial \beta_{\mu i} \partial \beta_{\sigma j}}, \; \left( H_{\sigma\sigma} \right)_{ij} = \frac{\partial^2 \log L}{\partial \beta_{\sigma i} \partial \beta_{\sigma j}}. +\end{equation} +We have already calculated $H_{\mu\mu}$ in \eqref{eq:Hmumu}. Differentiation of \eqref{eq:dll dbmu} and \eqref{eq:mle sigma 4} respectively gives +\begin{align*} +\left( H_{\mu\sigma} \right)_{ij} & = -2 \sum_{k=1}^n \frac{y_k - \mu_k}{\sigma_k^2} \left( X_\mu \right)_{ki} \left( X_\sigma \right)_{kj} \\ +\left( H_{\sigma\sigma} \right)_{ij} & = -2 \sum_{k=1}^n \left( \frac{y_k - \mu_k}{\sigma_k} \right)^2 \left( X_\sigma \right)_{ki} \left( X_\sigma \right)_{kj}. +\end{align*} +In matrix notation: +\begin{equation} +H_{\mu\sigma} = X_\mu^T \Lambda_1 X_\sigma, \qquad H_{\sigma\sigma} = X_\sigma^T \Lambda_2 X_\sigma, +\end{equation} +with the diagonal matrices +\begin{equation} +\left( \Lambda_1 \right)_{ij} = -2 \, \frac{y_i - \mu_i}{\sigma_i^2} \, \delta_{ij}, \qquad \left( \Lambda_2 \right)_{ij} = -2 \left( \frac{y_i - \mu_i}{\sigma_i} \right)^2 \delta_{ij}. +\end{equation} +When we take expected values, we have to take $\beta_\mu = \beta_\mu^\star$ and $\beta_\sigma = \beta_\sigma^\star$. Keeping in mind that +\begin{align*} +E[Y - \mu^\star] & = 0 \\ +E[(Y_i-\mu_i^\star)(Y_j - \mu_j^\star)] & = {\sigma_i^\star}^2 \delta_{ij}, +\end{align*} +we have +\begin{equation} +E[H_{\mu\mu}] = - X_\mu^T \Lambda^\star X_\mu, \; E[H_{\mu\sigma}] = 0, \; E[H_{\sigma\sigma}] = -2 X_\sigma^T X_\sigma +\end{equation} +where $\Lambda^\star$ is $\Lambda$ with $\sigma$ taken to be $\sigma^\star$. This brings the expected value of the Hessian in the form +\begin{equation} \label{eq:exp H} +E[H] = - +\begin{pmatrix} +X_\mu^T \Lambda^\star X_\mu & 0 \\ +0 & 2 X_\sigma^T X_\sigma +\end{pmatrix}. +\end{equation} +The function \texttt{fisher} in the \texttt{lmvar} package calculates the Fisher information matrix. It estimates $E[H]$ by replacing the true but unknown $\sigma^\star$ by its maximum-likelihood estimator $\hat{\sigma}$ in $\Lambda^\star$. + +The expectation value \eqref{eq:exp H} brings the covariance matrix $\Sigma_{\beta\beta}$ in the form +\begin{equation} +\Sigma_{\beta\beta} = +\begin{pmatrix} +\left( X_\mu^T \Lambda^\star X_\mu \right)^{-1} & 0 \\ +0 & \frac{1}{2} \left( X_\sigma^T X_\sigma \right)^{-1} +\end{pmatrix}. +\end{equation} +This implies +\begin{equation} +\begin{aligned} +\hat{\beta}_\mu & \sim \mathcal{N}_{k_\mu}( \beta_\mu^\star, \, \left( X_\mu^T \Lambda^\star X_\mu \right)^{-1}) \\ +\hat{\beta}_\sigma & \sim \mathcal{N}_{k_\sigma}( \beta_\sigma^\star, \,\tfrac{1}{2} \left( X_\sigma^T X_\sigma \right)^{-1}) +\end{aligned} \qquad \text{ for } n \text{ large.} +\end{equation} +We obtain for the asymptotic distribution of the maximum-likelihood estimators of $\mu^\star$ and $\sigma^\star$ +\begin{equation} +\begin{aligned} +\hat{\mu} & \sim \mathcal{N}_n (\mu^\star, \, X_\mu \left( X_\mu^T \Lambda^\star X_\mu \right)^{-1} X_\mu^T) \\ +\log \hat{\sigma} & \sim \mathcal{N}_n (\log \sigma^\star, \, \tfrac{1}{2} X_\sigma \left( X_\sigma^T X_\sigma \right)^{-1} X_\sigma^T) +\end{aligned} +\qquad \text{ for } n \text{ large.} +\end{equation} +The expectation value and the variance for an element $\hat{\sigma}_i$ of $\hat{\sigma}$ are +\begin{equation} +\begin{aligned} +E[\hat{\sigma}_i] & = \sigma_i^\star \exp\left( \frac{(X_\sigma \left( X_\sigma^T X_\sigma \right)^{-1} X_\sigma^T)_{ii}}{4} \right) \\ +\text{var}(\hat{\sigma}_i) & = \left( E[\hat{\sigma}_i] \right)^2 \left(\exp (\frac{(X_\sigma \left( X_\sigma^T X_\sigma \right)^{-1} X_\sigma^T)_{ii}}{2}) - 1 \right) +\end{aligned} +\qquad \text{ for } n \text{ large}. +\end{equation} +The function \texttt{fitted.lmvar} (with the option \texttt{log = FALSE}) returns $\hat{\mu}$ and $\hat{\sigma}$. + +\end{document}