A fully `Distributions.jl`-compliant copula package
The Copulas.jl package provides a large collection of models for dependence structures of real random vectors, known as copulas, with a wide selection of features:
- random number generation
- evaluation of (log)density and distribution functions
- copula-based multivariate distributions via Sklar's theorem
- fitting procedures, model diagnostics, and automatic family selection
- dependence metrics and tail coefficients
- marginalization, conditioning, and Rosenblatt transforms
- resampling-based hypothesis tests for dependence assumptions and goodness of fit
Since copulas are distribution functions, we fully comply with the Distributions.jl API. This compliance allows direct interoperability with other packages based on this API, such as Turing.jl.
Usually, users who work with copulas turn to the R package copula. While still well-maintained and regularly updated, the R package copula is a complicated code base in terms of readability, extensibility, reliability, and maintenance.
This package aims to provide a lightweight, fast, reliable, and maintainable copula implementation in native Julia. Among other benefits, a notable feature of such a native implementation is floating point type agnosticism, i.e., compatibility with Float32 (and GPU equivalents), BigFloat, DoubleFloats, MultiFloats, and other numeric types.
The package revolves around two main types:
Copula, the abstract supertype of all copulasSklarDist, the type for multivariate compound distributions via Sklar's theorem
The package is registered in Julia's General registry so you may simply install the package by running :
] add CopulasThe API contains random number generation, cdf and pdf evaluation, and the fit function from Distributions.jl. A typical use case might look like this:
using Copulas, Distributions, Random, Plots
X₁ = Gamma(2,3)
X₂ = Beta(1,4)
X₃ = Normal()
C = ClaytonCopula(3,5.2) # A 3-variate Clayton copula with θ = 5.2
D = SklarDist(C,(X₁,X₂,X₃)) # The final distribution
simu = rand(D,1000) # Generate a dataset
D̂ = fit(SklarDist{ClaytonCopula,Tuple{Gamma,Normal,Normal}}, simu) # estimate a model
plot(D̂) # plot the resultThe list of available copula models is very large; browse the Bestiary for definitions, parameterizations, constructors, and model-specific caveats. The general implementation philosophy is for the code to follow the mathematical boundaries of the implemented concepts. For example, this is the only implementation we know (in any language) that allows for all Archimedean copulas to be sampled: we use the Williamson transformation for non-standard generators, including user-provided black-box ones.
Other Julia packages cover related use cases. BivariateCopulas.jl focuses on a compact set of bivariate copulas, joint distributions, conditioning, and visualization. DatagenCopulaBased.jl focuses on data generation, including selected nested and chained constructions. The comparison below summarizes capabilities documented by each project; “Not documented” means that the linked public README does not advertise the feature, not that no implementation can exist.
| Capability | Copulas.jl |
DatagenCopulaBased.jl |
BivariateCopulas.jl |
|---|---|---|---|
| Sampling | ✅ Vector and matrix rand interface |
✅ Primary interface | |
Distributions.jl distribution API |
✅ | ❌ Not documented | |
| CDF and density | ✅ When defined by the model | ❌ Not documented as a common interface | |
| Copula plus arbitrary margins | ✅ SklarDist, any supported dimension |
||
| Parameter fitting | ✅ Quick fits and full CopulaModel results |
❌ Not documented | ❌ Not documented |
| Automatic family selection | ✅ Explicit candidate sets with AIC, BIC, AICc, or HQC | ❌ Not documented | ❌ Not documented |
| Statistical-model diagnostics | ✅ Covariance, confidence intervals, residuals, prediction, information criteria | ❌ Not documented | ❌ Not documented |
| Dependence measures | ✅ Scalar and pairwise rank and tail measures | ❌ Not documented as a common interface | |
| Subsetting and conditioning | ✅ Copulas and SklarDist; univariate or multivariate results |
❌ Not documented | |
| Rosenblatt and inverse Rosenblatt transforms | ✅ | ❌ Not documented | ❌ Not documented |
| Hypothesis tests | ✅ Independence, exchangeability, radial symmetry, extreme-value dependence, goodness of fit | ❌ Not documented | ❌ Not documented |
| Plot recipes | ✅ Pairwise samples, margins, CDF/PDF contours and surfaces | ❌ Not documented | |
| Archimedean models | ✅ Clayton, Frank, Gumbel, Joe, AMH, inverse Gaussian, BB1--BB10, and custom/empirical generators | ||
| Structured multivariate models | ✅ Liouville and nested Archimedean copulas | ✅ Same-family nested copulas and bivariate chains | ❌ Not documented |
| Elliptical models | ✅ Gaussian and Student, multivariate | ✅ Gaussian and Student | |
| Extreme-value models | ✅ Logistic, Galambos, Hüsler--Reiss, extremal-t, Tawn, asymmetric and spectral families; bivariate and multivariate |
❌ Not documented | |
| Nonparametric copulas | ✅ Empirical, beta, Bernstein, checkerboard, empirical EV | ❌ Not documented | ❌ Not documented |
| Archimax models | ❌ Not documented | ❌ Not documented |
The table compares public scope rather than runtime performance; algorithmic cost depends strongly on the family, dimension, and requested operation.
Here is a practical tour of the main public workflows. For precise behavioral guarantees see the Public API; for theory and model-specific guidance see the Manual and Bestiary.
You can construct a copula object with their respective constructors. They behave like multivariate distributions from Distributions.jl and respect their API:
using Copulas, Distributions, Random, StatsBase
# A 3-variate Clayton copula
C = ClaytonCopula(3, 2.0)
U = rand(C, 5)
Distributions.loglikelihood(C, U)To build multivariate distributions, you can compose a copula with marginals via Sklar’s theorem:
X₁, X₂, X₃ = Gamma(2,3), Beta(1,5), LogNormal(0,1)
C2 = GumbelCopula(3, 1.7)
D = SklarDist(C2, (X₁, X₂, X₃))
rand(D, 3)
pdf(D, rand(3))You can get scalar dependence metrics at copula level:
(
kendall_tau = Copulas.τ(C),
spearm_rho = Copulas.ρ(C),
blomqvist_beta = Copulas.β(C),
gini_gamma = Copulas.γ(C),
entropy_iota = Copulas.ι(C),
lower_tail_dep = Copulas.λₗ(C),
upper_tail_dep = Copulas.λᵤ(C)
)Pairwise matrices of bivariate versions are available through StatsBase.corkendall(C), StatsBase.corspearman(C), Copulas.corblomqvist(C), Copulas.corgini(C), Copulas.corentropy(C), Copulas.corlowertail(C), and Copulas.coruppertail(C).
Same functions work passing a dataset instead of the copula for their empirical counterpart.
The measure function measures hypercubes under the distribution of the copula. You can access the Rosenblatt transformation of a copula (or a Sklar distribution) through the rosenblatt and inverse_rosenblatt functions:
Copulas.measure(C, (0.1,0.2,0.3), (0.9,0.8,0.7))
x = rand(D, 100)
u = rosenblatt(D, x)
x2 = inverse_rosenblatt(D, u)
maximum(abs.(x2 .- x))You can subset the dimensions of a model through subsetdims(), and you can condition a model on some of its marginals with condition():
S23 = subsetdims(C2, (2,3))
StatsBase.corkendall(S23)
Dj = condition(C2, 2, 0.3) # Distributions of (U₁, U₃) | U₂ = 0.3 (d=2)
Distributions.cdf(Dj, [0.95, 0.80])
Dc = condition(D, (2,3), (0.3, 0.2))
rand(Dc, 2)Fit both marginals and copula from raw data (Sklar):
X = rand(D, 150)
M = fit(CopulaModel, SklarDist{GumbelCopula, Tuple{Gamma,Beta,LogNormal}}, X; copula_method=:mle)Directly fit a copula from pseudo-observations U:
U = pseudos(X)
Ĉ = fit(GumbelCopula, U; method=:itau)Notes
fitchooses a reasonable default per family; passmethod/copula_methodto control it.- Common methods: copulas
:mle,:itau,:irho,:ibeta; Sklar:ifm(parametric CDFs) and:ecdf(pseudo-observations).
Use CopulaModel when diagnostics and inference matter. If the family is not
known in advance, fit an explicit, scientifically appropriate candidate set and
rank successful fits by an information criterion:
Msel = fit(
CopulaModel,
Copulas.Copula,
U;
candidates=(ClaytonCopula, GumbelCopula, FrankCopula),
criterion=:bic,
vcov=false,
)
selectiontable(Msel)Selection is deliberately explicit: Copulas.jl does not treat every available family as a sensible candidate for every dimension or scientific question. See the fitting interface for covariance estimation, confidence intervals, residuals, prediction, and selection caveats.
The test constructors share the StatsAPI.HypothesisTest interface and return a
CopulaTest queried with teststatistic, pvalue, and nobs. Available
procedures assess mutual independence, exchangeability, radial symmetry, the
extreme-value property, and goodness of fit to a specified fitted family.
test = IndependenceCopulaTest(U; N=19, rng=Xoshiro(42))
(statistic=teststatistic(test), pvalue=pvalue(test), observations=nobs(test))These are resampling-based procedures. Set an RNG for reproducibility, use a
larger N for scientific work, and check the assumptions—especially continuity
and absence of ties—on the hypothesis-testing page.
If you want to contribute to the package, ask a question, found a bug or simply want to chat, do not hesitate to open an issue on the Copulas.jl repository
Do not hesitate to star this repository to show support. If you use this package in your researches, please cite it with the following bibtex code:
@article{LavernyJimenez2024,
author = {Oskar Laverny and Santiago Jimenez},
title = {Copulas.jl: A fully Distributions.jl-compliant copula package},
journal = {Journal of Open Source Software},
doi = {10.21105/joss.06189},
url = {https://doi.org/10.21105/joss.06189},
year = {2024},
publisher = {The Open Journal},
volume = {9},
number = {94},
pages = {6189}
}