← Previous: Uncertainty Analysis | Back to Index | Next: Multivariate Distributions →
Copulas separate the dependence structure of multivariate distributions from their marginal distributions. This separation is formalized by Sklar's theorem [1]: for any multivariate distribution
A copula
- Model marginal distributions independently (each can be any distribution)
- Model dependence separately via the copula
- Combine them to form any joint distribution
The Numerics library provides bivariate copula functions for modeling dependence between two random variables in risk assessment and multivariate analysis.
Elliptical copulas are derived from elliptical distributions (Normal, Student's t). They produce symmetric dependence structures.
The Normal copula is derived from the bivariate normal distribution. Its density function is:
where
The Normal copula has no tail dependence (
The relationship between Kendall's tau and the copula parameter is:
using Numerics.Distributions.Copulas;
// Normal (Gaussian) copula with correlation rho
double rho = 0.7; // Correlation coefficient
var normalCopula = new NormalCopula(rho);
// Evaluate copula density
double u1 = 0.3, u2 = 0.7;
double density = normalCopula.PDF(u1, u2);
Console.WriteLine($"Normal copula density: {density:F4}");The Student's t copula extends the Normal copula by adding symmetric tail dependence. Its density involves the bivariate Student's t distribution with
where
The tail dependence coefficient is:
As
// t-copula with 5 degrees of freedom
int nu = 5;
var tCopula = new StudentTCopula(rho, nu);
double density = tCopula.PDF(u1, u2);
Console.WriteLine($"t-copula density: {density:F4}");
Console.WriteLine($"Upper tail dependence: {tCopula.UpperTailDependence:F4}");
Console.WriteLine($"Lower tail dependence: {tCopula.LowerTailDependence:F4}");Archimedean copulas are defined through a generator function
The copula density is obtained by differentiating:
Each Archimedean family is characterized by its generator, which determines the copula's dependence properties. The Numerics library implements five Archimedean families:
The Clayton copula exhibits lower tail dependence, making it suitable for modeling the joint occurrence of low values (e.g., concurrent droughts in multiple watersheds).
| Property | Value |
|---|---|
| Generator | |
| Inverse generator | |
| CDF | |
| Parameter range | |
| Kendall's tau | |
| Lower tail dependence | |
| Upper tail dependence |
// Clayton copula (lower tail dependence), θ ∈ (0, ∞)
var claytonCopula = new ClaytonCopula(2.0);The Gumbel copula exhibits upper tail dependence, making it the natural choice for modeling joint flood events (e.g., concurrent high flows in tributaries).
| Property | Value |
|---|---|
| Generator | |
| Inverse generator | |
| Parameter range | |
| Kendall's tau | |
| Lower tail dependence | |
| Upper tail dependence |
// Gumbel copula (upper tail dependence), θ ∈ [1, ∞)
var gumbelCopula = new GumbelCopula(2.0);The Frank copula has no tail dependence and produces a symmetric dependence structure. It is useful for modeling moderate, general correlation without emphasizing joint extremes.
| Property | Value |
|---|---|
| Generator | |
| CDF | |
| Parameter range | |
| Tail dependence |
The Frank copula is the only Archimedean copula that allows both positive and negative dependence (
// Frank copula (no tail dependence), θ ∈ (-∞, ∞) \ {0}
var frankCopula = new FrankCopula(5.0);The Joe copula has upper tail dependence, similar to the Gumbel copula, but with a different dependence structure in the body of the distribution.
| Property | Value |
|---|---|
| Generator | |
| Parameter range | |
| Lower tail dependence | |
| Upper tail dependence |
// Joe copula (upper tail dependence), θ ∈ [1, ∞)
var joeCopula = new JoeCopula(2.0);The AMH copula models weak dependence structures and has no tail dependence. Its parameter range is limited to
| Property | Value |
|---|---|
| Generator | |
| Parameter range | |
| Kendall's tau range | |
| Tail dependence |
// Ali-Mikhail-Haq copula (weak dependence), θ ∈ [-1, 1]
var amhCopula = new AMHCopula(0.5);| Copula | Tail Dependence | Parameter Range | Best For |
|---|---|---|---|
| Normal | None | General symmetric dependence | |
| Student-t | Symmetric |
|
Heavy-tailed joint extremes |
| Clayton | Lower tail | Joint low extremes (droughts) | |
| Gumbel | Upper tail | Joint high extremes (floods) | |
| Frank | None | Moderate symmetric dependence | |
| Joe | Upper tail | Strong upper tail dependence | |
| AMH | None | Weak dependence structures |
The copula parameter can be estimated from data using the relationship between Kendall's tau and the copula parameter. The Numerics library provides the SetThetaFromTau method for Archimedean copulas:
using System.Linq;
using Numerics.Data.Statistics;
using Numerics.Distributions;
using Numerics.Distributions.Copulas;
// Sample paired observations (e.g., peak flow and volume)
double[] x = { 1200, 1500, 1100, 1800, 1350, 1600, 1250, 1450, 1900, 1300 };
double[] y = { 45, 52, 42, 65, 48, 58, 44, 51, 68, 46 };
// Step 1: Fit marginal distributions
var gevX = new GeneralizedExtremeValue();
gevX.Estimate(x, ParameterEstimationMethod.MethodOfLinearMoments);
var gevY = new GeneralizedExtremeValue();
gevY.Estimate(y, ParameterEstimationMethod.MethodOfLinearMoments);
// Step 2: Transform to uniform margins using fitted CDFs
double[] u = x.Select(xi => gevX.CDF(xi)).ToArray();
double[] v = y.Select(yi => gevY.CDF(yi)).ToArray();
// Step 3: Estimate copula parameter using rank correlation
double tau = Correlation.KendallsTau(x, y);
Console.WriteLine($"Kendall's tau: {tau:F3}");
// The tau-to-parameter relationships:
// Clayton: θ = 2τ/(1-τ) for τ > 0
// Gumbel: θ = 1/(1-τ) for τ > 0
// Normal: ρ = sin(πτ/2)Alternatively, copula parameters can be estimated by maximizing the pseudo-log-likelihood, which uses only the copula density evaluated at empirical probability-integral transforms:
// The BivariateCopula base class provides likelihood methods:
// PseudoLogLikelihood — copula-only log-likelihood
// IFMLogLikelihood — inference functions for margins (with pre-estimated marginals)
// LogLikelihood — full log-likelihood (copula + marginals)Construct a bivariate distribution with arbitrary marginals and specified dependence:
using System.Linq;
using Numerics.Data.Statistics;
using Numerics.Distributions;
using Numerics.Distributions.Copulas;
// Step 1: Define marginal distributions
var margin1 = new LogNormal(4.0, 0.5); // Streamflow
var margin2 = new Gumbel(100, 20); // Peak stage
// Step 2: Define dependence via copula
double rho = 0.8; // Strong positive correlation
var copula = new NormalCopula(rho);
// Step 3: Sample from joint distribution
int n = 1000;
var samples = copula.GenerateRandomValues(n);
// Transform uniforms to actual distributions
double[] flow = new double[n];
double[] stage = new double[n];
for (int i = 0; i < n; i++)
{
flow[i] = margin1.InverseCDF(samples[i, 0]);
stage[i] = margin2.InverseCDF(samples[i, 1]);
}
Console.WriteLine($"Generated {n} correlated samples");
Console.WriteLine($"Flow range: [{flow.Min():F1}, {flow.Max():F1}]");
Console.WriteLine($"Stage range: [{stage.Min():F1}, {stage.Max():F1}]");
// Empirical correlation
var correlation = Correlation.Pearson(flow, stage);
Console.WriteLine($"Sample correlation: {correlation:F3}");The sampling algorithm uses the conditional method: generate GenerateRandomValues method uses Latin Hypercube sampling for better coverage of the probability space.
For dam safety, estimate probability of joint high flow and high stage:
// Critical thresholds
double flowThreshold = 10000; // cfs
double stageThreshold = 150; // feet
// Compute joint exceedance probability
double u1 = margin1.CDF(flowThreshold);
double u2 = margin2.CDF(stageThreshold);
// P(Flow > threshold AND Stage > threshold)
// = 1 - u1 - u2 + C(u1, u2)
double jointExceedance = copula.ANDJointExceedanceProbability(u1, u2);
Console.WriteLine($"Joint exceedance probability: {jointExceedance:E4}");
Console.WriteLine($"Return period: {1.0 / jointExceedance:F1} years");The AND joint exceedance probability is computed as
Given flow, what is the conditional distribution of stage? The conditional CDF can be computed numerically using the copula CDF via partial differentiation:
// Observed flow
double observedFlow = 12000;
double uFlow = margin1.CDF(observedFlow);
// Approximate the conditional CDF: dC(u,v)/du via finite difference
Func<double, double> conditionalCDF = (stage) =>
{
double uStage = margin2.CDF(stage);
double du = 1e-6;
double uPlus = Math.Min(uFlow + du, 1.0);
double uMinus = Math.Max(uFlow - du, 0.0);
return (copula.CDF(uPlus, uStage) - copula.CDF(uMinus, uStage)) / (uPlus - uMinus);
};
// Conditional probability at specific values
Console.WriteLine($"Given flow = {observedFlow:F0} cfs:");
Console.WriteLine($" P(Stage > 15 | Flow = {observedFlow}) = {1 - conditionalCDF(15):P1}");Tail dependence measures the probability of observing an extreme value in one variable given that the other is already extreme. The upper tail dependence coefficient is:
The lower tail dependence coefficient is defined analogously as
A copula has tail dependence if
// Tail dependence comparison using UpperTailDependence / LowerTailDependence properties
Console.WriteLine("Tail Dependence Properties:");
Console.WriteLine($" Student-t(ρ=0.7, ν=5): λ_U = {new StudentTCopula(0.7, 5).UpperTailDependence:F4}");
Console.WriteLine($" Student-t(ρ=0.7, ν=20): λ_U = {new StudentTCopula(0.7, 20).UpperTailDependence:F4}");
Console.WriteLine($" Normal(ρ=0.7): λ_U = {new NormalCopula(0.7).UpperTailDependence:F4}");
Console.WriteLine($" Clayton(θ=2): λ_L = {new ClaytonCopula(2.0).LowerTailDependence:F4}");
Console.WriteLine($" Gumbel(θ=2): λ_U = {new GumbelCopula(2.0).UpperTailDependence:F4}");
Console.WriteLine($" Frank(θ=5): λ_U = {new FrankCopula(5.0).UpperTailDependence:F4}");For problems with more than two variables, there are several approaches:
- Multivariate Normal distribution: Use when Gaussian dependence is appropriate
- Nested Archimedean copulas: Hierarchical structure for grouped variables
- Vine copulas: Build from pairwise bivariate copulas (C-vine, D-vine, R-vine)
For hydrologic applications with 3+ correlated variables (e.g., peak flow, volume, duration), consider using the Multivariate Normal distribution for the initial analysis, which is available in the Numerics.Distributions namespace. See the Multivariate Distributions documentation for details.
-
Check for dependence: Use scatter plots and correlation tests before applying copulas. Kendall's tau is preferred over Pearson's
$r$ because it is rank-based and invariant under monotonic transformations - Choose copula family: Match tail behavior to application — Gumbel for joint highs, Clayton for joint lows, Student-t for symmetric tail dependence
- Validate fit: Compare empirical and theoretical joint exceedance curves. Use the pseudo-log-likelihood to compare copula families
-
Sample size: Need sufficient data (
$n > 50$ –$100$) for reliable parameter estimation via Kendall's tau - Non-stationarity: Check if dependence structure is time-varying — a copula fit to historical data may not represent future conditions
- Assumes marginals are correctly specified — copula inference is only valid when the marginal distributions are well-fitted
- Bivariate copulas may not capture complex nonlinear dependencies in higher dimensions
- Parameter estimation is challenging with limited data, especially for tail dependence
- Tail dependence is difficult to estimate from finite samples — the tail region by definition has few observations
[1] R. B. Nelsen, An Introduction to Copulas, 2nd ed., New York: Springer, 2006.
[2] H. Joe, Dependence Modeling with Copulas, Boca Raton: CRC Press, 2014.
[3] C. Genest and A.-C. Favre, "Everything you always wanted to know about copula modeling but were afraid to ask," Journal of Hydrologic Engineering, vol. 12, no. 4, pp. 347-368, 2007.
[4] G. Salvadori, C. De Michele, N. T. Kottegoda and R. Rosso, Extremes in Nature: An Approach Using Copulas, Dordrecht: Springer, 2007.
← Previous: Uncertainty Analysis | Back to Index | Next: Multivariate Distributions →