| Title: | Multivariate Normal Variance Mixtures |
|---|---|
| Description: | Functions for working with (grouped) multivariate normal variance mixture distributions (evaluation of distribution functions and densities, random number generation and parameter estimation), including Student's t distribution for non-integer degrees-of-freedom as well as the grouped t distribution and copula with multiple degrees-of-freedom parameters. See <doi:10.18637/jss.v102.i02> for a high-level description of select functionality. |
| Authors: | Marius Hofert [aut, cre], Erik Hintz [aut], Christiane Lemieux [aut] |
| Maintainer: | Marius Hofert <[email protected]> |
| License: | GPL (>= 3) | file LICENCE |
| Version: | 0.1-2 |
| Built: | 2026-05-22 06:02:10 UTC |
| Source: | https://github.com/cran/nvmix |
Evaluate the density / distribution function of normal variance mixture copulas (including Student t and normal copula) and generate vectors of random variates from normal variance mixture copulas.
dnvmixcopula(u, qmix, scale = diag(d), factor = NULL, control = list(), verbose = FALSE, log = FALSE, ...) pnvmixcopula(upper, lower = matrix(0, nrow = n, ncol = d), qmix, scale = diag(d), control = list(), verbose = FALSE, ...) rnvmixcopula(n, qmix, scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0, control = list(), verbose = FALSE, ...) dStudentcopula(u, df, scale = diag(d), factor = NULL, log = FALSE, verbose = TRUE) pStudentcopula(upper, lower = matrix(0, nrow = n, ncol = d), df, scale = diag(d), control = list(), verbose = TRUE) rStudentcopula(n, df, scale = diag(2), method = c("PRNG", "sobol", "ghalton"), skip = 0) pgStudentcopula(upper, lower = matrix(0, nrow = n, ncol = d), groupings = 1:d, df, scale = diag(d), control = list(), verbose = TRUE) dgStudentcopula(u, groupings = 1:d, df, scale = diag(d), factor = NULL, factor.inv = NULL, control = list(), verbose = TRUE, log = FALSE) rgStudentcopula(n, groupings = 1:d, df, scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0) fitgStudentcopula(x, u, df.init = NULL, scale = NULL, groupings = rep(1, d), df.bounds = c(0.5, 30), fit.method = c("joint-MLE", "groupewise-MLE"), control = list(), verbose = TRUE) fitStudentcopula(u, fit.method = c("Moment-MLE", "EM-MLE", "Full-MLE"), df.init = NULL, df.bounds = c(0.1, 30), control = list(), verbose = TRUE)dnvmixcopula(u, qmix, scale = diag(d), factor = NULL, control = list(), verbose = FALSE, log = FALSE, ...) pnvmixcopula(upper, lower = matrix(0, nrow = n, ncol = d), qmix, scale = diag(d), control = list(), verbose = FALSE, ...) rnvmixcopula(n, qmix, scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0, control = list(), verbose = FALSE, ...) dStudentcopula(u, df, scale = diag(d), factor = NULL, log = FALSE, verbose = TRUE) pStudentcopula(upper, lower = matrix(0, nrow = n, ncol = d), df, scale = diag(d), control = list(), verbose = TRUE) rStudentcopula(n, df, scale = diag(2), method = c("PRNG", "sobol", "ghalton"), skip = 0) pgStudentcopula(upper, lower = matrix(0, nrow = n, ncol = d), groupings = 1:d, df, scale = diag(d), control = list(), verbose = TRUE) dgStudentcopula(u, groupings = 1:d, df, scale = diag(d), factor = NULL, factor.inv = NULL, control = list(), verbose = TRUE, log = FALSE) rgStudentcopula(n, groupings = 1:d, df, scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0) fitgStudentcopula(x, u, df.init = NULL, scale = NULL, groupings = rep(1, d), df.bounds = c(0.5, 30), fit.method = c("joint-MLE", "groupewise-MLE"), control = list(), verbose = TRUE) fitStudentcopula(u, fit.method = c("Moment-MLE", "EM-MLE", "Full-MLE"), df.init = NULL, df.bounds = c(0.1, 30), control = list(), verbose = TRUE)
u |
|
upper, lower
|
|
n |
sample size |
qmix |
specification of the mixing variable |
groupings |
see |
df |
positive degress of freedom; can also be |
scale |
scale matrix (a covariance matrix entering the
distribution as a parameter) of dimension |
factor |
|
factor.inv |
inverse of |
method |
see |
skip |
see |
df.init |
|
df.bounds |
|
fit.method |
|
x |
|
control |
|
verbose |
|
log |
|
... |
additional arguments (for example, parameters) passed to the
underlying mixing distribution when |
Functionalities for normal variance mixture copulas provided here
essentially call pnvmix(), dnvmix() and
rnvmix() as well as qnvmix(), see their
documentations for more details.
We remark that computing normal variance mixtures is a challenging
task; evaluating normal variance mixture copulas additionally requires
the approximation of a univariate quantile function so that for large
dimensions and sample sizes, these procedures can be fairly slow. As
there are approximations on many levels, reported error estimates for
the copula versions of pnvmix() and dnvmix() can be
flawed.
The functions [d/p/r]Studentcopula() are user-friendly wrappers for
[d/p/r]nvmixcopula(, qmix = "inverse.gamma"), designed for the imporant
case of a t copula with degrees-of-freedom df.
The function fitgStudentcopula() can be used to estimate the matrix
scale and the degrees-of-freedom for grouped t-copulas. The matrix
scale, if not provided, is estimated non-parametrically. Initial values
for the degrees-of-freedom are estimated for each group separately (by fitting
the corresponding marginal t copula). Using these initial values, the joint
likelihood over all (length(unique(groupings))-many) degrees-of-freedom
parameters is optimized via optim(). For small dimensions,
the results are satisfactory but the optimization becomes extremely challenging
when the dimension is large, so care should be taking when interpreting the
results.
The values returned by dnvmixcopula(), rnvmixcopula() and
pnvmixcopula() are similar to the ones returned by their
non-copula alternatives dnvmix(), rnvmix()
and pnvmix().
The function fitgStudentcopula() returns an S3 object of
class "fitgStudentcopula", basically a list
which contains, among others, the components
dfEstimated degrees-of-freedom for each group.
scaleEstimated or provided scale matrix.
max.llEstimated log-likelihood at reported estimates.
df.initInitial estimate for the degrees-of-freedom.
The methods print() and summary() are defined for the class
"fitgStudentcopula".
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2020), Grouped Normal Variance Mixtures. Risks 8(4), 103.
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
Luo, X. and Shevchenko, P. (2010). The t copula with multiple parameters of degrees of freedom: bivariate characteristics and application to risk management. Quantitative Finance 10(9), 1039-1054.
Daul, S., De Giorgi, E. G., Lindskog, F. and McNeil, A (2003). The grouped t copula with an application to credit risk. Available at SSRN 1358956.
dnvmix(), pnvmix(), qnvmix(),
rnvmix()
## Generate a random correlation matrix in d dimensions d <- 2 # dimension set.seed(42) # for reproducibility rho <- runif(1, min = -1, max = 1) P <- matrix(rho, nrow = d, ncol = d) # build the correlation matrix P diag(P) <- 1 ## Generate two random evaluation points: u <- matrix(runif(2*d), ncol = d) ## We illustrate using a t-copula df = 2.1 ## Define quantile function which is inverse-gamma here: qmix. <- function(u) 1/qgamma(1-u, shape = df/2, rate = df/2) ### Example for dnvmixcopula() #################################################### ## If qmix = "inverse.gamma", dnvmix() calls qt and dt: d1 <- dnvmixcopula(u, qmix = "inverse.gamma", scale = P, df = df) ## Same can be obtained using 'dStudentcopula()' d2 <- dStudentcopula(u, scale = P, df = df) stopifnot(all.equal(d1, d2)) ## Use qmix. to force the algorithm to use a rqmc procedure: d3 <- dnvmixcopula(u, qmix = qmix., scale = P) stopifnot(all.equal(d1, d3, tol = 1e-3, check.attributes = FALSE)) ### Example for pnvmixcopula() #################################################### ## Same logic as above: p1 <- pnvmixcopula(u, qmix = "inverse.gamma", scale = P, df = df) p2 <- pnvmixcopula(u, qmix = qmix., scale = P) stopifnot(all.equal(p1, p2, tol = 1e-3, check.attributes = FALSE)) ### Examples for rnvmixcopula() ################################################### ## Draw random variates and compare n <- 60 set.seed(1) X <- rnvmixcopula(n, qmix = "inverse.gamma", df = df, scale = P) # with scale set.seed(1) X. <- rnvmixcopula(n, qmix = "inverse.gamma", df = df, factor = t(chol(P))) # with factor stopifnot(all.equal(X, X.)) ### Example for the grouped case ################################################## d <- 4 # dimension set.seed(42) # for reproducibility P <- matrix(runif(1, min = -1, max = 1), nrow = d, ncol = d) # build the correlation matrix P diag(P) <- 1 groupings <- c(1, 1, 2, 2) # two groups of size two each df <- c(1, 4) # dof for each of the two groups U <- rgStudentcopula(n, groupings = groupings, df = df, scale = P) (fit <- fitgStudentcopula(u = U, groupings = groupings, verbose = FALSE))## Generate a random correlation matrix in d dimensions d <- 2 # dimension set.seed(42) # for reproducibility rho <- runif(1, min = -1, max = 1) P <- matrix(rho, nrow = d, ncol = d) # build the correlation matrix P diag(P) <- 1 ## Generate two random evaluation points: u <- matrix(runif(2*d), ncol = d) ## We illustrate using a t-copula df = 2.1 ## Define quantile function which is inverse-gamma here: qmix. <- function(u) 1/qgamma(1-u, shape = df/2, rate = df/2) ### Example for dnvmixcopula() #################################################### ## If qmix = "inverse.gamma", dnvmix() calls qt and dt: d1 <- dnvmixcopula(u, qmix = "inverse.gamma", scale = P, df = df) ## Same can be obtained using 'dStudentcopula()' d2 <- dStudentcopula(u, scale = P, df = df) stopifnot(all.equal(d1, d2)) ## Use qmix. to force the algorithm to use a rqmc procedure: d3 <- dnvmixcopula(u, qmix = qmix., scale = P) stopifnot(all.equal(d1, d3, tol = 1e-3, check.attributes = FALSE)) ### Example for pnvmixcopula() #################################################### ## Same logic as above: p1 <- pnvmixcopula(u, qmix = "inverse.gamma", scale = P, df = df) p2 <- pnvmixcopula(u, qmix = qmix., scale = P) stopifnot(all.equal(p1, p2, tol = 1e-3, check.attributes = FALSE)) ### Examples for rnvmixcopula() ################################################### ## Draw random variates and compare n <- 60 set.seed(1) X <- rnvmixcopula(n, qmix = "inverse.gamma", df = df, scale = P) # with scale set.seed(1) X. <- rnvmixcopula(n, qmix = "inverse.gamma", df = df, factor = t(chol(P))) # with factor stopifnot(all.equal(X, X.)) ### Example for the grouped case ################################################## d <- 4 # dimension set.seed(42) # for reproducibility P <- matrix(runif(1, min = -1, max = 1), nrow = d, ncol = d) # build the correlation matrix P diag(P) <- 1 groupings <- c(1, 1, 2, 2) # two groups of size two each df <- c(1, 4) # dof for each of the two groups U <- rgStudentcopula(n, groupings = groupings, df = df, scale = P) (fit <- fitgStudentcopula(u = U, groupings = groupings, verbose = FALSE))
Computation of rank correlation coefficients Spearman's rho and Kendall's tau for grouped normal variance mixture copulas as well as computation of the (lower and upper) tail dependence coefficient of a grouped t copula.
corgnvmix(scale, qmix, method = c("kendall", "spearman"), groupings = 1:2, ellip.kendall = FALSE, control = list(), verbose = TRUE, ...) lambda_gStudent(df, scale, control = list(), verbose = TRUE)corgnvmix(scale, qmix, method = c("kendall", "spearman"), groupings = 1:2, ellip.kendall = FALSE, control = list(), verbose = TRUE, ...) lambda_gStudent(df, scale, control = list(), verbose = TRUE)
scale |
|
qmix |
specification of the mixing variables; see |
method |
|
groupings |
|
ellip.kendall |
|
df |
either scalar or |
control |
|
verbose |
|
... |
additional arguments (for example, parameters) passed
to the underlying mixing distribution when |
For grouped normal variance mixture copulas, including the grouped t,
there is no closed formula for Kendall's tau and Spearman's rho. The function
corgnvmix() approximates these dependence measures by numerically
approximating an integral representation for these measures.
If no grouping is present (i.e., when groupings = rep(1, 2)), the
copula is an elliptical copula for which the formula
holds. This formula holds only approximately in the grouped case; the quality
of the approximation depends on how different the mixing variables for the
two components are. When the mixing distributions are not too far apart and
when the copula parameter is not close to 1, this approximation is “very
accurate“, as demonstrated in Daul et al (2003).
In the ungrouped case, lambda_gStudent() computes the tail dependence
coefficient based on the known formula
2 * pt( -sqrt( (df + 1)*(1 - rho) / (1 + rho)), df = df + 1) for
the tail dependence coefficient of a t copula.
In the grouped case, RQMC methods are used to efficiently approximate the integral given in Eq. (26) of Luo and Shevchenko (2010).
lambda_gStudent() and corgnvmix() return
a numeric -vector with the computed
dependence measure with corresponding attributes
"abs. error" and "rel. error"(error estimates of the RQMC estimator)
and "numiter" (number of iterations).
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2020), Grouped Normal Variance Mixtures. Risks 8(4), 103.
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
Luo, X. and Shevchenko, P. (2010). The t copula with multiple parameters of degrees of freedom: bivariate characteristics and application to risk management. Quantitative Finance 10(9), 1039-1054.
Daul, S., De Giorgi, E. G., Lindskog, F. and McNeil, A (2003). The grouped t copula with an application to credit risk. Available at SSRN 1358956.
dgStudentcopula(), pgStudentcopula(),
rgStudentcopula()
### Examples for corgnvmix() ################################################### ## Create a plot displaying Spearman's rho for a grouped t copula as a function ## of the copula parameter for various choices of the degrees-of-freedom qmix <- "inverse.gamma" df <- matrix( c(1, 2, 1, 5, 1, Inf), ncol = 2, byrow = TRUE) l.df <- nrow(df) scale <- seq(from = 0, to = 1, length.out = 99) set.seed(1) # for reproducibility kendalls <- sapply(seq_len(l.df), function(i) corgnvmix(scale, qmix = qmix, method = "kendall", df = df[i, ])) ## Include the elliptical approximation (exact when df1 = df2) kendall_ell <- corgnvmix(scale, method = "kendall", ellip.kendall = TRUE) ## Plot lgnd <- character(l.df + 1) lgnd[1] <- "elliptical (equal df)" plot(NA, xlim = c(0, 1), ylim = c(0, 1), xlab = expression(rho), ylab = "Kendall's tau") lines(scale, kendall_ell, lty = 1) for(i in 1:l.df){ lines(scale, kendalls[, i], col = i + 1, lty = i + 1) lgnd[i+1] <- paste0("df1 = ", df[i, 1], ", df2 = ", df[i, 2]) } legend("topleft", lgnd, col = 1:(l.df + 1), lty = 1:(l.df + 1), bty = 'n') ### Examples for lambda_gStudent() ############################################# ## Create a plot displaying 'lambda' as a function of the copula parameter ## for various choices of the degrees-of-freedom df <- c(3, 6, 9) df_ <- list( rep(df[1], 2), rep(df[2], 2), rep(df[3], 2), # ungrouped c(df[1], df[2]), c(df[1], df[3]), c(df[2], df[3])) # grouped l.df_ <- length(df_) scale <- seq(from = -0.99, to = 0.99, length.out = 112) # scale parameters set.seed(1) # for reproducibilty lambdas <- sapply(seq_len(l.df_), function(i) lambda_gStudent(df_[[i]], scale = scale)) lgnd <- character(length(df_)) plot(NA, xlim = range(scale), ylim = range(lambdas), xlab = expression(rho), ylab = expression(lambda)) for(i in seq_len(l.df_)){ lines(scale, lambdas[, i], col = i, lty = i) lgnd[i] <- if(df_[[i]][1] == df_[[i]][2]) paste0("df = ", df_[[i]][1]) else paste0("df1 = ", df_[[i]][1], ", df2 = ", df_[[i]][2]) } legend("topleft", lgnd, col = seq_len(l.df_), lty = seq_len(l.df_), bty = 'n') ## If called with 'df' a 1-vector, closed formula for lambda is used => check lambda.true <- sapply(1:3, function(i) lambda_gStudent(df_[[i]][1], scale = scale)) stopifnot(max(abs( lambda.true - lambdas[, 1:3])) < 4e-4)### Examples for corgnvmix() ################################################### ## Create a plot displaying Spearman's rho for a grouped t copula as a function ## of the copula parameter for various choices of the degrees-of-freedom qmix <- "inverse.gamma" df <- matrix( c(1, 2, 1, 5, 1, Inf), ncol = 2, byrow = TRUE) l.df <- nrow(df) scale <- seq(from = 0, to = 1, length.out = 99) set.seed(1) # for reproducibility kendalls <- sapply(seq_len(l.df), function(i) corgnvmix(scale, qmix = qmix, method = "kendall", df = df[i, ])) ## Include the elliptical approximation (exact when df1 = df2) kendall_ell <- corgnvmix(scale, method = "kendall", ellip.kendall = TRUE) ## Plot lgnd <- character(l.df + 1) lgnd[1] <- "elliptical (equal df)" plot(NA, xlim = c(0, 1), ylim = c(0, 1), xlab = expression(rho), ylab = "Kendall's tau") lines(scale, kendall_ell, lty = 1) for(i in 1:l.df){ lines(scale, kendalls[, i], col = i + 1, lty = i + 1) lgnd[i+1] <- paste0("df1 = ", df[i, 1], ", df2 = ", df[i, 2]) } legend("topleft", lgnd, col = 1:(l.df + 1), lty = 1:(l.df + 1), bty = 'n') ### Examples for lambda_gStudent() ############################################# ## Create a plot displaying 'lambda' as a function of the copula parameter ## for various choices of the degrees-of-freedom df <- c(3, 6, 9) df_ <- list( rep(df[1], 2), rep(df[2], 2), rep(df[3], 2), # ungrouped c(df[1], df[2]), c(df[1], df[3]), c(df[2], df[3])) # grouped l.df_ <- length(df_) scale <- seq(from = -0.99, to = 0.99, length.out = 112) # scale parameters set.seed(1) # for reproducibilty lambdas <- sapply(seq_len(l.df_), function(i) lambda_gStudent(df_[[i]], scale = scale)) lgnd <- character(length(df_)) plot(NA, xlim = range(scale), ylim = range(lambdas), xlab = expression(rho), ylab = expression(lambda)) for(i in seq_len(l.df_)){ lines(scale, lambdas[, i], col = i, lty = i) lgnd[i] <- if(df_[[i]][1] == df_[[i]][2]) paste0("df = ", df_[[i]][1]) else paste0("df1 = ", df_[[i]][1], ", df2 = ", df_[[i]][2]) } legend("topleft", lgnd, col = seq_len(l.df_), lty = seq_len(l.df_), bty = 'n') ## If called with 'df' a 1-vector, closed formula for lambda is used => check lambda.true <- sapply(1:3, function(i) lambda_gStudent(df_[[i]][1], scale = scale)) stopifnot(max(abs( lambda.true - lambdas[, 1:3])) < 4e-4)
Evaluating grouped normal variance mixture density functions (including Student t with multiple degrees-of-freedom).
dgnvmix(x, groupings = 1:d, qmix, loc = rep(0, d), scale = diag(d), factor = NULL, factor.inv = NULL, control = list(), log = FALSE, verbose = TRUE, ...) dgStudent(x, groupings = 1:d, df, loc = rep(0, d), scale = diag(d), factor = NULL, factor.inv = NULL, control = list(), log = FALSE, verbose = TRUE)dgnvmix(x, groupings = 1:d, qmix, loc = rep(0, d), scale = diag(d), factor = NULL, factor.inv = NULL, control = list(), log = FALSE, verbose = TRUE, ...) dgStudent(x, groupings = 1:d, df, loc = rep(0, d), scale = diag(d), factor = NULL, factor.inv = NULL, control = list(), log = FALSE, verbose = TRUE)
x |
see |
groupings |
see |
qmix |
specification of the mixing variables |
loc |
see |
scale |
see |
factor |
|
factor.inv |
inverse of |
df |
|
control |
|
log |
|
verbose |
see |
... |
additional arguments (for example, parameters) passed
to the underlying mixing distribution when |
Internally used is factor.inv, so factor and scale are not
required to be provided (but allowed for consistency with other functions in the
package).
dgStudent() is a wrapper of
dgnvmix(, qmix = "inverse.gamma", df = df). If there is no grouping,
the analytical formula for the density of a multivariate t distribution
is used.
Internally, an adaptive randomized Quasi-Monte Carlo (RQMC) approach
is used to estimate the log-density. It is an iterative algorithm that
evaluates the integrand at a randomized Sobol' point-set (default) in
each iteration until the pre-specified error tolerance
control$dnvmix.reltol in the control argument
is reached for the log-density. The attribute
"numiter" gives the worst case number of such iterations needed
(over all rows of x). Note that this function calls underlying
C code.
Algorithm specific parameters (such as above mentioned control$dnvmix.reltol)
can be passed as a list via the control argument,
see get_set_param() for details and defaults.
If the error tolerance cannot be achieved within control$max.iter.rqmc
iterations and fun.eval[2] function evaluations, an additional
warning is thrown if verbose=TRUE.
dgnvmix() and dgStudent() return a
numeric -vector with the computed density values
and corresponding attributes "abs. error" and "rel. error"
(error estimates of the RQMC estimator) and "numiter" (number of iterations).
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2020), Grouped Normal Variance Mixtures. Risks 8(4), 103.
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
rgnvmix(), pgnvmix(), get_set_param()
n <- 100 # sample size to generate evaluation points ### 1. Inverse-gamma mixture ## 1.1. Grouped t with mutliple dof d <- 3 # dimension set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) # random scale matrix df <- c(1.1, 2.4, 4.9) # dof for margin i groupings <- 1:d x <- rgStudent(n, df = df, scale = P) # evaluation points for the density ### Call 'dgnvmix' with 'qmix' a string: set.seed(12) dgt1 <- dgnvmix(x, qmix = "inverse.gamma", df = df, scale = P) ### Version providing quantile functions of the mixing distributions as list qmix_ <- function(u, df) 1 / qgamma(1-u, shape = df/2, rate = df/2) qmix <- list(function(u) qmix_(u, df = df[1]), function(u) qmix_(u, df = df[2]), function(u) qmix_(u, df = df[3])) set.seed(12) dgt2 <- dgnvmix(x, groupings = groupings, qmix = qmix, scale = P) ### Similar, but using ellipsis argument: qmix <- list(function(u, df1) qmix_(u, df1), function(u, df2) qmix_(u, df2), function(u, df3) qmix_(u, df3)) set.seed(12) dgt3 <- dgnvmix(x, groupings = groupings, qmix = qmix, scale = P, df1 = df[1], df2 = df[2], df3 = df[3]) ### Using the wrapper 'dgStudent()' set.seed(12) dgt4 <- dgStudent(x, groupings = groupings, df = df, scale = P) stopifnot(all.equal(dgt1, dgt2, tol = 1e-5, check.attributes = FALSE), all.equal(dgt1, dgt3, tol = 1e-5, check.attributes = FALSE), all.equal(dgt1, dgt4, tol = 1e-5, check.attributes = FALSE)) ## 1.2 Classical multivariate t df <- 2.4 groupings <- rep(1, d) # same df for all components x <- rStudent(n, scale = P, df = df) # evaluation points for the density dt1 <- dStudent(x, scale = P, df = df, log = TRUE) # uses analytical formula ## If 'qmix' provided as string and no grouping, dgnvmix() uses analytical formula dt2 <- dgnvmix(x, qmix = "inverse.gamma", groupings = groupings, df = df, scale = P, log = TRUE) stopifnot(all.equal(dt1, dt2)) ## Provide 'qmix' as a function to force estimation in 'dgnvmix()' dt3 <- dgnvmix(x, qmix = qmix_, groupings = groupings, df = df, scale = P, log = TRUE) stopifnot(all.equal(dt1, dt3, tol = 5e-4, check.attributes = FALSE)) ### 2. More complicated mixutre ## Let W1 ~ IG(1, 1), W2 = 1, W3 ~ Exp(1), W4 ~ Par(2, 1), W5 = W1, all comonotone ## => X1 ~ t_2; X2 ~ normal; X3 ~ Exp-mixture; X4 ~ Par-mixture; X5 ~ t_2 d <- 5 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) b <- 3 * runif(d) * sqrt(d) # random upper limit groupings <- c(1, 2, 3, 4, 1) # since W_5 = W_1 qmix <- list(function(u) qmix_(u, df = 2), function(u) rep(1, length(u)), list("exp", rate=1), function(u) (1-u)^(-1/2)) # length 4 (# of groups) x <- rgnvmix(n, groupings = groupings, qmix = qmix, scale = P) dg <- dgnvmix(x, groupings = groupings, qmix = qmix, scale = P, log = TRUE)n <- 100 # sample size to generate evaluation points ### 1. Inverse-gamma mixture ## 1.1. Grouped t with mutliple dof d <- 3 # dimension set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) # random scale matrix df <- c(1.1, 2.4, 4.9) # dof for margin i groupings <- 1:d x <- rgStudent(n, df = df, scale = P) # evaluation points for the density ### Call 'dgnvmix' with 'qmix' a string: set.seed(12) dgt1 <- dgnvmix(x, qmix = "inverse.gamma", df = df, scale = P) ### Version providing quantile functions of the mixing distributions as list qmix_ <- function(u, df) 1 / qgamma(1-u, shape = df/2, rate = df/2) qmix <- list(function(u) qmix_(u, df = df[1]), function(u) qmix_(u, df = df[2]), function(u) qmix_(u, df = df[3])) set.seed(12) dgt2 <- dgnvmix(x, groupings = groupings, qmix = qmix, scale = P) ### Similar, but using ellipsis argument: qmix <- list(function(u, df1) qmix_(u, df1), function(u, df2) qmix_(u, df2), function(u, df3) qmix_(u, df3)) set.seed(12) dgt3 <- dgnvmix(x, groupings = groupings, qmix = qmix, scale = P, df1 = df[1], df2 = df[2], df3 = df[3]) ### Using the wrapper 'dgStudent()' set.seed(12) dgt4 <- dgStudent(x, groupings = groupings, df = df, scale = P) stopifnot(all.equal(dgt1, dgt2, tol = 1e-5, check.attributes = FALSE), all.equal(dgt1, dgt3, tol = 1e-5, check.attributes = FALSE), all.equal(dgt1, dgt4, tol = 1e-5, check.attributes = FALSE)) ## 1.2 Classical multivariate t df <- 2.4 groupings <- rep(1, d) # same df for all components x <- rStudent(n, scale = P, df = df) # evaluation points for the density dt1 <- dStudent(x, scale = P, df = df, log = TRUE) # uses analytical formula ## If 'qmix' provided as string and no grouping, dgnvmix() uses analytical formula dt2 <- dgnvmix(x, qmix = "inverse.gamma", groupings = groupings, df = df, scale = P, log = TRUE) stopifnot(all.equal(dt1, dt2)) ## Provide 'qmix' as a function to force estimation in 'dgnvmix()' dt3 <- dgnvmix(x, qmix = qmix_, groupings = groupings, df = df, scale = P, log = TRUE) stopifnot(all.equal(dt1, dt3, tol = 5e-4, check.attributes = FALSE)) ### 2. More complicated mixutre ## Let W1 ~ IG(1, 1), W2 = 1, W3 ~ Exp(1), W4 ~ Par(2, 1), W5 = W1, all comonotone ## => X1 ~ t_2; X2 ~ normal; X3 ~ Exp-mixture; X4 ~ Par-mixture; X5 ~ t_2 d <- 5 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) b <- 3 * runif(d) * sqrt(d) # random upper limit groupings <- c(1, 2, 3, 4, 1) # since W_5 = W_1 qmix <- list(function(u) qmix_(u, df = 2), function(u) rep(1, length(u)), list("exp", rate=1), function(u) (1-u)^(-1/2)) # length 4 (# of groups) x <- rgnvmix(n, groupings = groupings, qmix = qmix, scale = P) dg <- dgnvmix(x, groupings = groupings, qmix = qmix, scale = P, log = TRUE)
Evaluating multivariate normal variance mixture densities (including Student t and normal densities).
dnvmix(x, qmix, loc = rep(0, d), scale = diag(d), factor = NULL, control = list(), log = FALSE, verbose = TRUE,...) dStudent(x, df, loc = rep(0, d), scale = diag(d), factor = NULL, log = FALSE, verbose = TRUE, ...) dNorm(x, loc = rep(0, d), scale = diag(d), factor = NULL, log = FALSE, verbose = TRUE, ...)dnvmix(x, qmix, loc = rep(0, d), scale = diag(d), factor = NULL, control = list(), log = FALSE, verbose = TRUE,...) dStudent(x, df, loc = rep(0, d), scale = diag(d), factor = NULL, log = FALSE, verbose = TRUE, ...) dNorm(x, loc = rep(0, d), scale = diag(d), factor = NULL, log = FALSE, verbose = TRUE, ...)
x |
|
qmix |
specification of the mixing variable |
df |
positive degress of freedom; can also be |
loc |
location vector of dimension |
scale |
scale matrix (a covariance matrix entering the
distribution as a parameter) of dimension |
factor |
|
control |
|
log |
|
verbose |
|
... |
additional arguments (for example, parameters)
passed to the underlying mixing distribution when |
For the density to exist, scale must be full rank.
Internally used is factor, so scale is not required
to be provided if factor is given. The default factorization
used to obtain factor is the Cholesky
decomposition via chol().
dStudent() and dNorm() are wrappers of
dnvmix(, qmix = "inverse.gamma", df = df) and
dnvmix(, qmix = "constant"), respectively.
In these cases, dnvmix() uses the analytical formulas for the
density of a multivariate Student t and normal distribution,
respectively.
Internally, an adaptive randomized Quasi-Monte Carlo (RQMC) approach
is used to estimate the log-density. It is an iterative algorithm that
evaluates the integrand at a randomized Sobol' point-set (default) in
each iteration until the pre-specified error tolerance
control$dnvmix.reltol in the control argument
is reached for the log-density. The attribute
"numiter" gives the worst case number of such iterations needed
(over all rows of x). Note that this function calls underlying
C code.
Algorithm specific parameters (such as above mentioned control$dnvmix.reltol)
can be passed as a list via the control argument,
see get_set_param() for details and defaults.
If the error tolerance cannot be achieved within control$max.iter.rqmc
iterations and fun.eval[2] function evaluations, an additional
warning is thrown if verbose=TRUE.
dnvmix(), dStudent() and dNorm() return a
numeric -vector with the computed (log-)density
values and attributes "abs. error" and "rel. error"
(containing the absolute and relative error
estimates of the of the (log-)density) and "numiter"
(containing the number of iterations).
Erik Hintz, Marius Hofert and Christiane Lemieux.
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
pnvmix(), rnvmix(), fitnvmix(),
get_set_param().
### Examples for dnvmix() ###################################################### ## Generate a random correlation matrix in three dimensions d <- 3 set.seed(271) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) ## Evaluate a t_{3.5} density df <- 3.5 x <- matrix(1:12/12, ncol = d) # evaluation points dt1 <- dnvmix(x, qmix = "inverse.gamma", df = df, scale = P) stopifnot(all.equal(dt1, c(0.013266542, 0.011967156, 0.010760575, 0.009648682), tol = 1e-7, check.attributes = FALSE)) ## Here is a version providing the quantile function of the mixing distribution qW <- function(u, df) 1 / qgamma(1-u, shape = df/2, rate = df/2) dt2 <- dnvmix(x, qmix = qW, df = df, scale = P) ## Compare stopifnot(all.equal(dt1, dt2, tol = 5e-4, check.attributes = FALSE)) ## Evaluate a normal density dn <- dnvmix(x, qmix = "constant", scale = P) stopifnot(all.equal(dn, c(0.013083858, 0.011141923, 0.009389987, 0.007831596), tol = 1e-7, check.attributes = FALSE)) ## Case with missing data x. <- x x.[3,2] <- NA x.[4,3] <- NA dt <- dnvmix(x., qmix = "inverse.gamma", df = df, scale = P) stopifnot(is.na(dt) == rep(c(FALSE, TRUE), each = 2)) ## Univariate case x.. <- cbind(1:10/10) # (n = 10, 1)-matrix; vectors are considered rows in dnvmix() dt1 <- dnvmix(x.., qmix = "inverse.gamma", df = df, factor = 1) dt2 <- dt(as.vector(x..), df = df) stopifnot(all.equal(dt1, dt2, check.attributes = FALSE)) ### Examples for dStudent() and dNorm() ######################################## ## Evaluate a t_{3.5} density dt <- dStudent(x, df = df, scale = P) stopifnot(all.equal(dt, c(0.013266542, 0.011967156, 0.010760575, 0.009648682), tol = 1e-7, check.attributes = FALSE)) ## Evaluate a normal density x <- x[1,] # use just the first point this time dn <- dNorm(x, scale = P) stopifnot(all.equal(dn, 0.013083858, tol = 1e-7, check.attributes = FALSE))### Examples for dnvmix() ###################################################### ## Generate a random correlation matrix in three dimensions d <- 3 set.seed(271) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) ## Evaluate a t_{3.5} density df <- 3.5 x <- matrix(1:12/12, ncol = d) # evaluation points dt1 <- dnvmix(x, qmix = "inverse.gamma", df = df, scale = P) stopifnot(all.equal(dt1, c(0.013266542, 0.011967156, 0.010760575, 0.009648682), tol = 1e-7, check.attributes = FALSE)) ## Here is a version providing the quantile function of the mixing distribution qW <- function(u, df) 1 / qgamma(1-u, shape = df/2, rate = df/2) dt2 <- dnvmix(x, qmix = qW, df = df, scale = P) ## Compare stopifnot(all.equal(dt1, dt2, tol = 5e-4, check.attributes = FALSE)) ## Evaluate a normal density dn <- dnvmix(x, qmix = "constant", scale = P) stopifnot(all.equal(dn, c(0.013083858, 0.011141923, 0.009389987, 0.007831596), tol = 1e-7, check.attributes = FALSE)) ## Case with missing data x. <- x x.[3,2] <- NA x.[4,3] <- NA dt <- dnvmix(x., qmix = "inverse.gamma", df = df, scale = P) stopifnot(is.na(dt) == rep(c(FALSE, TRUE), each = 2)) ## Univariate case x.. <- cbind(1:10/10) # (n = 10, 1)-matrix; vectors are considered rows in dnvmix() dt1 <- dnvmix(x.., qmix = "inverse.gamma", df = df, factor = 1) dt2 <- dt(as.vector(x..), df = df) stopifnot(all.equal(dt1, dt2, check.attributes = FALSE)) ### Examples for dStudent() and dNorm() ######################################## ## Evaluate a t_{3.5} density dt <- dStudent(x, df = df, scale = P) stopifnot(all.equal(dt, c(0.013266542, 0.011967156, 0.010760575, 0.009648682), tol = 1e-7, check.attributes = FALSE)) ## Evaluate a normal density x <- x[1,] # use just the first point this time dn <- dNorm(x, scale = P) stopifnot(all.equal(dn, 0.013083858, tol = 1e-7, check.attributes = FALSE))
Functionalities for fitting multivariate normal variance mixtures (in particular also Multivariate t distributions) via an ECME algorithm.
fitnvmix(x, qmix, mix.param.bounds, nu.init = NA, loc = NULL, scale = NULL, init.size.subsample = min(n, 100), size.subsample = n, control = list(), verbose = TRUE) fitStudent(x, loc = NULL, scale = NULL, mix.param.bounds = c(1e-3, 1e2), ...) fitNorm(x)fitnvmix(x, qmix, mix.param.bounds, nu.init = NA, loc = NULL, scale = NULL, init.size.subsample = min(n, 100), size.subsample = n, control = list(), verbose = TRUE) fitStudent(x, loc = NULL, scale = NULL, mix.param.bounds = c(1e-3, 1e2), ...) fitNorm(x)
x |
|
qmix |
specification of the mixing variable
|
mix.param.bounds |
either |
nu.init |
either |
loc |
|
scale |
positive definite |
init.size.subsample |
|
size.subsample |
|
control |
|
verbose |
|
... |
additional arguments passed to the underlying
|
The function fitnvmix() uses an ECME algorithm to approximate the
MLEs of the parameters nu, loc and scale of a
normal variance mixture specified by qmix. The underlying
procedure successively estimates nu (with given loc and
scale) by maximizing the likelihood which is approximated by
dnvmix() (unless qmix is a character
string, in which case analytical formulas for the log-densities are
used) and scale and loc (given nu) using weights
(which again need to be approximated) related to the posterior
distribution, details can be found in the first reference below.
It should be highlighted that (unless unless qmix is a
character string), every log-likelihood and every weight needed
in the estimation is numerically approximated via RQMC methods. For
large dimensions and sample sizes this procedure can therefore be
slow.
Various tolerances and convergence criteria can be changed by the user
via the control argument. For more details, see
get_set_param().
The function fitnvmix() returns an S3 object of
class "fitnvmix", basically a list
which contains, among others, the components
nuEstimated mixing parameter (vector) nu.
locEstimated or provided loc vector.
scaleEstimated or provided scale matrix.
max.llEstimated log-likelihood at reported estimates.
xInput data matrix x.
The methods print(), summary() and plot() are defined
for the class "fitnvmix".
fitStudent() is a wrapper to fitnvmix() for parameter
estimation of multivariate Student t distributions; it also
returns an S3 object of class "fitnvmix" where
the fitted degrees of freedom are called "df" instead of
"nu" (to be consistent
with the other wrappers for the Student t distributions).
fitNorm() just returns a list with components
loc (columnwise sample means) and scale (sample
covariance matrix).
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
Liu, C. and Rubin, D. (1994). The ECME algorithm: a simple extension of EM and ECM with faster monotone convergence. Biometrika 81(4), 633–648.
dnvmix(), rnvmix(), pnvmix(),
qqplot_maha(), get_set_param().
## Sampling parameters set.seed(274) # for reproducibility nu <- 2.8 # parameter used to sample data d <- 4 # dimension n <- 75 # small sample size to have examples run fast loc <- rep(0, d) # location vector A <- matrix(runif(d * d), ncol = d) diag_vars <- diag(runif(d, min = 2, max = 5)) scale <- diag_vars %*% cov2cor(A %*% t(A)) %*% diag_vars # scale matrix mix.param.bounds <- c(1, 5) # nu in [1, 5] ### Example 1: Fitting a multivariate t distribution ########################### if(FALSE){ ## Define 'qmix' as the quantile function of an IG(nu/2, nu/2) distribution qmix <- function(u, nu) 1 / qgamma(1 - u, shape = nu/2, rate = nu/2) ## Sample data using 'rnvmix' x <- rnvmix(n, qmix = qmix, nu = nu, loc = loc, scale = scale) ## Call 'fitvnmix' with 'qmix' as a function (so all densities/weights are estimated) (MyFit11 <- fitnvmix(x, qmix = qmix, mix.param.bounds = mix.param.bounds)) ## Call 'fitnvmix' with 'qmix = "inverse.gamma"' in which case analytical formulas ## for weights and densities are used: (MyFit12 <- fitnvmix(x, qmix = "inverse.gamma", mix.param.bounds = mix.param.bounds)) ## Alternatively, use the wrapper 'fitStudent()' (MyFit13 <- fitStudent(x)) ## Check stopifnot(all.equal(MyFit11$nu, MyFit12$nu, tol = 5e-2), all.equal(MyFit11$nu, MyFit13$nu, tol = 5e-2)) ## Can also provide 'loc' and 'scale' in which case only 'nu' is estimated (MyFit13 <- fitnvmix(x, qmix = "inverse.gamma", mix.param.bounds = mix.param.bounds, loc = loc, scale = scale)) (MyFit14 <- fitStudent(x, loc = loc, scale = scale)) stopifnot(all.equal(MyFit13$nu, MyFit14$df, tol = 1e-6)) } ### Example 2: Fitting a Pareto mixture ######################################## ## Define 'qmix' as the quantile function of a Par(nu, 1) distribution qmix <- function(u, nu) (1-u)^(-1/nu) ## Sample data using 'rnvmix': x <- rnvmix(n, qmix = qmix, nu = nu, loc = loc, scale = scale) ## Call 'fitvnmix' with 'qmix' as function (=> densities/weights estimated) (MyFit21 <- fitnvmix(x, qmix = qmix, mix.param.bounds = mix.param.bounds)) ## Call 'fitnvmix' with 'qmix = "pareto"' in which case an analytical formula ## for the density is used (MyFit22 <- fitnvmix(x, qmix = "pareto", mix.param.bounds = mix.param.bounds)) stopifnot(all.equal(MyFit21$nu, MyFit22$nu, tol = 5e-2))## Sampling parameters set.seed(274) # for reproducibility nu <- 2.8 # parameter used to sample data d <- 4 # dimension n <- 75 # small sample size to have examples run fast loc <- rep(0, d) # location vector A <- matrix(runif(d * d), ncol = d) diag_vars <- diag(runif(d, min = 2, max = 5)) scale <- diag_vars %*% cov2cor(A %*% t(A)) %*% diag_vars # scale matrix mix.param.bounds <- c(1, 5) # nu in [1, 5] ### Example 1: Fitting a multivariate t distribution ########################### if(FALSE){ ## Define 'qmix' as the quantile function of an IG(nu/2, nu/2) distribution qmix <- function(u, nu) 1 / qgamma(1 - u, shape = nu/2, rate = nu/2) ## Sample data using 'rnvmix' x <- rnvmix(n, qmix = qmix, nu = nu, loc = loc, scale = scale) ## Call 'fitvnmix' with 'qmix' as a function (so all densities/weights are estimated) (MyFit11 <- fitnvmix(x, qmix = qmix, mix.param.bounds = mix.param.bounds)) ## Call 'fitnvmix' with 'qmix = "inverse.gamma"' in which case analytical formulas ## for weights and densities are used: (MyFit12 <- fitnvmix(x, qmix = "inverse.gamma", mix.param.bounds = mix.param.bounds)) ## Alternatively, use the wrapper 'fitStudent()' (MyFit13 <- fitStudent(x)) ## Check stopifnot(all.equal(MyFit11$nu, MyFit12$nu, tol = 5e-2), all.equal(MyFit11$nu, MyFit13$nu, tol = 5e-2)) ## Can also provide 'loc' and 'scale' in which case only 'nu' is estimated (MyFit13 <- fitnvmix(x, qmix = "inverse.gamma", mix.param.bounds = mix.param.bounds, loc = loc, scale = scale)) (MyFit14 <- fitStudent(x, loc = loc, scale = scale)) stopifnot(all.equal(MyFit13$nu, MyFit14$df, tol = 1e-6)) } ### Example 2: Fitting a Pareto mixture ######################################## ## Define 'qmix' as the quantile function of a Par(nu, 1) distribution qmix <- function(u, nu) (1-u)^(-1/nu) ## Sample data using 'rnvmix': x <- rnvmix(n, qmix = qmix, nu = nu, loc = loc, scale = scale) ## Call 'fitvnmix' with 'qmix' as function (=> densities/weights estimated) (MyFit21 <- fitnvmix(x, qmix = qmix, mix.param.bounds = mix.param.bounds)) ## Call 'fitnvmix' with 'qmix = "pareto"' in which case an analytical formula ## for the density is used (MyFit22 <- fitnvmix(x, qmix = "pareto", mix.param.bounds = mix.param.bounds)) stopifnot(all.equal(MyFit21$nu, MyFit22$nu, tol = 5e-2))
Evaluating density-, distribution- and quantile-function of Gamma scale mixtures as well as random variate generation.
dgammamix(x, qmix, d, control = list(), verbose = TRUE, log = FALSE, ...) pgammamix(x, qmix, d, lower.tail = TRUE, control = list(), verbose = TRUE, ...) qgammamix(u, qmix, d, control = list(), verbose = TRUE, q.only = TRUE, stored.values = NULL, ...) rgammamix(n, rmix, qmix, d, method = c("PRNG", "sobol", "ghalton"), skip = 0, ...)dgammamix(x, qmix, d, control = list(), verbose = TRUE, log = FALSE, ...) pgammamix(x, qmix, d, lower.tail = TRUE, control = list(), verbose = TRUE, ...) qgammamix(u, qmix, d, control = list(), verbose = TRUE, q.only = TRUE, stored.values = NULL, ...) rgammamix(n, rmix, qmix, d, method = c("PRNG", "sobol", "ghalton"), skip = 0, ...)
x |
|
u |
|
qmix |
see |
rmix |
see |
d |
dimension of the underlying normal variance mixture, see also details below. |
n |
sample size |
lower.tail |
|
log |
|
q.only |
see |
stored.values |
see |
method |
see |
skip |
see |
control |
|
verbose |
|
... |
additional arguments (for example, parameters) passed to
the underlying mixing distribution when |
We define a Gamma mixture as a random variable satisfying,
in distribution, where is
specified via qmix. If follows a dimensional
normal variance mixture, the squared Mahalanobis distance
has the same distribution as
.
The functions presented here are similar to the corresponding
functions for normal variance mixtures (d/p/q/rnvmix()),
details can be found in the corresponding help-files there.
pgammamix() and dgammamix() return
a numeric -vector with the computed
probabilities/densities and corresponding attributes "abs. error"
and "rel. error" (error estimates of the RQMC estimator) and
"numiter" (number of iterations).
If q.only = TRUE, qgammamix() a vector of the same length as
u with entries where satisfies
where the df of the Gamma mixture
specified via qmix; if q.only = FALSE, see qnvmix.
rgammamix() returns a -vector containing
samples of the specified (via mix) Gamma mixture.
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
dnvmix(), pnvmix(), qnvmix(),
rnvmix(), get_set_param(),
qqplot_maha(), fitnvmix()
## Specify inverse-gamma mixture => results in d * F(d, nu) dist'n, ## handled correctly when 'qmix = "inverse.gamma"' is specified qmix <- function(u, nu) 1/qgamma(1 - u, shape = nu/2, rate = nu/2) ## Example for rgammamix() set.seed(271) # for reproducibility n <- 25 nu <- 3 d <- 5 x <- rgammamix(n, qmix = qmix, d = d, nu = nu) ## Evaluate distribution function at 'x' p.true_1 <- pgammamix(x, qmix = "inverse.gamma", d = d, df = nu) # calls pf(...) p.true_2 <- pf(x/d, df1 = d, df2 = nu) p.estim <- pgammamix(x, qmix = qmix, d = d, nu = nu) stopifnot(all.equal(p.true_1, p.true_2, tol = 1e-3, check.attributes = FALSE), all.equal(p.true_1, p.estim, tol = 1e-3, check.attributes = FALSE)) ## Evaluate density function at 'x' d.true_1 <- dgammamix(x, qmix = "inverse.gamma", d = d, df = nu) d.true_2 <- df(x/d, df1 = d, df2 = nu)/d d.est <- dgammamix(x, qmix = qmix, d = d, nu = nu) stopifnot(all.equal(d.true_1, d.true_2, tol = 5e-4, check.attributes = FALSE), all.equal(d.true_1, d.est, tol = 5e-4, check.attributes = FALSE)) ## Evaluate quantile function u <- seq(from = 0.5, to = 0.9, by = 0.1) q.true_1 <- qgammamix(u, qmix = "inverse.gamma", d = d, df = nu) q.true_2 <- qf(u, df1 = d, df2 = nu) * d q.est <- qgammamix(u, qmix = qmix, d = d, nu = nu) stopifnot(all.equal(q.true_1, q.true_2, tol = 5e-4, check.attributes = FALSE), all.equal(q.true_1, q.est, tol = 5e-4, check.attributes = FALSE))## Specify inverse-gamma mixture => results in d * F(d, nu) dist'n, ## handled correctly when 'qmix = "inverse.gamma"' is specified qmix <- function(u, nu) 1/qgamma(1 - u, shape = nu/2, rate = nu/2) ## Example for rgammamix() set.seed(271) # for reproducibility n <- 25 nu <- 3 d <- 5 x <- rgammamix(n, qmix = qmix, d = d, nu = nu) ## Evaluate distribution function at 'x' p.true_1 <- pgammamix(x, qmix = "inverse.gamma", d = d, df = nu) # calls pf(...) p.true_2 <- pf(x/d, df1 = d, df2 = nu) p.estim <- pgammamix(x, qmix = qmix, d = d, nu = nu) stopifnot(all.equal(p.true_1, p.true_2, tol = 1e-3, check.attributes = FALSE), all.equal(p.true_1, p.estim, tol = 1e-3, check.attributes = FALSE)) ## Evaluate density function at 'x' d.true_1 <- dgammamix(x, qmix = "inverse.gamma", d = d, df = nu) d.true_2 <- df(x/d, df1 = d, df2 = nu)/d d.est <- dgammamix(x, qmix = qmix, d = d, nu = nu) stopifnot(all.equal(d.true_1, d.true_2, tol = 5e-4, check.attributes = FALSE), all.equal(d.true_1, d.est, tol = 5e-4, check.attributes = FALSE)) ## Evaluate quantile function u <- seq(from = 0.5, to = 0.9, by = 0.1) q.true_1 <- qgammamix(u, qmix = "inverse.gamma", d = d, df = nu) q.true_2 <- qf(u, df1 = d, df2 = nu) * d q.est <- qgammamix(u, qmix = qmix, d = d, nu = nu) stopifnot(all.equal(q.true_1, q.true_2, tol = 5e-4, check.attributes = FALSE), all.equal(q.true_1, q.est, tol = 5e-4, check.attributes = FALSE))
Algorithm specific parameters for functionalities in the nvmix
package, notably for fitnvmix(), dnvmix(),
pnvmix(), qnvmix(), pgammamix(),
dgammamix() and ES_nvmix() as well as the
corresponding functions for grouped mixtures.
get_set_param(control = list())get_set_param(control = list())
control |
|
For most functions in the nvmix package, internally, an
iterative randomized Quasi-Monte Carlo (RQMC) approach is used to
estimate probabilities, weights and (log-)densities. There are various
parameters of underlying methods than can be changed.
Algorithm specific parameters can be passed as a list via
control. It can contain any of the following:
methodcharacter string indicating the
method to be used to compute the integral. Available are:
"sobol":Sobol' sequence (default),
"ghalton":generalized Halton sequence,
"PRNG":plain Monte Carlo based on a pseudo-random number generator.
incrementcharacter string indicating how
the sample size should be increased in each iteration. Available are:
"doubling":next iteration has as many sample points as all the previous iterations combined,
"num.init":all iterations use an additional
fun.eval[1]-many points (default for most functions).
CI.factormultiplier of the Monte Carlo confidence interval
bounds. The algorithm runs until CI.factor times the estimated
standard error is less than abstol or reltol (whichever
is provided). If CI.factor = 3.5 (the default), one can expect
the actual absolute error to be less than abstol in
99.9% of the cases.
fun.evalnumeric(2) providing the size of
the first point set to be used to estimate integrals
(typically a power of 2) and the maximal number of function
evaluations. fun.eval defaults to c(2^7, 1e12).
max.iter.rqmcnumeric, providing the maximum
number of iterations allowed in the RQMC approach; the default is 15
if increment = "doubling" and 1250 otherwise.
Bnumber of randomizations for obtaining an error estimate
in the RQMC approach; the default is 15.
pnvmix() and pgnvmix():pnvmix.abstol, pnvmix.reltol
non-negative numeric
providing the relative/absolute precision required for the distribution
function. Relative precision via pnvmix.reltol is only used
when pnvmix.abstol = NA; in all other cases, absolute precision
will be used. pnvmix.abstol defaults to 1e-3.
If pnvmix.abstol = 0 and pnvmix.reltol = 0, the algorithm
will typically run until the total number of function evaluations
exceeds fun.eval[2] or until the total number of iterations exeeds
max.iter.rqmc, whichever happens first.
If (so upper has more than
one row), the algorithm runs until the precision requirement is reached
for all probability estimates.
mean.sqrt.mixexpectation of the square root
of the mixing variable . If NULL, it will be estimated via
QMC; this is only needed for determining the reordering of the
integration bounds, so a rather crude approximation is fine.
precondlogical indicating whether
preconditioning is applied, that is, reordering of the integration
variables. If TRUE, integration limits lower, upper
as well as scale
are internally re-ordered in a way such that the overall variance of the
integrand is usually smaller than with the original ordering; this
usually leads smaller run-times.
cholesky.tolnon-negative numeric providing lower threshold
for non-zero elements in the computation of the cholesky factor: If
calculated , the diagonal
element (and all other elements in column ) of the cholesky factor
are set to zero, yielding a singular matrix. cholesky.tol
defaults to 1e-9.
dnvmix() and dgnvmix():dnvmix.reltol, dnvmix.abstol
non-negative
numeric providing the relative/absolute precision for the *log-*
density required. Absolute precision via dnvmix.abstol
is only used when dnvmix.reltol = NA; in all other
cases, relative precision will be used. dnvmix.reltol
defaults to 1e-2.
If dnvmix.reltol=0 and dnvmix.abstol=0, the algorithm
will typically run until the total number of function evaluations exceeds
fun.eval[2] or until the total number of iterations exeeds
max.iter.rqmc, whichever happens first.
If (so x has more than one row), the algorithm runs until
the precision requirement is reached for all log-density estimates.
dnvmix.doAdaptlogical indicating if an adaptive
integration procedure shall be used that only samples in relevant subdomains
of the mixing variable; defaults to TRUE.
dnvmix.max.iter.rqmc.pilotnumeric, providing
the maximum number of unstratified, non-adaptive pilot runs the internal
integration procedure performs. Defaults to 6.
dnvmix.tol.int.lower, dnvmix.order.lower
both numeric and nonnegative. RQMC integration
is only performed where the integrand is > than the maximum of
dnvmix.tol.int.lower and , where
is the theoretical maximum of the integrand and
is the specified dnvmix.order.lower. Default to 1e-100
and 5, respectively.
dnvmix.tol.bisecnumeric vector of
length 3 specifying bisection tolerances in the adaptive RQMC algorithm.
First/second/third element specify the tolerance on , and
the log-integrand and default to 1e-6, 1e-1 and
1e-1, respectively.
dnvmix.max.iter.bisecnumeric, maximum number
of iterations in the internal bisection procedure to find good cutting
points allowed, defaults to 15.
dnvmix.tol.stratlengthnumeric, nonnegative.
If the stratum found by the adaptive integration method has length >
dnvmix.tol.stratlength RQMC integration is used there; otherwise
a crude approximation. Defaults to 1e-50.
fitnvmix():ECMEsteplogical, if TRUE (default),
ECME iteration is performed;
if FALSE, no ECME step is performed so that fitnvmix()
performs between zero and two optimizations over , depending
on laststep.do.nu and whether nu.init was provided.
ECMEstep.do.nulogical, if TRUE
(default), the likelihood is maximized over in each ECME
iteration; if FALSE, this step is omitted.
laststep.do.nulogical, if TRUE
another last maximization of the likelihood over is
performed using all observations after the ECME iterations.
Only makes sense if either ECMEstep.do.nu=FALSE or
if size.subsample is smaller than the number of observations.
Defaults to FALSE.
resamplelogical, if TRUE, a different
subsample of x is taken in each optimization over in
the ECME iterations. Only relevant when size.subsample is
smaller than the number of observations. Defaults to FALSE.
ECME.miniter, ECME.maxiter
numeric
positive, minimum and maximum number
of ECME iterations. Default to 5 and 200, respectively.
max.iter.locscaleupdatenumeric positive.
Maximum number of location-scale updates (while helding fixed)
in each individual ECME iteration; defaults to 50.
weights.reltolnumeric non-negative. Relative
tolerance to estimate internal weights used to update
and estimates in the ECME iterations. Defaults to
1e-2.
weights.interpol.reltolnumeric
non-negative. Some weights can be obtained by interpolating
previously calculated weights; if the maximal relative
interpolation error is smaller than
weights.interpol.reltol, this is done. Defaults to 1e-2.
ECME.rel.conv.tolnumeric(3) vector
specifying relative convergence tolerances for loc, scale
and nu (in this order). Defaults to c(1e-2, 1e-2, 1e-3).
control.optimlist of control parameters
passed to the underlying optim in the initial step as well as
in the ECME iterations. See optim() for details; defaults to
list(maxit=75).
control.optim.laststeplike control.optim;
this list of control arguments is passed to optim in the last-step.
Only relevant when laststep.do.nu = TRUE and defaults to
list() (so no defaults of optim() changed).
qnvmix():max.iter.newtonnumeric, maximum number
of Newton iterations allowed to approximate the quantile; defaults
to 45.
newton.conv.abstolnumeric, convergence
tolerance for the Newton proceudre; convergence is detected once
the difference of estimated quantiles in two successive iterations
is smaller than newton.conv.abstol; defaults to 5e-4.
newton.df.reltolnumeric, relative error
tolerance for estimating the univariate distribution function;
defaults to 2.5e-4.
newton.logdens.abstolnumeric, absolute error
tolerance for the internal estimation of the log-density needed for the
update; defaults to 1e-2.
newton.df.max.iter.rqmcnumeric, maximum
number of iterations to estimate the univariate distribution function
required in the Newton update; defaults to 350. Note that
internally used is increment = "doubling", no matter what.
qqplot_maha():qqplot.df.reltolnumeric, with the same
meaning as newton.df.reltol for the function qnvmix().
Defaults to 5e-3.
ES_nvmix():riskmeasures.abstol, riskmeasures.reltolnumeric, absolute or relative error tolerance for
estimating riskmeasures, notably for ES_nvmix(). By default,
riskmeasures.reltol=5e-2 and riskmeasures.abstol=NA,
so that a relative tolerance is used.
Care should be taken when changing algorithm specific parameters, notably tolerances, as the accuracy of the result is heavily influenced by those.
get_set_param() returns a list with more
than 30 elements specifying algorithm specific parameters for the
functions fitnvmix(), dnvmix(),
pnvmix(), qnvmix(), pgammamix(),
dgammamix() and ES_nvmix(), as well as the
corresponding functions for grouped mixtures such as pgnvmix()
and dgnvmix().
Parameter values passed to get_set_param() via the
control argument overwrite the defaults; for parameters not
specified in the control argument, the default values are being
returned.
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2020), Grouped Normal Variance Mixtures. Risks 8(4), 103.
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
fitnvmix(), dnvmix(),
pnvmix(), qnvmix(), pgammamix(),
dgammamix(), ES_nvmix()
get_set_param() # obtain defaultsget_set_param() # obtain defaults
Plotting parameters for the method plot() of the class
qqplot_maha.
get_set_qqplot_param(plot.pars = list(log = ""))get_set_qqplot_param(plot.pars = list(log = ""))
plot.pars |
|
This function provides a convenient way to set plotting parameters in the
argument plot.pars of the
function qqplot_maha() (more precisely, the underlying
plot() method), such as logarithmic plotting, colors, linetypes and more.
The input list plot.pars can contain any of the following:
logcharacter specifying the logarithmic
axes. Just like for the generic plot, must be one of "",
"x", "y" or "xy".
xlim, ylimThe x- and y-limits for plotting.
xlab, ylabcharacter specifying the x- and
y-axis labels. Default to "Theoretical quantiles" and
"Sample quantiles", respectively.
sub, maincharacter specifying title and subtitle
of the plot; default to "", so no titles.
plot_legend, plot_test, plot_linelogical
specifying if a legend should be plotted; if the test result of
the GoF test should be displayed on the 3rd axis and if the plot should
contain a fitted line. All default to TRUE.
pchspecification of the plotting symbol; see
?points(). Defaults to 1.
lty3-vector containing the specification of
the linetypes for i) the diagonal, ii) the asymptotic CI and iii)
the bootstrap CI; see also ?par(). Defaults to
1:3.
col4-vector specifying the colors to be used
for i) the points in the QQ plot; ii) the diagonal; iii) the asymptotic
CI and iv) the bootstrap CI. Defaults to c("black", "red", "azure4",
"chocolate4").
get_set_qqplot_param() returns a list with 13 elements
that is passed to qqplot_maha(), more specifically, to the
underlying plot() method.
Parameter values passed to get_set_qqplot_param() via the
plot.pars argument overwrite the defaults; for parameters not
specified in the plot.pars argument, the default values are being
returned.
Erik Hintz, Marius Hofert and Christiane Lemieux
get_set_qqplot_param(plot.pars = list()) # obtain defaults ## See ?qqplot_maha() for more examples.get_set_qqplot_param(plot.pars = list()) # obtain defaults ## See ?qqplot_maha() for more examples.
Data generated by the demo('numerical_experiments') of the
nvmix package.
data(numerical_experiments_data, package = "nvmix")data(numerical_experiments_data, package = "nvmix")
A list with 10 elements:
$pnvmix.abserrorsArray as returned by the function
pnvmix_testing_abserr(),
see Section 1.1 of the demo('numerical_experiments').
$pnvmix.t.variancesArray as returned by the function
precond_testing_variance(),
see Section 1.1 of the demo('numerical_experiments').
$pnvmix.t.sobolindArray as returned by the function
pnvmix_estimate_sobolind(),
see Section 1.1 of the demo('numerical_experiments').
$pnvmix.t.timingArray as returned by the function
pnvmix_timing_mvt(),
see Section 1.1 of the demo('numerical_experiments').
$dnvmix.resultsArray as returned by the function
dnvmix_testing(),
see Section 1.2 of the demo('numerical_experiments').
$fitnvmix.resultsArray as returned by the function
fitnvmix_testing(),
see Section 1.3 of the demo('numerical_experiments').
$fit.dj30.anaylyticalArray containing results of
fitnvmix() applied to DJ30 data using analytical
weights/densities, see Section 5 of
demo('numerical_experiments').
$fit.dj30.estimatedArray containing results of
fitnvmix() applied to DJ30 data using estimated
weights/densities, see Section 5 of
demo('numerical_experiments').
$qqplots.dj30Array containing results of qqplot.maha()
applied to DJ30 data, see Section 5 of the demo('numerical_experiments').
$tailprobs.dj30Array containing estimated quantile shortfall
probabilities of models fitted to DJ30 data, see Section 5 of
demo('numerical_experiments').
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Evaluating grouped and generalized multivariate normal variance mixture distribution functions (including Student t with multiple degrees-of-freedom).
pgnvmix(upper, lower = matrix(-Inf, nrow = n, ncol = d), groupings = 1:d, qmix, rmix, loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE, ...) pgStudent(upper, lower = matrix(-Inf, nrow = n, ncol = d), groupings = 1:d, df, loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE)pgnvmix(upper, lower = matrix(-Inf, nrow = n, ncol = d), groupings = 1:d, qmix, rmix, loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE, ...) pgStudent(upper, lower = matrix(-Inf, nrow = n, ncol = d), groupings = 1:d, df, loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE)
upper |
see |
lower |
see |
groupings |
|
qmix |
specification of the mixing variables
|
rmix |
only allowed when |
df |
|
loc |
see |
scale |
see |
standardized |
see |
control |
|
verbose |
see |
... |
additional arguments (for example, parameters) passed
to the underlying mixing distribution when |
One should highlight that evaluating grouped normal variance mixtures is a non-trivial tasks which, at the time of development of nvmix, was not available in R before, not even the special case of a multivariate Student t distribution for non-integer degrees of freedoms, which frequently appears in applications in finance, insurance and risk management after estimating such distributions.
Internally, an iterative randomized Quasi-Monte Carlo (RQMC) approach
is used to estimate the probabilities. It is an iterative algorithm
that evaluates the integrand at a point-set (with size as specified by
control$increment in the control argument) in each
iteration until the pre-specified absolute error tolerance
control$pnvmix.abstol (or relative error tolerance
control$pnvmix.reltol which is used only when
control$pnvmix.abstol = NA) is reached. The attribute
"numiter" gives the number of such iterations needed.
Algorithm specific parameters (such as the above mentioned
control$pnvmix.abstol) can be passed as a list
via control, see get_set_param() for more
details. If specified error tolerances are not reached and
verbose = TRUE, a warning is thrown.
pgStudent() is a wrapper of
pgnvmix(, qmix = "inverse.gamma", df = df).
pgnvmix() and pgStudent() return a
numeric -vector with the computed probabilities
and corresponding attributes "abs. error" and "rel. error"
(error estimates of the RQMC estimator) and "numiter" (number of iterations).
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2020), Grouped Normal Variance Mixtures. Risks 8(4), 103.
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
Genz, A. and Bretz, F. (1999). Numerical computation of multivariate t-probabilities with application to power calculation of multiple contrasts. Journal of Statistical Computation and Simulation 63(4), 103–117.
Genz, A. and Bretz, F. (2002). Comparison of methods for the computation of multivariate t probabilities. Journal of Computational and Graphical Statistics 11(4), 950–971.
rgnvmix(), dgnvmix(), get_set_param()
### Examples for pgnvmix() ##################################################### ## 1. Inverse-gamma mixture (=> distribution is grouped t with mutliple dof) d <- 3 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) a <- -3 * runif(d) * sqrt(d) # random lower limit b <- 3 * runif(d) * sqrt(d) # random upper limit df <- c(1.1, 2.4, 4.9) # dof for margin i groupings <- 1:d ### Call 'pgnvmix' with 'qmix' a string: set.seed(12) (pgt1 <- pgnvmix(b, lower = a, groupings = groupings, qmix = "inverse.gamma", df = df, scale = P)) ### Version providing quantile functions of the mixing distributions as list qmix_ <- function(u, df) 1 / qgamma(1-u, shape = df/2, rate = df/2) qmix <- list(function(u) qmix_(u, df = df[1]), function(u) qmix_(u, df = df[2]), function(u) qmix_(u, df = df[3])) set.seed(12) (pgt2 <- pgnvmix(b, lower = a, groupings = groupings, qmix = qmix, scale = P)) ### Similar, but using ellipsis argument: qmix <- list(function(u, df1) qmix_(u, df1), function(u, df2) qmix_(u, df2), function(u, df3) qmix_(u, df3)) set.seed(12) (pgt3 <- pgnvmix(b, lower = a, groupings = groupings, qmix = qmix, scale = P, df1 = df[1], df2 = df[2], df3 = df[3])) ## Version using the user friendly wrapper 'pgStudent()' set.seed(12) (pgt4 <- pgStudent(b, lower = a, groupings = groupings, scale = P, df = df)) stopifnot(all.equal(pgt1, pgt2, tol = 1e-4, check.attributes = FALSE), all.equal(pgt2, pgt3), all.equal(pgt1, pgt4)) ## 2. More complicated mixutre ## Let W1 ~ IG(1, 1), W2 = 1, W3 ~ Exp(1), W4 ~ Par(2, 1), W5 = W1, all comonotone ## => X1 ~ t_2; X2 ~ normal; X3 ~ Exp-mixture; X4 ~ Par-mixture; X5 ~ t_2 d <- 5 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) b <- 3 * runif(d) * sqrt(d) # random upper limit groupings <- c(1, 2, 3, 4, 1) # since W_5 = W_1 qmix <- list(function(u) qmix_(u, df = 2), function(u) rep(1, length(u)), list("exp", rate=1), function(u) (1-u)^(-1/2)) # length 4 (# of groups) pg1 <- pgnvmix(b, groupings = groupings, qmix = qmix, scale = P) stopifnot(all.equal(pg1, 0.78711, tol = 5e-6, check.attributes = FALSE))### Examples for pgnvmix() ##################################################### ## 1. Inverse-gamma mixture (=> distribution is grouped t with mutliple dof) d <- 3 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) a <- -3 * runif(d) * sqrt(d) # random lower limit b <- 3 * runif(d) * sqrt(d) # random upper limit df <- c(1.1, 2.4, 4.9) # dof for margin i groupings <- 1:d ### Call 'pgnvmix' with 'qmix' a string: set.seed(12) (pgt1 <- pgnvmix(b, lower = a, groupings = groupings, qmix = "inverse.gamma", df = df, scale = P)) ### Version providing quantile functions of the mixing distributions as list qmix_ <- function(u, df) 1 / qgamma(1-u, shape = df/2, rate = df/2) qmix <- list(function(u) qmix_(u, df = df[1]), function(u) qmix_(u, df = df[2]), function(u) qmix_(u, df = df[3])) set.seed(12) (pgt2 <- pgnvmix(b, lower = a, groupings = groupings, qmix = qmix, scale = P)) ### Similar, but using ellipsis argument: qmix <- list(function(u, df1) qmix_(u, df1), function(u, df2) qmix_(u, df2), function(u, df3) qmix_(u, df3)) set.seed(12) (pgt3 <- pgnvmix(b, lower = a, groupings = groupings, qmix = qmix, scale = P, df1 = df[1], df2 = df[2], df3 = df[3])) ## Version using the user friendly wrapper 'pgStudent()' set.seed(12) (pgt4 <- pgStudent(b, lower = a, groupings = groupings, scale = P, df = df)) stopifnot(all.equal(pgt1, pgt2, tol = 1e-4, check.attributes = FALSE), all.equal(pgt2, pgt3), all.equal(pgt1, pgt4)) ## 2. More complicated mixutre ## Let W1 ~ IG(1, 1), W2 = 1, W3 ~ Exp(1), W4 ~ Par(2, 1), W5 = W1, all comonotone ## => X1 ~ t_2; X2 ~ normal; X3 ~ Exp-mixture; X4 ~ Par-mixture; X5 ~ t_2 d <- 5 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) b <- 3 * runif(d) * sqrt(d) # random upper limit groupings <- c(1, 2, 3, 4, 1) # since W_5 = W_1 qmix <- list(function(u) qmix_(u, df = 2), function(u) rep(1, length(u)), list("exp", rate=1), function(u) (1-u)^(-1/2)) # length 4 (# of groups) pg1 <- pgnvmix(b, groupings = groupings, qmix = qmix, scale = P) stopifnot(all.equal(pg1, 0.78711, tol = 5e-6, check.attributes = FALSE))
Evaluating multivariate normal variance mixture distribution functions (including Student t and normal distributions).
pnvmix(upper, lower = matrix(-Inf, nrow = n, ncol = d), qmix, rmix, loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE, ...) pStudent(upper, lower = matrix(-Inf, nrow = n, ncol = d), df, loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE) pNorm(upper, lower = matrix(-Inf, nrow = n, ncol = d), loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE)pnvmix(upper, lower = matrix(-Inf, nrow = n, ncol = d), qmix, rmix, loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE, ...) pStudent(upper, lower = matrix(-Inf, nrow = n, ncol = d), df, loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE) pNorm(upper, lower = matrix(-Inf, nrow = n, ncol = d), loc = rep(0, d), scale = diag(d), standardized = FALSE, control = list(), verbose = TRUE)
upper |
|
lower |
|
qmix, rmix
|
specification of the mixing variable
|
df |
positive degress of freedom; can also be |
loc |
location vector of dimension |
scale |
scale matrix (a covariance matrix entering the
distribution as a parameter) of dimension |
standardized |
|
control |
|
verbose |
|
... |
additional arguments (for example, parameters) passed
to the underlying mixing distribution when |
One should highlight that evaluating normal variance mixtures is a non-trivial tasks which, at the time of development of nvmix, was not available in R before, not even the special case of a multivariate Student t distribution for non-integer degrees of freedom, which frequently appears in applications in finance, insurance and risk management after estimating such distributions.
Note that the procedures call underlying C code. Currently, dimensions
are not supported for the default method
sobol.
Internally, an iterative randomized Quasi-Monte Carlo (RQMC) approach
is used to estimate the probabilities. It is an iterative algorithm
that evaluates the integrand at a point-set (with size as specified by
control$increment in the control argument) in each
iteration until the pre-specified absolute error tolerance
control$pnvmix.abstol (or relative error tolerance
control$pnvmix.reltol which is used only when
control$pnvmix.abstol = NA) is reached. The attribute
"numiter" gives the number of such iterations needed.
Algorithm specific parameters (such as the above mentioned
control$pnvmix.abstol) can be passed as a list
via control, see get_set_param() for more
details. If specified error tolerances are not reached and
verbose = TRUE, a warning is thrown.
If provided scale
is singular, pnvmix() estimates the correct probability but
throws a warning if verbose = TRUE.
It is recommended to supply a quantile function via qmix, if available,
as in this case efficient RQMC methods are used to approximate the probability.
If rmix is provided, internally used is
plain MC integration, typically leading to slower convergence.
If both qmix and rmix are provided, the latter
is ignored.
pStudent() and pNorm() are wrappers of
pnvmix(, qmix = "inverse.gamma", df = df) and
pnvmix(, qmix = "constant"), respectively.
In the univariate case, the functions
pt() and pnorm() are used.
pnvmix(), pStudent() and pNorm() return a
numeric -vector with the computed probabilities
and corresponding attributes "abs. error" and rel. error
(error estimates of the RQMC estimator) and "numiter" (number of iterations).
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
Genz, A. and Bretz, F. (1999). Numerical computation of multivariate t-probabilities with application to power calculation of multiple contrasts. Journal of Statistical Computation and Simulation 63(4), 103–117.
Genz, A. and Bretz, F. (2002). Comparison of methods for the computation of multivariate t probabilities. Journal of Computational and Graphical Statistics 11(4), 950–971.
Genz, A. and Kwong, K. (2000). Numerical evaluation of singular multivariate normal distributions. Journal of Statistical Computation and Simulation 68(1), 1–21.
dnvmix(), rnvmix(), fitnvmix(),
pgnvmix(), get_set_param()
### Examples for pnvmix() ###################################################### ## Generate a random correlation matrix in d dimensions d <- 3 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) ## Evaluate a t_{1/2} distribution function a <- -3 * runif(d) * sqrt(d) # random lower limit b <- 3 * runif(d) * sqrt(d) # random upper limit df <- 1.5 # note that this is *non-integer* set.seed(123) pt1 <- pnvmix(b, lower = a, qmix = "inverse.gamma", df = df, scale = P) ## Here is a version providing the quantile function of the mixing distribution qmix <- function(u, df) 1 / qgamma(1-u, shape = df/2, rate = df/2) mean.sqrt.mix <- sqrt(df) * gamma(df/2) / (sqrt(2) * gamma((df+1) / 2)) set.seed(123) pt2 <- pnvmix(b, lower = a, qmix = qmix, df = df, scale = P, control = list(mean.sqrt.mix = mean.sqrt.mix)) ## Compare stopifnot(all.equal(pt1, pt2, tol = 7e-4, check.attributes = FALSE)) ## mean.sqrt.mix will be approximated by QMC internally if not provided, ## so the results will differ slightly. set.seed(123) pt3 <- pnvmix(b, lower = a, qmix = qmix, df = df, scale = P) stopifnot(all.equal(pt3, pt1, tol = 7e-4, check.attributes = FALSE)) ## Here is a version providing a RNG for the mixing distribution ## Note the significantly larger number of iterations in the attribute 'numiter' ## compared to when 'qmix' was provided (=> plain MC versus RQMC) set.seed(123) pt4 <- pnvmix(b, lower = a, rmix = function(n, df) 1/rgamma(n, shape = df/2, rate = df/2), df = df, scale = P) stopifnot(all.equal(pt4, pt1, tol = 8e-4, check.attributes = FALSE)) ## Case with missing data and a matrix of lower and upper bounds a. <- matrix(rep(a, each = 4), ncol = d) b. <- matrix(rep(b, each = 4), ncol = d) a.[2,1] <- NA b.[3,2] <- NA pt <- pnvmix(b., lower = a., qmix = "inverse.gamma", df = df, scale = P) stopifnot(is.na(pt) == c(FALSE, TRUE, TRUE, FALSE)) ## Case where upper = (Inf,..,Inf) and lower = (-Inf,...,-Inf) stopifnot(all.equal(pnvmix(upper = rep(Inf, d), qmix = "constant"), 1, check.attributes = FALSE)) ## An example with singular scale: A <- matrix( c(1, 0, 0, 0, 2, 1, 0, 0, 3, 0, 0, 0, 4, 1, 0, 1), ncol = 4, nrow = 4, byrow = TRUE) scale <- A%*%t(A) upper <- 2:5 pn <- pnvmix(upper, qmix = "constant", scale = scale) # multivariate normal pt <- pnvmix(upper, qmix = "inverse.gamma", scale = scale, df = df) # multivariate t stopifnot(all.equal(pn, 0.8581, tol = 1e-3, check.attributes = FALSE)) stopifnot(all.equal(pt, 0.7656, tol = 1e-3, check.attributes = FALSE)) ## Evaluate a Exp(1)-mixture ## Specify the mixture distribution parameter rate <- 1.9 # exponential rate parameter ## Method 1: Use R's qexp() function and provide a list as 'mix' set.seed(42) (p1 <- pnvmix(b, lower = a, qmix = list("exp", rate = rate), scale = P)) ## Method 2: Define the quantile function manually (note that ## we do not specify rate in the quantile function here, ## but conveniently pass it via the ellipsis argument) set.seed(42) (p2 <- pnvmix(b, lower = a, qmix = function(u, lambda) -log(1-u)/lambda, scale = P, lambda = rate)) ## Check stopifnot(all.equal(p1, p2)) ### Examples for pStudent() and pNorm() ######################################## ## Evaluate a t_{3.5} distribution function set.seed(271) pt <- pStudent(b, lower = a, df = 3.5, scale = P) stopifnot(all.equal(pt, 0.6180, tol = 7e-5, check.attributes = FALSE)) ## Evaluate a normal distribution function set.seed(271) pn <- pNorm(b, lower = a, scale = P) stopifnot(all.equal(pn, 0.7001, tol = 1e-4, check.attributes = FALSE)) ## pStudent deals correctly with df = Inf: set.seed(123) p.St.dfInf <- pStudent(b, df = Inf, scale = P) set.seed(123) p.Norm <- pNorm(b, scale = P) stopifnot(all.equal(p.St.dfInf, p.Norm, check.attributes = FALSE))### Examples for pnvmix() ###################################################### ## Generate a random correlation matrix in d dimensions d <- 3 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) ## Evaluate a t_{1/2} distribution function a <- -3 * runif(d) * sqrt(d) # random lower limit b <- 3 * runif(d) * sqrt(d) # random upper limit df <- 1.5 # note that this is *non-integer* set.seed(123) pt1 <- pnvmix(b, lower = a, qmix = "inverse.gamma", df = df, scale = P) ## Here is a version providing the quantile function of the mixing distribution qmix <- function(u, df) 1 / qgamma(1-u, shape = df/2, rate = df/2) mean.sqrt.mix <- sqrt(df) * gamma(df/2) / (sqrt(2) * gamma((df+1) / 2)) set.seed(123) pt2 <- pnvmix(b, lower = a, qmix = qmix, df = df, scale = P, control = list(mean.sqrt.mix = mean.sqrt.mix)) ## Compare stopifnot(all.equal(pt1, pt2, tol = 7e-4, check.attributes = FALSE)) ## mean.sqrt.mix will be approximated by QMC internally if not provided, ## so the results will differ slightly. set.seed(123) pt3 <- pnvmix(b, lower = a, qmix = qmix, df = df, scale = P) stopifnot(all.equal(pt3, pt1, tol = 7e-4, check.attributes = FALSE)) ## Here is a version providing a RNG for the mixing distribution ## Note the significantly larger number of iterations in the attribute 'numiter' ## compared to when 'qmix' was provided (=> plain MC versus RQMC) set.seed(123) pt4 <- pnvmix(b, lower = a, rmix = function(n, df) 1/rgamma(n, shape = df/2, rate = df/2), df = df, scale = P) stopifnot(all.equal(pt4, pt1, tol = 8e-4, check.attributes = FALSE)) ## Case with missing data and a matrix of lower and upper bounds a. <- matrix(rep(a, each = 4), ncol = d) b. <- matrix(rep(b, each = 4), ncol = d) a.[2,1] <- NA b.[3,2] <- NA pt <- pnvmix(b., lower = a., qmix = "inverse.gamma", df = df, scale = P) stopifnot(is.na(pt) == c(FALSE, TRUE, TRUE, FALSE)) ## Case where upper = (Inf,..,Inf) and lower = (-Inf,...,-Inf) stopifnot(all.equal(pnvmix(upper = rep(Inf, d), qmix = "constant"), 1, check.attributes = FALSE)) ## An example with singular scale: A <- matrix( c(1, 0, 0, 0, 2, 1, 0, 0, 3, 0, 0, 0, 4, 1, 0, 1), ncol = 4, nrow = 4, byrow = TRUE) scale <- A%*%t(A) upper <- 2:5 pn <- pnvmix(upper, qmix = "constant", scale = scale) # multivariate normal pt <- pnvmix(upper, qmix = "inverse.gamma", scale = scale, df = df) # multivariate t stopifnot(all.equal(pn, 0.8581, tol = 1e-3, check.attributes = FALSE)) stopifnot(all.equal(pt, 0.7656, tol = 1e-3, check.attributes = FALSE)) ## Evaluate a Exp(1)-mixture ## Specify the mixture distribution parameter rate <- 1.9 # exponential rate parameter ## Method 1: Use R's qexp() function and provide a list as 'mix' set.seed(42) (p1 <- pnvmix(b, lower = a, qmix = list("exp", rate = rate), scale = P)) ## Method 2: Define the quantile function manually (note that ## we do not specify rate in the quantile function here, ## but conveniently pass it via the ellipsis argument) set.seed(42) (p2 <- pnvmix(b, lower = a, qmix = function(u, lambda) -log(1-u)/lambda, scale = P, lambda = rate)) ## Check stopifnot(all.equal(p1, p2)) ### Examples for pStudent() and pNorm() ######################################## ## Evaluate a t_{3.5} distribution function set.seed(271) pt <- pStudent(b, lower = a, df = 3.5, scale = P) stopifnot(all.equal(pt, 0.6180, tol = 7e-5, check.attributes = FALSE)) ## Evaluate a normal distribution function set.seed(271) pn <- pNorm(b, lower = a, scale = P) stopifnot(all.equal(pn, 0.7001, tol = 1e-4, check.attributes = FALSE)) ## pStudent deals correctly with df = Inf: set.seed(123) p.St.dfInf <- pStudent(b, df = Inf, scale = P) set.seed(123) p.Norm <- pNorm(b, scale = P) stopifnot(all.equal(p.St.dfInf, p.Norm, check.attributes = FALSE))
Evaluating multivariate normal variance mixture distribution functions (including normal and Student t for non-integer degrees of freedom).
qnvmix(u, qmix, control = list(), verbose = TRUE, q.only = TRUE, stored.values = NULL, ...)qnvmix(u, qmix, control = list(), verbose = TRUE, q.only = TRUE, stored.values = NULL, ...)
u |
vector of probabilities . |
qmix |
specification of the mixing variable |
control |
|
verbose |
|
q.only |
|
stored.values |
|
... |
additional arguments containing parameters of
mixing distributions when |
This function uses a Newton procedure to estimate the quantile of the
specified univariate normal variance mixture distribution. Internally,
a randomized quasi-Monte Carlo (RQMC) approach is used to estimate the
distribution and (log)density function; the method is similar to the
one in pnvmix() and dnvmix(). The result depends
slightly on .random.seed.
Internally, symmetry is used for . Function values
(i.e., df and log-density values) are stored and reused to get good
starting values. These values are returned if q.only = FALSE
and can be re-used by passing it to qnvmix() via the argument
stored.values; this can significantly reduce run-time.
Accuracy and run-time depend on both the magnitude of and on
how heavy the tail of the underlying distributions is. Numerical
instabilities can occur for values of close to 0 or 1,
especially when the tail of the distribution is heavy.
If q.only = FALSE the log-density values of the underlying
distribution evaluated at the estimated quantiles are returned as
well: This can be useful for copula density evaluations where both
quantities are needed.
Underlying algorithm specific parameters can be changed via the control
argument, see get_set_param() for details.
If q.only = TRUE a vector of the same length as u with
entries where satisfies where the univariate df of the normal variance
mixture specified via qmix;
if q.only = FALSE a list of four:
$q:Vector of quantiles,
$log.density:vector log-density values at q,
$computed.values:matrix with 3 columns [x, F(x), logf(x)]; see details above,
$newton.iterations:vector giving the number of Newton
iterations needed for u[i].
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R., and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
## Evaluation points u <- seq(from = 0.05, to = 0.95, by = 0.025) set.seed(271) # for reproducibility ## Evaluate the t_{1.4} quantile function df <- 1.4 qmix. <- function(u) 1/qgamma(1-u, shape = df/2, rate = df/2) ## If qmix = "inverse.gamma", qt() is being called qt1 <- qnvmix(u, qmix = "inverse.gamma", df = df) ## Estimate quantiles (without using qt()) qt1. <- qnvmix(u, qmix = qmix., q.only = FALSE) stopifnot(all.equal(qt1, qt1.$q, tolerance = 2.5e-3)) ## Look at absolute error: abs.error <- abs(qt1 - qt1.$q) plot(u, abs.error, type = "l", xlab = "u", ylab = "Absolute error") ## Now do this again but provide qt1.$stored.values, in which case at most ## one Newton iteration will be needed: qt2 <- qnvmix(u, qmix = qmix., stored.values = qt1.$computed.values, q.only = FALSE) stopifnot(max(qt2$newton.iterations) <= 1)## Evaluation points u <- seq(from = 0.05, to = 0.95, by = 0.025) set.seed(271) # for reproducibility ## Evaluate the t_{1.4} quantile function df <- 1.4 qmix. <- function(u) 1/qgamma(1-u, shape = df/2, rate = df/2) ## If qmix = "inverse.gamma", qt() is being called qt1 <- qnvmix(u, qmix = "inverse.gamma", df = df) ## Estimate quantiles (without using qt()) qt1. <- qnvmix(u, qmix = qmix., q.only = FALSE) stopifnot(all.equal(qt1, qt1.$q, tolerance = 2.5e-3)) ## Look at absolute error: abs.error <- abs(qt1 - qt1.$q) plot(u, abs.error, type = "l", xlab = "u", ylab = "Absolute error") ## Now do this again but provide qt1.$stored.values, in which case at most ## one Newton iteration will be needed: qt2 <- qnvmix(u, qmix = qmix., stored.values = qt1.$computed.values, q.only = FALSE) stopifnot(max(qt2$newton.iterations) <= 1)
Visual goodness-of-fit test for multivariate normal variance mixtures: Plotting squared Mahalanobis distances against their theoretical quantiles.
qqplot_maha(x, qmix, loc, scale, fitnvmix_object, trafo.to.normal = FALSE, test = c("KS.AD", "KS", "AD", "none"), boot.pars = list(B = 500, level = 0.95), plot = TRUE, verbose = TRUE, control = list(), digits = max(3, getOption("digits") - 4), plot.pars = list(), ...)qqplot_maha(x, qmix, loc, scale, fitnvmix_object, trafo.to.normal = FALSE, test = c("KS.AD", "KS", "AD", "none"), boot.pars = list(B = 500, level = 0.95), plot = TRUE, verbose = TRUE, control = list(), digits = max(3, getOption("digits") - 4), plot.pars = list(), ...)
x |
|
qmix |
see |
loc |
see |
scale |
see |
fitnvmix_object |
Optional. Object of class |
trafo.to.normal |
|
test |
|
boot.pars |
|
plot |
|
verbose |
see |
control |
see |
digits |
integer specifying the number of digits of the test statistic and the p-value to be displayed. |
plot.pars |
|
... |
additional arguments (for example, parameters) passed to the
underlying mixing distribution when |
If follows a multivariate normal variance mixture, the distribution of
the Mahalanobis distance
is a gamma mixture whose distribution function can be approximated.
The function qqplot_maha() first estimates the theoretical quantiles
by calling qgammamix() and then plots those against
the empirical squared Mahalanobis distances
from the data in x (with loc and
scale). Furthermore, the function computes
asymptotic standard errors of the sample quantiles by using an asymptotic
normality result for the order statistics which
are used to plot the asymptotic CI; see Fox (2008, p. 35 – 36).+
If boot.pars$B > 1 (which is the default), the function additionally
performs Bootstrap to construct a CI. Note that by default, the plot contains
both the asymptotic and the Bootstrap CI.
Finally, depending on the parameter test, the function performs a
univariate GoF test of the observed Mahalanobis distances as described above.
The test result (i.e., the value of the statistic along with a p-value) are
typically plotted on the second y-axis.
The return object of class "qqplot_maha" contains all computed values
(such as p-value, test-statistics, Bootstrap CIs and more). We highlight that
storing this return object makes the QQ plot
quickly reproducible, as in this case, the theoretical quantiles do not need
to be recomputed.
For changing plotting parameters (such as logarithmic axes or colors)
via the argument plot.pars, see get_set_qqplot_param().
qqplot_maha() (invisibly) returns an object of the class
"qqplot_maha" for which the methods plot() and print()
are defined. The return object contains, among others, the components
maha2Sorted, squared Mahalanobis distances of the data
from loc wrt to scale.
theo_quantThe theoretical quantile function
evaluated at ppoints(length(maha2)).
boot_CI matrix containing the
Bootstrap CIs for the empirical quantiles.
asymptSEvector of length length(maha2)
with estimated, asympotic standard errors for the empirical quantiles.
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
fitnvmix(), get_set_qqplot_param(),
rnvmix(), pnvmix(), dnvmix()
## Sample from a heavy tailed multivariate t and construct QQ plot set.seed(1) d <- 2 n <- 1000 df <- 3.1 rho <- 0.5 loc <- rep(0, d) scale <- matrix(c(1, rho, rho, 1), ncol = 2) qmix <- "inverse.gamma" ## Sample data x <- rnvmix(n, qmix = qmix, loc = loc, scale = scale, df = df) # Construct QQ Plot with 'true' parameters and store result object qq1 <- qqplot_maha(x, qmix = qmix, df = df, loc = loc, scale = scale) ## ... which is an object of class "qqplot_maha" with two methods stopifnot(class(qq1) == "qqplot_maha", "plot.qqplot_maha" %in% methods(plot), "print.qqplot_maha" %in% methods(print)) plot(qq1) # reproduce the plot plot(qq1, plotpars = list(log = "xy")) # we can also plot on log-log scale ## In fact, with the 'plotpars' argument, we can change a lot of things plot(qq1, plotpars = list(col = rep("black", 4), lty = 4:6, pch = "*", plot_test = FALSE, main = "Same with smaller y limits", sub = "MySub", xlab = "MyXlab", ylim = c(0, 1.5e3))) ## What about estimated parameters? myfit <- fitStudent(x) ## We can conveniently pass 'myfit', rather than specifying 'x', 'loc', ... set.seed(1) qq2.1 <- qqplot_maha(fitnvmix_object = myfit, test = "AD", trafo_to_normal = TRUE) set.seed(1) qq2.2 <- qqplot_maha(x, qmix = "inverse.gamma", loc = myfit$loc, scale = myfit$scale, df = myfit$df, test = "AD", trafo_to_normal = TRUE) stopifnot(all.equal(qq2.1$boot_CI, qq2.2$boot_CI)) # check qq2.2 # it mentions here that the Maha distances were transformed to normal ## Another example where 'qmix' is a function, so quantiles are internally ## estimated via 'qgammamix()' n <- 15 # small sample size to have examples run fast ## Define the quantile function of an IG(nu/2, nu/2) distribution qmix <- function(u, df) 1 / qgamma(1 - u, shape = df/2, rate = df/2) ## Sample data x <- rnvmix(n, qmix = qmix, df = df, loc = loc, scale = scale) ## QQ Plot of empirical quantiles vs true quantiles, all values estimated ## via RQMC: set.seed(1) qq3.1 <- qqplot_maha(x, qmix = qmix, loc = loc, scale = scale, df = df) ## Same could be obtained by specifying 'qmix' as string in which case ## qqplot_maha() calls qf() set.seed(1) qq3.2 <- qqplot_maha(x, qmix = "inverse.gamma", loc = loc, scale = scale, df = df)## Sample from a heavy tailed multivariate t and construct QQ plot set.seed(1) d <- 2 n <- 1000 df <- 3.1 rho <- 0.5 loc <- rep(0, d) scale <- matrix(c(1, rho, rho, 1), ncol = 2) qmix <- "inverse.gamma" ## Sample data x <- rnvmix(n, qmix = qmix, loc = loc, scale = scale, df = df) # Construct QQ Plot with 'true' parameters and store result object qq1 <- qqplot_maha(x, qmix = qmix, df = df, loc = loc, scale = scale) ## ... which is an object of class "qqplot_maha" with two methods stopifnot(class(qq1) == "qqplot_maha", "plot.qqplot_maha" %in% methods(plot), "print.qqplot_maha" %in% methods(print)) plot(qq1) # reproduce the plot plot(qq1, plotpars = list(log = "xy")) # we can also plot on log-log scale ## In fact, with the 'plotpars' argument, we can change a lot of things plot(qq1, plotpars = list(col = rep("black", 4), lty = 4:6, pch = "*", plot_test = FALSE, main = "Same with smaller y limits", sub = "MySub", xlab = "MyXlab", ylim = c(0, 1.5e3))) ## What about estimated parameters? myfit <- fitStudent(x) ## We can conveniently pass 'myfit', rather than specifying 'x', 'loc', ... set.seed(1) qq2.1 <- qqplot_maha(fitnvmix_object = myfit, test = "AD", trafo_to_normal = TRUE) set.seed(1) qq2.2 <- qqplot_maha(x, qmix = "inverse.gamma", loc = myfit$loc, scale = myfit$scale, df = myfit$df, test = "AD", trafo_to_normal = TRUE) stopifnot(all.equal(qq2.1$boot_CI, qq2.2$boot_CI)) # check qq2.2 # it mentions here that the Maha distances were transformed to normal ## Another example where 'qmix' is a function, so quantiles are internally ## estimated via 'qgammamix()' n <- 15 # small sample size to have examples run fast ## Define the quantile function of an IG(nu/2, nu/2) distribution qmix <- function(u, df) 1 / qgamma(1 - u, shape = df/2, rate = df/2) ## Sample data x <- rnvmix(n, qmix = qmix, df = df, loc = loc, scale = scale) ## QQ Plot of empirical quantiles vs true quantiles, all values estimated ## via RQMC: set.seed(1) qq3.1 <- qqplot_maha(x, qmix = qmix, loc = loc, scale = scale, df = df) ## Same could be obtained by specifying 'qmix' as string in which case ## qqplot_maha() calls qf() set.seed(1) qq3.2 <- qqplot_maha(x, qmix = "inverse.gamma", loc = loc, scale = scale, df = df)
Generate vectors of random variates from grouped normal variance mixtures (including Student t with multiple degrees-of-freedom).
rgnvmix(n, qmix, groupings = 1:d, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0, ...) rgStudent(n, groupings = 1:d, df, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0)rgnvmix(n, qmix, groupings = 1:d, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0, ...) rgStudent(n, groupings = 1:d, df, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0)
n |
sample size |
qmix |
specification of the mixing variables |
groupings |
|
df |
|
loc |
see |
scale |
see |
factor |
see |
method |
see |
skip |
see |
... |
additional arguments (for example, parameters) passed to
the underlying mixing distribution when |
Internally used is factor, so scale is not required
to be provided if factor is given.
The default factorization used to obtain factor is the Cholesky
decomposition via chol(). To this end, scale
needs to have full rank.
rgStudent() is a wrapper of
rgnvmix(, qmix = "inverse.gamma", df = df).
rgnvmix() returns an -matrix
containing samples of the specified (via qmix)
-dimensional grouped normal variance mixture with
location vector loc and scale matrix scale
(a covariance matrix).
rgStudent() returns samples from the -dimensional
multivariate t distribution with multiple degrees-of-freedom
specified by df, location vector
loc and scale matrix scale.
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2020), Grouped Normal Variance Mixtures. Risks 8(4), 103.
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
n <- 1000 # sample size ## Generate a random correlation matrix in d dimensions d <- 2 set.seed(157) A <- matrix(runif(d * d), ncol = d) scale <- cov2cor(A %*% t(A)) ## Example 1: Exponential mixture ## Let W_1 ~ Exp(1), W_2 ~ Exp(10) rates <- c(1, 10) #qmix <- list(list("exp", rate = rates[1]), list("exp", rate = rates[2])) qmix <- lapply(1:2, function(i) list("exp", rate = rates[i])) set.seed(1) X.exp1 <- rgnvmix(n, qmix = qmix, scale = scale) ## For comparison, consider NVM distribution with W ~ Exp(1) set.seed(1) X.exp2 <- rnvmix(n, qmix = list("exp", rate = rates[1]), scale = scale) ## Plot both samples with the same axes opar <- par(no.readonly = TRUE) par(mfrow=c(1,2)) plot(X.exp1, xlim = range(X.exp1, X.exp2), ylim = range(X.exp1, X.exp2), xlab = expression(X[1]), ylab = expression(X[2])) mtext("Two groups with rates 1 and 10") plot(X.exp2, xlim = range(X.exp1, X.exp2), ylim = range(X.exp1, X.exp2), xlab = expression(X[1]), ylab = expression(X[2])) mtext("One group with rate 1") par(opar) ## Example 2: Exponential + Inverse-gamma mixture ## Let W_1 ~ Exp(1), W_2 ~ IG(1.5, 1.5) (=> X_2 ~ t_3 marginally) df <- 3 qmix <- list(list("exp", rate = rates[1]), function(u, df) 1/qgamma(1-u, shape = df/2, rate = df/2)) set.seed(1) X.mix1 <- rgnvmix(n, qmix = qmix, scale = scale, df = df) plot(X.mix1, xlab = expression(X[1]), ylab = expression(X[2])) ## Example 3: Mixtures in d > 2 d <- 5 set.seed(157) A <- matrix(runif(d * d), ncol = d) scale <- cov2cor(A %*% t(A)) ## Example 3.1: W_i ~ Exp(i), i = 1,...,d qmix <- lapply(1:d, function(i) list("exp", rate = i)) set.seed(1) X.mix2 <- rgnvmix(n, qmix = qmix, scale = scale) ## Example 3.2: W_1, W_2 ~ Exp(1), W_3, W_4, W_5 ~ Exp(2) ## => 2 groups, so we need two elements in 'qmix' qmix <- lapply(1:2, function(i) list("exp", rate = i)) groupings <- c(1, 1, 2, 2, 2) set.seed(1) X.mix3 <- rgnvmix(n, qmix = qmix, groupings = groupings, scale = scale) ## Example 3.3: W_1, W_3 ~ IG(1, 1), W_2, W_4 ~ IG(2, 2), W_5 = 1 ## => X_1, X_3 ~ t_2; X_2, X_4 ~ t_4, X_5 ~ N(0, 1) qmix <- list(function(u, df1) 1/qgamma(1-u, shape = df1/2, rate = df1/2), function(u, df2) 1/qgamma(1-u, shape = df2/2, rate = df2/2), function(u) rep(1, length(u))) groupings = c(1, 2, 1, 2, 3) df = c(2, 4, Inf) set.seed(1) X.t1 <- rgnvmix(n, qmix = qmix, groupings = groupings, scale = scale, df1 = df[1], df2 = df[2]) ## This is equivalent to calling 'rgnmvix' with 'qmix = "inverse.gamma"' set.seed(1) X.t2 <- rgnvmix(n, qmix = "inverse.gamma", groupings = groupings, scale = scale, df = df) ## Alternatively, one can use the user friendly wrapper 'rgStudent()' set.seed(1) X.t3 <- rgStudent(n, df = df, groupings = groupings, scale = scale) stopifnot(all.equal(X.t1, X.t2), all.equal(X.t1, X.t3))n <- 1000 # sample size ## Generate a random correlation matrix in d dimensions d <- 2 set.seed(157) A <- matrix(runif(d * d), ncol = d) scale <- cov2cor(A %*% t(A)) ## Example 1: Exponential mixture ## Let W_1 ~ Exp(1), W_2 ~ Exp(10) rates <- c(1, 10) #qmix <- list(list("exp", rate = rates[1]), list("exp", rate = rates[2])) qmix <- lapply(1:2, function(i) list("exp", rate = rates[i])) set.seed(1) X.exp1 <- rgnvmix(n, qmix = qmix, scale = scale) ## For comparison, consider NVM distribution with W ~ Exp(1) set.seed(1) X.exp2 <- rnvmix(n, qmix = list("exp", rate = rates[1]), scale = scale) ## Plot both samples with the same axes opar <- par(no.readonly = TRUE) par(mfrow=c(1,2)) plot(X.exp1, xlim = range(X.exp1, X.exp2), ylim = range(X.exp1, X.exp2), xlab = expression(X[1]), ylab = expression(X[2])) mtext("Two groups with rates 1 and 10") plot(X.exp2, xlim = range(X.exp1, X.exp2), ylim = range(X.exp1, X.exp2), xlab = expression(X[1]), ylab = expression(X[2])) mtext("One group with rate 1") par(opar) ## Example 2: Exponential + Inverse-gamma mixture ## Let W_1 ~ Exp(1), W_2 ~ IG(1.5, 1.5) (=> X_2 ~ t_3 marginally) df <- 3 qmix <- list(list("exp", rate = rates[1]), function(u, df) 1/qgamma(1-u, shape = df/2, rate = df/2)) set.seed(1) X.mix1 <- rgnvmix(n, qmix = qmix, scale = scale, df = df) plot(X.mix1, xlab = expression(X[1]), ylab = expression(X[2])) ## Example 3: Mixtures in d > 2 d <- 5 set.seed(157) A <- matrix(runif(d * d), ncol = d) scale <- cov2cor(A %*% t(A)) ## Example 3.1: W_i ~ Exp(i), i = 1,...,d qmix <- lapply(1:d, function(i) list("exp", rate = i)) set.seed(1) X.mix2 <- rgnvmix(n, qmix = qmix, scale = scale) ## Example 3.2: W_1, W_2 ~ Exp(1), W_3, W_4, W_5 ~ Exp(2) ## => 2 groups, so we need two elements in 'qmix' qmix <- lapply(1:2, function(i) list("exp", rate = i)) groupings <- c(1, 1, 2, 2, 2) set.seed(1) X.mix3 <- rgnvmix(n, qmix = qmix, groupings = groupings, scale = scale) ## Example 3.3: W_1, W_3 ~ IG(1, 1), W_2, W_4 ~ IG(2, 2), W_5 = 1 ## => X_1, X_3 ~ t_2; X_2, X_4 ~ t_4, X_5 ~ N(0, 1) qmix <- list(function(u, df1) 1/qgamma(1-u, shape = df1/2, rate = df1/2), function(u, df2) 1/qgamma(1-u, shape = df2/2, rate = df2/2), function(u) rep(1, length(u))) groupings = c(1, 2, 1, 2, 3) df = c(2, 4, Inf) set.seed(1) X.t1 <- rgnvmix(n, qmix = qmix, groupings = groupings, scale = scale, df1 = df[1], df2 = df[2]) ## This is equivalent to calling 'rgnmvix' with 'qmix = "inverse.gamma"' set.seed(1) X.t2 <- rgnvmix(n, qmix = "inverse.gamma", groupings = groupings, scale = scale, df = df) ## Alternatively, one can use the user friendly wrapper 'rgStudent()' set.seed(1) X.t3 <- rgStudent(n, df = df, groupings = groupings, scale = scale) stopifnot(all.equal(X.t1, X.t2), all.equal(X.t1, X.t3))
Estimation of value-at-risk and expected shortfall for univariate normal variance mixtures
VaR_nvmix(level, qmix, loc = 0, scale = 1, control = list(), verbose = TRUE, ...) ES_nvmix(level, qmix, loc = 0, scale = 1, control = list(), verbose = TRUE, ...)VaR_nvmix(level, qmix, loc = 0, scale = 1, control = list(), verbose = TRUE, ...) ES_nvmix(level, qmix, loc = 0, scale = 1, control = list(), verbose = TRUE, ...)
level |
|
qmix |
see |
loc |
|
scale |
|
control |
|
verbose |
|
... |
additional arguments (for example, parameters) passed to
the underlying mixing distribution when |
VaR_nvmix calls qnvmix().
The function ES_nvmix() estimates the expected shortfall using a
randomized quasi Monte Carlo procedure by sampling from the mixing variable
specified via qmix and and using the identity
where denotes the
density of a standard normal distribution.
Algorithm specific paramaters (such as tolerances) can be conveniently passed
via the control argument, see get_set_param() for more
details.
VaR_nvmix() and ES_nvmix() return
a numeric -vector with the computed
risk measures and in case of ES_nvmix() corresponding attributes
"abs. error" and "rel. error"(error estimates of the RQMC estimator)
and "numiter" (number of iterations).
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
dnvmix(), pnvmix(), qnvmix(),
rnvmix(), get_set_param()
## Example for inverse-gamma mixture (resulting in a t distribution) for ## which the expected shortfall admits a closed formula set.seed(42) # reproducibility level <- seq(from = 0.9, to = 0.95, by = 0.01) df <- 4 ## If 'qmix' is provided as string, ES_nvmix() uses the closed formula ES1 <- ES_nvmix(level, qmix = "inverse.gamma", df = df) ## If 'qmix' is provided as function, the expected shortfall is estimated ES2 <- ES_nvmix(level, qmix = function(u, df) 1/qgamma(1-u, shape = df/2, rate = df/2), df = df) stopifnot(all.equal(ES1, ES2, tol = 1e-2, check.attributes = FALSE))## Example for inverse-gamma mixture (resulting in a t distribution) for ## which the expected shortfall admits a closed formula set.seed(42) # reproducibility level <- seq(from = 0.9, to = 0.95, by = 0.01) df <- 4 ## If 'qmix' is provided as string, ES_nvmix() uses the closed formula ES1 <- ES_nvmix(level, qmix = "inverse.gamma", df = df) ## If 'qmix' is provided as function, the expected shortfall is estimated ES2 <- ES_nvmix(level, qmix = function(u, df) 1/qgamma(1-u, shape = df/2, rate = df/2), df = df) stopifnot(all.equal(ES1, ES2, tol = 1e-2, check.attributes = FALSE))
Generate vectors of random variates from multivariate normal variance mixtures (including Student t and normal distributions).
rnvmix(n, rmix, qmix, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0, ...) rStudent(n, df, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0) rNorm(n, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0) rNorm_sumconstr(n, weights, s, method = c("PRNG", "sobol", "ghalton"), skip = 0)rnvmix(n, rmix, qmix, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0, ...) rStudent(n, df, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0) rNorm(n, loc = rep(0, d), scale = diag(2), factor = NULL, method = c("PRNG", "sobol", "ghalton"), skip = 0) rNorm_sumconstr(n, weights, s, method = c("PRNG", "sobol", "ghalton"), skip = 0)
n |
sample size |
rmix |
specification of the mixing variable
|
qmix |
specification of the mixing variable
|
df |
positive degress of freedom; can also be |
loc |
location vector of dimension |
scale |
scale matrix (a covariance matrix entering the
distribution as a parameter) of dimension |
factor |
|
method |
If |
skip |
|
weights |
|
s |
|
... |
additional arguments (for example, parameters) passed to
the underlying mixing distribution when |
Internally used is factor, so scale is not required
to be provided if factor is given.
The default factorization used to obtain factor is the Cholesky
decomposition via chol(). To this end, scale
needs to have full rank.
Sampling from a singular normal variance mixture distribution can be
achieved by providing factor.
The number of rows of factor equals the dimension of
the sample. Typically (but not necessarily), factor is square.
rStudent() and rNorm() are wrappers of
rnvmix(, qmix = "inverse.gamma", df = df) and
rnvmix(, qmix = "constant", df = df), respectively.
The function rNorm_sumconstr() can be used to sample from the
multivariate standard normal distribution under a weighted sum constraint;
the implementation is based on Algorithm 1 in Vrins (2018). Let
. The function rNorm_sumconstr()
then samples from where and correspond
to the arguments weights and s. If supplied s is a vector
of length n, the i'th row of the returned matrix uses the constraint
where is the i'th element in s.
rnvmix() returns an -matrix
containing samples of the specified (via mix)
-dimensional multivariate normal variance mixture with
location vector loc and scale matrix scale
(a covariance matrix).
rStudent() returns samples from the -dimensional
multivariate Student t distribution with location vector
loc and scale matrix scale.
rNorm() returns samples from the -dimensional
multivariate normal distribution with mean vector
loc and covariance matrix scale.
rNorm_sumconstr() returns samples from the -dimensional
multivariate normal distribution conditional on the weighted sum being
constrained to s.
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
Vrins, E. (2018) Sampling the Multivariate Standard Normal Distribution under a Weighted Sum Constraint. Risks 6(3), 64.
### Examples for rnvmix() ###################################################### ## Generate a random correlation matrix in d dimensions d <- 3 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) ## Draw random variates and compare df <- 3.5 n <- 1000 set.seed(271) X <- rnvmix(n, rmix = "inverse.gamma", df = df, scale = P) # with scale set.seed(271) X. <- rnvmix(n, rmix = "inverse.gamma", df = df, factor = t(chol(P))) # with factor stopifnot(all.equal(X, X.)) ## Checking df = Inf set.seed(271) X <- rnvmix(n, rmix = "constant", scale = P) # normal set.seed(271) X. <- rnvmix(n, rmix = "inverse.gamma", scale = P, df = Inf) # t_infinity stopifnot(all.equal(X, X.)) ## Univariate case (dimension = number of rows of 'factor' = 1 here) set.seed(271) X.1d <- rnvmix(n, rmix = "inverse.gamma", df = df, factor = 1/2) set.seed(271) X.1d. <- rnvmix(n, rmix = "inverse.gamma", df = df, factor = 1)/2 # manual scaling stopifnot(all.equal(X.1d, X.1d.)) ## Checking different ways of providing 'mix' ## 1) By providing a character string (and corresponding ellipsis arguments) set.seed(271) X.mix1 <- rnvmix(n, rmix = "inverse.gamma", df = df, scale = P) ## 2) By providing a list; the first element has to be an existing distribution ## with random number generator available with prefix "r" rinverse.gamma <- function(n, df) 1 / rgamma(n, shape = df/2, rate = df/2) set.seed(271) X.mix2 <- rnvmix(n, rmix = list("inverse.gamma", df = df), scale = P) ## 3) The same without extra arguments (need the extra list() here to ## distinguish from Case 1)) rinverseGamma <- function(n) 1 / rgamma(n, shape = df/2, rate = df/2) set.seed(271) X.mix3 <- rnvmix(n, rmix = list("inverseGamma"), scale = P) ## 4) By providing a quantile function ## Note: P(1/Y <= x) = P(Y >= 1/x) = 1-F_Y(1/x) = y <=> x = 1/F_Y^-(1-y) set.seed(271) X.mix4 <- rnvmix(n, qmix = function(p) 1/qgamma(1-p, shape = df/2, rate = df/2), scale = P) ## 5) By providing random variates set.seed(271) # if seed is set here, results are comparable to the above methods W <- rinverse.gamma(n, df = df) X.mix5 <- rnvmix(n, rmix = W, scale = P) ## Compare (note that X.mix4 is not 'all equal' with X.mix1 or the other samples) ## since rgamma() != qgamma(runif()) (or qgamma(1-runif())) stopifnot(all.equal(X.mix2, X.mix1), all.equal(X.mix3, X.mix1), all.equal(X.mix5, X.mix1)) ## For a singular normal variance mixture: ## Need to provide 'factor' A <- matrix( c(1, 0, 0, 1, 0, 1), ncol = 2, byrow = TRUE) stopifnot(all.equal(dim(rnvmix(n, rmix = "constant", factor = A)), c(n, 3))) stopifnot(all.equal(dim(rnvmix(n, rmix = "constant", factor = t(A))), c(n, 2))) ## Using 'skip'. Need to reset the seed everytime to get the same shifts in "sobol". ## Note that when using method = "sobol", we have to provide 'qmix' instead of 'rmix'. set.seed(271) X.skip0 <- rnvmix(n, qmix = "inverse.gamma", df = df, scale = P, method = "sobol") set.seed(271) X.skip1 <- rnvmix(n, qmix = "inverse.gamma", df = df, scale = P, method = "sobol", skip = n) set.seed(271) X.wo.skip <- rnvmix(2*n, qmix = "inverse.gamma", df = df, scale = P, method = "sobol") X.skip <- rbind(X.skip0, X.skip1) stopifnot(all.equal(X.wo.skip, X.skip)) ### Examples for rStudent() and rNorm() ######################################## ## Draw N(0, P) random variates by providing scale or factor and compare n <- 1000 set.seed(271) X.n <- rNorm(n, scale = P) # providing scale set.seed(271) X.n. <- rNorm(n, factor = t(chol(P))) # providing the factor stopifnot(all.equal(X.n, X.n.)) ## Univariate case (dimension = number of rows of 'factor' = 1 here) set.seed(271) X.n.1d <- rNorm(n, factor = 1/2) set.seed(271) X.n.1d. <- rNorm(n, factor = 1)/2 # manual scaling stopifnot(all.equal(X.n.1d, X.n.1d.)) ## Draw t_3.5 random variates by providing scale or factor and compare df <- 3.5 n <- 1000 set.seed(271) X.t <- rStudent(n, df = df, scale = P) # providing scale set.seed(271) X.t. <- rStudent(n, df = df, factor = t(chol(P))) # providing the factor stopifnot(all.equal(X.t, X.t.)) ## Univariate case (dimension = number of rows of 'factor' = 1 here) set.seed(271) X.t.1d <- rStudent(n, df = df, factor = 1/2) set.seed(271) X.t.1d. <- rStudent(n, df = df, factor = 1)/2 # manual scaling stopifnot(all.equal(X.t.1d, X.t.1d.)) ## Check df = Inf set.seed(271) X.t <- rStudent(n, df = Inf, scale = P) set.seed(271) X.n <- rNorm(n, scale = P) stopifnot(all.equal(X.t, X.n)) ### Examples for rNorm_sumconstr() ############################################# set.seed(271) weights <- c(1, 1) Z.constr <- rNorm_sumconstr(n, weights = c(1, 1), s = 2) stopifnot(all(rowSums(Z.constr ) == 2)) plot(Z.constr , xlab = expression(Z[1]), ylab = expression(Z[2]))### Examples for rnvmix() ###################################################### ## Generate a random correlation matrix in d dimensions d <- 3 set.seed(157) A <- matrix(runif(d * d), ncol = d) P <- cov2cor(A %*% t(A)) ## Draw random variates and compare df <- 3.5 n <- 1000 set.seed(271) X <- rnvmix(n, rmix = "inverse.gamma", df = df, scale = P) # with scale set.seed(271) X. <- rnvmix(n, rmix = "inverse.gamma", df = df, factor = t(chol(P))) # with factor stopifnot(all.equal(X, X.)) ## Checking df = Inf set.seed(271) X <- rnvmix(n, rmix = "constant", scale = P) # normal set.seed(271) X. <- rnvmix(n, rmix = "inverse.gamma", scale = P, df = Inf) # t_infinity stopifnot(all.equal(X, X.)) ## Univariate case (dimension = number of rows of 'factor' = 1 here) set.seed(271) X.1d <- rnvmix(n, rmix = "inverse.gamma", df = df, factor = 1/2) set.seed(271) X.1d. <- rnvmix(n, rmix = "inverse.gamma", df = df, factor = 1)/2 # manual scaling stopifnot(all.equal(X.1d, X.1d.)) ## Checking different ways of providing 'mix' ## 1) By providing a character string (and corresponding ellipsis arguments) set.seed(271) X.mix1 <- rnvmix(n, rmix = "inverse.gamma", df = df, scale = P) ## 2) By providing a list; the first element has to be an existing distribution ## with random number generator available with prefix "r" rinverse.gamma <- function(n, df) 1 / rgamma(n, shape = df/2, rate = df/2) set.seed(271) X.mix2 <- rnvmix(n, rmix = list("inverse.gamma", df = df), scale = P) ## 3) The same without extra arguments (need the extra list() here to ## distinguish from Case 1)) rinverseGamma <- function(n) 1 / rgamma(n, shape = df/2, rate = df/2) set.seed(271) X.mix3 <- rnvmix(n, rmix = list("inverseGamma"), scale = P) ## 4) By providing a quantile function ## Note: P(1/Y <= x) = P(Y >= 1/x) = 1-F_Y(1/x) = y <=> x = 1/F_Y^-(1-y) set.seed(271) X.mix4 <- rnvmix(n, qmix = function(p) 1/qgamma(1-p, shape = df/2, rate = df/2), scale = P) ## 5) By providing random variates set.seed(271) # if seed is set here, results are comparable to the above methods W <- rinverse.gamma(n, df = df) X.mix5 <- rnvmix(n, rmix = W, scale = P) ## Compare (note that X.mix4 is not 'all equal' with X.mix1 or the other samples) ## since rgamma() != qgamma(runif()) (or qgamma(1-runif())) stopifnot(all.equal(X.mix2, X.mix1), all.equal(X.mix3, X.mix1), all.equal(X.mix5, X.mix1)) ## For a singular normal variance mixture: ## Need to provide 'factor' A <- matrix( c(1, 0, 0, 1, 0, 1), ncol = 2, byrow = TRUE) stopifnot(all.equal(dim(rnvmix(n, rmix = "constant", factor = A)), c(n, 3))) stopifnot(all.equal(dim(rnvmix(n, rmix = "constant", factor = t(A))), c(n, 2))) ## Using 'skip'. Need to reset the seed everytime to get the same shifts in "sobol". ## Note that when using method = "sobol", we have to provide 'qmix' instead of 'rmix'. set.seed(271) X.skip0 <- rnvmix(n, qmix = "inverse.gamma", df = df, scale = P, method = "sobol") set.seed(271) X.skip1 <- rnvmix(n, qmix = "inverse.gamma", df = df, scale = P, method = "sobol", skip = n) set.seed(271) X.wo.skip <- rnvmix(2*n, qmix = "inverse.gamma", df = df, scale = P, method = "sobol") X.skip <- rbind(X.skip0, X.skip1) stopifnot(all.equal(X.wo.skip, X.skip)) ### Examples for rStudent() and rNorm() ######################################## ## Draw N(0, P) random variates by providing scale or factor and compare n <- 1000 set.seed(271) X.n <- rNorm(n, scale = P) # providing scale set.seed(271) X.n. <- rNorm(n, factor = t(chol(P))) # providing the factor stopifnot(all.equal(X.n, X.n.)) ## Univariate case (dimension = number of rows of 'factor' = 1 here) set.seed(271) X.n.1d <- rNorm(n, factor = 1/2) set.seed(271) X.n.1d. <- rNorm(n, factor = 1)/2 # manual scaling stopifnot(all.equal(X.n.1d, X.n.1d.)) ## Draw t_3.5 random variates by providing scale or factor and compare df <- 3.5 n <- 1000 set.seed(271) X.t <- rStudent(n, df = df, scale = P) # providing scale set.seed(271) X.t. <- rStudent(n, df = df, factor = t(chol(P))) # providing the factor stopifnot(all.equal(X.t, X.t.)) ## Univariate case (dimension = number of rows of 'factor' = 1 here) set.seed(271) X.t.1d <- rStudent(n, df = df, factor = 1/2) set.seed(271) X.t.1d. <- rStudent(n, df = df, factor = 1)/2 # manual scaling stopifnot(all.equal(X.t.1d, X.t.1d.)) ## Check df = Inf set.seed(271) X.t <- rStudent(n, df = Inf, scale = P) set.seed(271) X.n <- rNorm(n, scale = P) stopifnot(all.equal(X.t, X.n)) ### Examples for rNorm_sumconstr() ############################################# set.seed(271) weights <- c(1, 1) Z.constr <- rNorm_sumconstr(n, weights = c(1, 1), s = 2) stopifnot(all(rowSums(Z.constr ) == 2)) plot(Z.constr , xlab = expression(Z[1]), ylab = expression(Z[2]))
Sampling and density evaluation for the multivariate skew-t distribution and copula.
rskewt(n, loc = rep(0, d), scale = diag(2), factor = NULL, gamma = rep(0, d), df = Inf, method = c("PRNG", "sobol", "ghalton"), skip = 0) dskewt(x, loc = rep(0, d), scale = diag(2), gamma = rep(0, d), df, log = FALSE, scale.inv, ldet) rskewtcopula(n, scale = diag(2), factor = NULL, gamma = rep(0, d), df = Inf, pseudo = TRUE, method = c("PRNG", "sobol", "ghalton"), skip = 0) dskewtcopula(u, scale = diag(2), gamma = rep(0, d), df, log = FALSE, scale.inv, ldet)rskewt(n, loc = rep(0, d), scale = diag(2), factor = NULL, gamma = rep(0, d), df = Inf, method = c("PRNG", "sobol", "ghalton"), skip = 0) dskewt(x, loc = rep(0, d), scale = diag(2), gamma = rep(0, d), df, log = FALSE, scale.inv, ldet) rskewtcopula(n, scale = diag(2), factor = NULL, gamma = rep(0, d), df = Inf, pseudo = TRUE, method = c("PRNG", "sobol", "ghalton"), skip = 0) dskewtcopula(u, scale = diag(2), gamma = rep(0, d), df, log = FALSE, scale.inv, ldet)
u |
|
x |
|
n |
sample size |
df |
positive degress of freedom; can also be |
loc |
location of length |
gamma |
Skewness-vector of dimension |
scale |
scale matrix (a covariance matrix entering the
distribution as a parameter) of dimension |
factor |
|
scale.inv |
inverse of |
ldet |
|
log |
|
pseudo |
|
method |
see |
skip |
see |
Functionalities for sampling from the multivariate skew-t distribution
and copula; the former has stochastic representation
where , follows an inverse-gamma distrubution with
parameters df/2 and is independent of the -dimensional vector
following a standard multivariate normal distribution. When is the
null-vector, the distribution becomes the multivariate distribution.
A major computational challenge when working with the skew t copula is
the lack of an available distribution and quantile function of the univariate
skew t distribution. These are required in rskewtcopula(, pobs = FALSE)
and in dskewtcopula(). The unviarate skew t distribution and
quantile functions are currently implemented as described Yoshiba, T. (2018).
The functions described here are currently being further developed to improve
stability, accuracy and speed, so that arguments may change in subsequent
versions of nvmix.
-vector of (log-)density values and -matrix of samples, respectively.
Erik Hintz, Marius Hofert and Christiane Lemieux
Hintz, E., Hofert, M. and Lemieux, C. (2020), Grouped Normal Variance Mixtures. Risks 8(4), 103.
Hintz, E., Hofert, M. and Lemieux, C. (2021), Normal variance mixtures: Distribution, density and parameter estimation. Computational Statistics and Data Analysis 157C, 107175.
Hintz, E., Hofert, M. and Lemieux, C. (2022), Multivariate Normal Variance Mixtures in R: The R Package nvmix. Journal of Statistical Software, doi:10.18637/jss.v102.i02.
McNeil, A. J., Frey, R. and Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques, Tools. Princeton University Press.
Yoshiba, T. (2018). Maximum Likelihood Estimation of Skew-t Copulas with Its Applications to Stock Returns. Journal of Statistical Computation and Simulation 88 (13): 2489–2506.
rStudent(), dStudent(), rStudentcopula(), dStudentcopula()
## Sampling from the skew-t copula n <- 100 # sample size d <- 10 # dimension rho <- 0.5 scale <- matrix(rho, ncol = d, nrow = d) diag(scale) <- 1 # scale gamma <- rep(1, d) # skewness df <- 7 # degrees-of-freedom parameter set.seed(1) # same random numbers for both runs system.time(samplecop_pobs <- rskewtcopula(n, scale = scale, gamma = gamma, df = df, pseudo = TRUE)) set.seed(1) system.time(samplecop_pskewt <- rskewtcopula(n, scale = scale, gamma = gamma, df = df, pseudo = FALSE)) ## Plot first two coordinates layout(rbind(1:2)) plot(samplecop_pobs, xlab = expression(U[1]), ylab = expression(U[2])) mtext("pobs = TRUE") plot(samplecop_pskewt, xlab = expression(U[1]), ylab = expression(U[2])) mtext("pobs = FALSE") layout(1)## Sampling from the skew-t copula n <- 100 # sample size d <- 10 # dimension rho <- 0.5 scale <- matrix(rho, ncol = d, nrow = d) diag(scale) <- 1 # scale gamma <- rep(1, d) # skewness df <- 7 # degrees-of-freedom parameter set.seed(1) # same random numbers for both runs system.time(samplecop_pobs <- rskewtcopula(n, scale = scale, gamma = gamma, df = df, pseudo = TRUE)) set.seed(1) system.time(samplecop_pskewt <- rskewtcopula(n, scale = scale, gamma = gamma, df = df, pseudo = FALSE)) ## Plot first two coordinates layout(rbind(1:2)) plot(samplecop_pobs, xlab = expression(U[1]), ylab = expression(U[2])) mtext("pobs = TRUE") plot(samplecop_pskewt, xlab = expression(U[1]), ylab = expression(U[2])) mtext("pobs = FALSE") layout(1)