Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/lrnv/Copulas.jl
Browse files Browse the repository at this point in the history
  • Loading branch information
lrnv committed Dec 21, 2023
2 parents facae2e + 15be93b commit 26015da
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 77 deletions.
80 changes: 15 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
<p align=center>
<a href="https://lrnv.github.io/Copulas.jl/stable"><img src="https://img.shields.io/badge/docs-stable-blue.svg" alt="Stable" /></a>
<a href="https://lrnv.github.io/Copulas.jl/dev"><img src="https://img.shields.io/badge/docs-dev-blue.svg" alt="Dev" /></a>
<a href="https://joss.theoj.org/papers/98fa5d88d0d8f27038af2da00f210d45"><img src="https://joss.theoj.org/papers/98fa5d88d0d8f27038af2da00f210d45/status.svg"></a>
<a href="https://zenodo.org/badge/latestdoi/456485213"><img src="https://zenodo.org/badge/456485213.svg" alt="DOI" /></a>
<br />
<a href="https://www.repostatus.org/#active"><img src="https://www.repostatus.org/badges/latest/active.svg" alt="Project Status: Active – The project has reached a stable, usable state and is being actively developed." /></a>
<a href="https://github.com/lrnv/Copulas.jl/actions/workflows/CI.yml?query=branch%3Amain"><img src="https://github.com/lrnv/Copulas.jl/actions/workflows/CI.yml/badge.svg?branch=main" alt="Build Status" /></a>
<br />
<a href="https://codecov.io/gh/lrnv/Copulas.jl"><img src="https://codecov.io/gh/lrnv/Copulas.jl/branch/main/graph/badge.svg"/></a>
<a href="https://github.com/JuliaTesting/Aqua.jl"><img src="https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg" alt="Aqua QA" /></a>
<!-- <a href="https://benchmark.tansongchen.com/TaylorDiff.jl"><img src="https://img.shields.io/buildkite/2c801728055463e7c8baeeb3cc187b964587235a49b3ed39ab/main.svg?label=benchmark" alt="Benchmark Status" /></a> -->
<br />
<a href="https://joss.theoj.org/papers/98fa5d88d0d8f27038af2da00f210d45"><img src="https://joss.theoj.org/papers/98fa5d88d0d8f27038af2da00f210d45/status.svg"></a>
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT" /></a>
<a href="https://zenodo.org/badge/latestdoi/456485213"><img src="https://zenodo.org/badge/456485213.svg" alt="DOI" /></a>
<br />
<a href="https://github.com/SciML/ColPrac"><img src="https://img.shields.io/badge/contributor's%20guide-ColPrac-blueviolet" alt="ColPrac: Contributor's Guide on Collaborative Practices for Community Packages" /></a>
<a href="https://github.com/invenia/BlueStyle"><img src="https://img.shields.io/badge/code%20style-blue-4495d1.svg" alt="Code Style: Blue" /></a>
</p>
Expand All @@ -24,12 +22,11 @@
<a href="https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=563952901&machine=standardLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=EastUshttps://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=563952901&machine=standardLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=EastUs"><img src="https://github.com/codespaces/badge.svg" alt="Open in GitHub Codespaces" /></a>
</p> -->

