Vine copula models
- Set up a custom vine copula model
- How to read the R-vine matrix
- Fit and select a vine copula model
- Work with a vine copula model
Vine copula models are implemented in the class Vinecop
. To use this class in your code, include the header include the header vinecopulib/
(or simply vinecopulib.hpp
) at the top of your source file. This automatically enables all features for bivariate copula models.
Set up a custom vine copula model
Custom models can be created through the constructor of Vinecop
. A model is represented by a std::vector<std::vector<Bicop>>
containing all pair-copulas and an R-vine matrix.
Similarly to bivariate copulas, there are essentially two ways of setting-up vine copulas:
- with known parameters,
- from data (i.e., with estimated parameters).
The constructor with known parameters has two versions:
- one for which the only argument is the dimension, allowing to set-up a D-vine with only independence copulas,
- and one for which the two arguments are a matrix of integers (i.e., and R-vine matrix) and a
std::vector<std::vector<Bicop>>
containing all pair-copulas.
// specify the dimension of the model int d = 3; // instantiate a three dimensional D-vine with independence copulas Vinecop default_model(d); // alternatively, instantiate a std::vector<std::vector<Bicop>> object auto pair_copulas = Vinecop::make_pair_copula_store(d); // specify the pair copulas auto par = Eigen::VectorXd::Constant(1, 3.0); for (auto& tree : pair_copulas) { for (auto& pc : tree) { pc = Bicop(BicopFamily::clayton, 270, par); } } // specify a structure matrix Eigen::Matrix<size_t, Eigen::Dynamic, Eigen::Dynamic> mat(3, 3); mat << 1, 1, 1, 2, 2, 0, 3, 0, 0; // instantiate the custom model Vinecop custom_model(pair_copulas, mat);
The constructors from data take the same arguments as the two select methods described below.
How to read the R-vine matrix
The R-vine matrix notation in vinecopulib is different from the one in VineCopula. An exemplary array is
4 4 4 4 3 3 3 2 2 1
which encodes the following pair-copulas:
| tree | edge | pair-copulas | |------|------|----------------| | 0 | 0 | `(1, 4)` | | | 1 | `(2, 4)` | | | 2 | `(3, 4)` | | 1 | 0 | `(1, 3; 4)` | | | 1 | `(2, 3; 4)` | | 2 | 0 | `(1, 2; 3, 4)` |
Denoting by M[i, j]
the matrix entry in row i
and column j
, the pair-copula index for edge e
in tree t
of a d
dimensional vine is (M[d - 1 - e, e], M[t, e]; M[t - 1, e], ..., M[0, e])
. Less formally,
- Start with the counter-diagonal element of column
e
(first conditioned variable). - Jump up to the element in row
t
(second conditioned variable). - Gather all entries further up in column
e
(conditioning set).
A valid R-vine matrix must satisfy several conditions which are checked when RVineStructure()
is called:
- The lower right triangle must only contain zeros.
- The upper left triangle can only contain numbers between 1 and d.
- The antidiagonal must contain the numbers 1, ..., d.
- The antidiagonal entry of a column must not be contained in any column further to the right.
- The entries of a column must be contained in all columns to the left.
- The proximity condition must hold: For all t = 1, ..., d - 2 and e = 0, ..., d - t - 1 there must exist an index j > d, such that
(M[t, e], {M[0, e], ..., M[t-1, e]})
equals either(M[d-j-1, j], {M[0, j], ..., M[t-1, j]})
or(M[t-1, j], {M[d-j-1, j], M[0, j], ..., M[t-2, j]})
.
Fit and select a vine copula model
The method select_all()
performs parameter estimation and automatic model selection when the vine structure is unknown (i.e., it modifies the structure of the object), using the sequential procedure proposed by Dissman et al. (2013). Alternatively, select_families()
performs parameter estimation and automatic model selection for a known structure (i.e., using the structure of the object). In both cases, the only mandatory argument is the data (stored in a Eigen::MatrixXd
), while controls argument allow for customization of the fit.
// specify the dimension of the model int d = 5; // simulate dummy data Eigen::MatrixXd data = tools_stats::simulate_uniform(100, d); // instantiate a D-vine and select the families Vinecop model(d); model.select_families(data); // alternatively, select the structure along with the families model.select_all(data);
Note that the second argument to select_all()
and select_families()
is similar to the one of select()
for Bicop
objects. Objects of the class FitControlsVinecop
inherit from FitControlsBicop
and extend them with additional data members to control the structure selection:
size_t trunc_lvl
describes the tree after whichfamily_set
is set to{BicopFamily::indep}
. In other words, all pair copulas in trees lower thantrunc_lvl
(default to none) are "selected" as independence copulas.std::string tree_criterion
describes the criterion used to construct the minimum spanning tree (see Dissman et al. (2013)). It can take"tau"
(default) for Kendall's tau,"rho"
for Spearman's rho, or"hoeffd"
for Hoeffding's D (suited for non-monotonic relationships).double threshold
describes a value (default is 0) oftree_criterion
under which the corresponding pair-copula is set to independence.bool select_trunc_lvl
can be set to true to select the truncation level automatically (default isfalse
).bool select_threshold
can be set to true to select the threshold parameter automatically (default isfalse
).size_t num_threads
number of threads to run in parallel when fitting pair copulas within one tree.
As mentioned above, the arguments of select_all()
and select_families()
can be used as arguments to a constructor allowing to instantiate a new object directly:
// specify the dimension of the model int d = 4; // simulate dummy data Eigen::MatrixXd data = simulate_uniform(100, d); // instantiate a vine from data using the default arguments Vinecop best_vine(data); // alternatively, instantiate a structure matrix... Eigen::Matrix<size_t, Eigen::Dynamic, Eigen::Dynamic> M; M << 1, 1, 1, 1, 2, 2, 2, 0, 3, 3, 0, 0 4, 0, 0, 0; // ... and instantiate a vine copula from data using the custom structure, // Kendall's tau inversion for parameters // estimation and a truncation after the second tree FitControlsVinecop controls(bicop_families::itau, "itau"); controls.set_trunc_lvl(2); controls.set_num_threads(4); // parallelize with 4 threads Vinecop custom_vine(data, M, controls);
Work with a vine copula model
You can simulate from a vine copula model, evaluate its density, distribution, log-likelihood, AIC and BIC.
// 5-dimensional independence vine Vinecop model(5); // simulate 100 observations auto data = model.simulate(100) // evaluate the density auto pdf = model.pdf(data) // evaluate the distribution auto cdf = model.cdf(data) // evaluate the log-likelihood auto ll = model.loglik(data) // evaluate the AIC auto aic = model.aic(data) // evaluate the BIC auto bic = model.bic(data)
Vine copula models can also be written to and constructed from JSON files and nlohmann::json
objects:
// 5-dimensional vine copula Vinecop vinecop(5); // Save as a nlohmann::json object nlohmann::json vinecop_json = vinecop.to_json(); // Write into a JSON file std::ofstream file(std::string("myfile.json")); file << vinecop_json << std::endl; // Equivalently vinecop.to_file(myfile); // Then a new Vine can be constructed from the nlohmann::json object Vinecop vinecop2(vinecop_json); // Or from the JSON file Vinecop vinecop2(std::string("myfile.json"));