`Copulas.jl` brings most standard [copula](https://en.wikipedia.org/wiki/Copula_(probability_theory)) features into native Julia: random number generation, pdf and cdf, fitting, copula-based multivariate distributions through Sklar's theorem, etc. Since copulas are distribution functions, we fully comply with the [`Distributions.jl`](https://github.com/JuliaStats/Distributions.jl) API. This complience allows interoperability with other packages based on this API such as, e.g., [`Turing.jl`](https://github.com/TuringLang/Turing.jl).
`Copulas.jl` brings most standard [copula](https://en.wikipedia.org/wiki/Copula_(probability_theory)) features into native Julia: random number generation, pdf and cdf, fitting, copula-based multivariate distributions through Sklar's theorem, etc. Since copulas are distribution functions, we fully comply with the [`Distributions.jl`](https://github.com/JuliaStats/Distributions.jl) API. This allows interoperability with the broader ecosystem, based on this API, such as, e.g., [`Turing.jl`](https://github.com/TuringLang/Turing.jl).

Usually, people that use and work with copulas turn to R, because of the amazing `R` package [`copula`](https://cran.r-project.org/web/packages/copula/copula.pdf).
While it is still well maintained and regularly updated, the `R` package `copula` is a mixture of obscure, heavily optimized `C` code and more standard `R` code, which makes it a complicated code base for readability, extensibility, reliability and maintenance.
Usually, people that use and work with copulas turn to R, because of the amazing package [`R::copula`](https://cran.r-project.org/web/packages/copula/copula.pdf). While well-maintained and regularly updated, `R::copula` is a mixture of obscure, heavily optimized `C` code and more standard `R` code, which makes it a complicated code base for readability, extensibility, reliability and maintenance.

This is an attempt to provide a very light, fast, reliable and maintainable copula implementation in native Julia. Among others, one of the notable benefits of such a native implementatioon is the floating point type agnosticity, i.e. compatibility with `BigFloat`, [`DoubleFloats`](https://github.com/JuliaMath/DoubleFloats.jl), [`MultiFloats`](https://github.com/dzhang314/MultiFloats.jl) and other kind of numbers.
This is an attempt to provide a very light, fast, reliable and maintainable copula implementation in native Julia. One of the notable benefits of such a native implementation (among others) is the floating point type agnosticity, i.e. compatibility with `BigFloat`, [`DoubleFloats`](https://github.com/JuliaMath/DoubleFloats.jl), [`MultiFloats`](https://github.com/dzhang314/MultiFloats.jl), etc.

The package revolves around two main types:

Expand All @@ -38,14 +35,14 @@ The package revolves around two main types:

**Warning: This is fairly experimental work and our API might change without notice.**

## Instalation
## Getting started

The package is registered in Julia's General registry so you may simply install the package by running :

```julia
] add Copulas
```

## Usage

The API contains random number generation, cdf and pdf evaluation, and the `fit` function from `Distributions.jl`. A typical use case might look like this:

```julia
Expand All @@ -56,72 +53,25 @@ X₃ = LogNormal(0,1)
C = ClaytonCopula(3,0.7) # A 3-variate Clayton Copula with θ = 0.7
D = SklarDist(C,(X₁,X₂,X₃)) # The final distribution

# This generates a (3,1000)-sized dataset from the multivariate distribution D
simu = rand(D,1000)
simu = rand(D,1000) # Generate a dataset

# While the following estimates the parameters of the model from a dataset:
# You may estimate a copula using the `fit` function:
= fit(SklarDist{FrankCopula,Tuple{Gamma,Normal,LogNormal}}, simu)
# Increase the number of observations to get a beter fit (or not?)
```

Available copula families are:
- `EllipticalCopulas`: `GaussianCopula` and `TCopula`
- `ArchimedeanCopula`: `WilliamsonCopula` (for any generator), but also `ClaytonCopula`,`FrankCopula`, `AMHCopula`, `JoeCopula`, `GumbelCopula`, supporting the full ranges in every dimensions (e.g. ClaytonCopula can be sampled with negative dependence in any dimension, not just d=2).
- `WCopula`, `IndependentCopula` and `MCopula`, which are [Fréchet-Hoeffding bounds](https://en.wikipedia.org/wiki/Copula_(probability_theory)#Fr%C3%A9chet%E2%80%93Hoeffding_copula_bounds),
- `PlackettCopula`, see ref?
- `EmpiricalCopula` to follow closely a given dataset.

The next ones to be implemented will probably be:
- Extreme values copulas.
- Nested archimedeans (for any generators, with automatic nesting conditions checking).
- Bernstein copula and more general Beta copula as smoothing of the Empirical copula.
- `CheckerboardCopula` (and more generally `PatchworkCopula`)

Adding a new `ArchimedeanCopula` is very easy. The `Clayton` implementation is as short as:

```julia
struct ClaytonCopula{d,T} <: Copulas.ArchimedeanCopula{d}
θ::T
end
ClaytonCopula(d,θ) = ClaytonCopula{d,typeof(θ)}(θ) # Constructor
ϕ(C::ClaytonCopula, t) = (1+sign(C.θ)*t)^(-1/C.θ) # Generator
ϕ⁻¹(C::ClaytonCopula,t) = sign(C.θ)*(t^(-C.θ)-1) # Inverse Generator
τ(C::ClaytonCopula) = C.θ/(C.θ+2) # θ -> τ
τ⁻¹(::Type{ClaytonCopula},τ) = 2τ/(1-τ) # τ -> θ
williamson_dist(C::ClaytonCopula{d,T}) where {d,T} = WilliamsonFromFrailty(Distributions.Gamma(1/C.θ,1),d) # Radial distribution
```
The Archimedean API is modular:

- To sample an archimedean, only `ϕ` is required. Indeed, the `williamson_dist` has a generic fallback that uses [WilliamsonTransforms.jl](https://www.github.com/lrnv/WilliamsonTransforms.jl) for any generator. Note however that providing the `williamson_dist` yourself if you know it will allow sampling to be an order of magnitude faster.
- To evaluate the cdf and (log-)density in any dimension, only `ϕ` and `ϕ⁻¹` are needed.
- Currently, to fit the copula `τ⁻¹` is needed as we use the inverse tau moment method. But we plan on also implementing inverse rho and MLE (density needed).
- Note that the generator `ϕ` follows the convention `ϕ(0)=1`, while others (e.g., https://en.wikipedia.org/wiki/Copula_(probability_theory)#Archimedean_copulas) use `ϕ⁻¹` as the generator.
The list of availiable copula models is *very* large, check it out on our [documentation](https://lrnv.github.io/Copulas.jl/stable) !

Please take a look at the [documentation](https://lrnv.github.io/Copulas.jl/dev) for more details.

## Dev Roadmap

**Next:**
- [ ] More documentation and tests for the current implementation.
- [ ] Docs: show how to use the WilliamsonCopula to implement generic archimedeans.
- [ ] Give the user the choice of fitting method via `fit(dist,data; method="MLE")` or `fit(dist,data; method="itau")` or `fit(dist,data; method="irho")`.
- [ ] Fitting a generic archimedean with an empirically produced generarator
- [ ] Automatic checking of generator d-monotonicity ? Dunno if it is even possible.

**Maybe later:**
- [ ] `NestedArchimedean`, with automatic checking of nesting conditions for generators.
- [ ] `Vines`?
- [ ] `Archimax` ?
- [ ] `BernsteinCopula` and `BetaCopula` could also be implemented.
- [ ] `PatchworkCopula` and `CheckerboardCopula`: could be nice things to have :)
- [ ] Goodness of fits tests ?
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.

## Contributions are welcome

If you want to contribute to the package, found a bug in it or simply want to chat, do not hesitate to open an issue on this repo.
If you want to contribute to the package, found a bug in it or simply want to chat, simply open an issue!

## Citation

Do not hesitate to star this repository to show support ! You may also cite the package by using the following bibtex code:

```bibtex
@software{oskar_laverny_2023_10084669,
author = {Oskar Laverny},
Expand Down
6 changes: 3 additions & 3 deletions docs/src/archimedean/generalities.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ This transformation is implemented through one method in the Generator interface
To put it in a nutshell, for ``\phi`` a ``d``-monotone archimedean generator, the inverse Williamson-d-transform of ``\\phi`` is the cumulative distribution function ``F`` of a non-negative random variable ``R``, defined by :

```math
F(x) = 𝒲_{d}^{-1}(\\phi)(x) = 1 - \\frac{(-x)^{d-1} \\phi_+^{(d-1)}(x)}{k!} - \\sum_{k=0}^{d-2} \\frac{(-x)^k \\phi^{(k)}(x)}{k!}
F(x) = 𝒲_{d}^{-1}(\phi)(x) = 1 - \frac{(-x)^{d-1} \phi_+^{(d-1)}(x)}{k!} - \sum_{k=0}^{d-2} \frac{(-x)^k \phi^{(k)}(x)}{k!}
```

The [WilliamsonTransforms.jl](https://github.com/lrnv/WilliamsonTransforms.jl) package implements this transfromation (and its inverse, the Williamson d-transfrom) in all generality. It returns this cumulative distribution function in the form of the corresponding random variable `<:Distributions.ContinuousUnivariateDistribution` from `Distributions.jl`. You may then compute :
The [WilliamsonTransforms.jl](https://github.com/lrnv/WilliamsonTransforms.jl) package implements this transformation (and its inverse, the Williamson d-transfrom) in all generality. It returns this cumulative distribution function in the form of the corresponding random variable `<:Distributions.ContinuousUnivariateDistribution` from `Distributions.jl`. You may then compute :
* The cdf via `Distributions.cdf`
* The pdf via `Distributions.pdf` and the logpdf via `Distributions.logpdf`
* Samples from the distribution via `rand(X,n)`
Expand Down Expand Up @@ -139,4 +139,4 @@ ArchimedeanCopula
```@bibliography
Pages = ["generalities.md"]
Canonical = false
```
```
12 changes: 6 additions & 6 deletions src/EllipticalCopula.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
This is an abstract type. It implements an interface for all Elliptical copulas. We construct internally elliptical copulas using the sklar's theorem, by considering the copula ``C`` to be defined as :
```math
C = F `\\circ (F_1^{-1},...,F_d^{-1}),
C = F \\circ (F_1^{-1},...,F_d^{-1}),
```
where ``F`` and ``F_1,...,F_d`` are respectively the multivariate distribution function of some elliptical random vector and the univaraite distribution function of its marginals. For a type `MyCop <: EllipitcalCopula`, it is necessary to implement the following methods:
where ``F`` and ``F_1,...,F_d`` are respectively the multivariate distribution function of some elliptical random vector and the univariate distribution function of its marginals. For a type `MyCop <: EllipitcalCopula`, it is necessary to implement the following methods:
- `N(::Type{MyCOp})`, returning the constructor of the elliptical random vector from its corelation matrix. For example, `N(GaussianCopula)` simply returns `MvNormal` from `Distributions.jl`.
- `U(::Type{MyCOp})`, returning the constructor for the univariate marginal, usually in standardized form. For exemple, `U(GaussianCopula)` returns `Normal` from `Distributions.jl`.
- `N(::Type{MyCOp})`, returning the constructor of the elliptical random vector from its correlation matrix. For example, `N(GaussianCopula)` simply returns `MvNormal` from `Distributions.jl`.
- `U(::Type{MyCOp})`, returning the constructor for the univariate marginal, usually in standardized form. For example, `U(GaussianCopula)` returns `Normal` from `Distributions.jl`.
From these two functions, the abstract type provide a fully functional copula.
From these two functions, the abstract type provides a fully functional copula.
# Details
Expand Down Expand Up @@ -60,4 +60,4 @@ function make_cor!(Σ)
Σ[i,j] *= σ[i] .* σ[j]
end
end
end
end
6 changes: 3 additions & 3 deletions src/EllipticalCopulas/GaussianCopula.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ Constructor
GaussianCopula(Σ)
The [Gaussian Copula](https://en.wikipedia.org/wiki/Copula_(probability_theory)#Gaussian_copula) is the
copula of a [Multivariate normal distribution](http://en.wikipedia.org/wiki/Multivariate_normal_distribution). It is constructed as :
copula of a [Multivariate normal distribution](http://en.wikipedia.org/wiki/Multivariate_normal_distribution). It is constructed as:
```math
C(\\mathbf{x}; \\boldsymbol{\\Sigma}) = F_{\\Sigma}(F_{\\Sigma,i}^{-1}(x_i),i\\in 1,...d)
```
where ``F_{\\Sigma}`` is a cdf of a gaussina random vector and `F_{\\Sigma,i}` is the ith marignal cdf, while ```\\Sigma`` is the covariance matrix.
where ``F_{\\Sigma}`` is a cdf of a gaussian random vector and `F_{\\Sigma,i}` is the ith marginal cdf, while ``\\Sigma`` is the covariance matrix.
It can be constructed in Julia via:
```julia
Expand Down Expand Up @@ -59,4 +59,4 @@ function _cdf(C::CT,u) where {CT<:GaussianCopula}
μ = zeros(T,d)
lb = repeat([T(-Inf)],d)
return MvNormalCDF.mvnormcdf(μ, C.Σ, lb, x)[1]
end
end

0 comments on commit 26015da

Please sign in to comment.