I'm trying to model a bivariate distribution using copulas in R. See image below for the pairs plot of the data. Variable 1 can be modeled nicely using a gamma distribution, but variable 2 fails miserably. I think the only way variable 2 could be modeled is by a customized piece-wise distribution?

Pairs plot of my bivariate distribution

See the histograms below:

The green bars indicate the distribution of the observed data, and the blue bars indicate the distribution of the sampled data with gamma distributions with rate and shape as in the title of the graph.

Histograms of marginal distributions

I've been folling the tutorial here:


Using the copula and VineCopula packages, using BiCopSelect, it tells me that I need to use "Rotated Tawn type 1 270 degrees", familycode = 134, parameter1 = -2.669133 parameter 2= 0.1562118, although I have no idea how to achieve this, "Tawn type" doesn't seem to be one of the standard family names.

So running BiCopSelect again but this time having the input parameter familyset = c(1,2,3,4,5,6,7) , restricting to the standard family types, it tells me I should use Bivariate copula: Frank (par = -0.23, tau = -0.03).

Code I used:


#Build the distribution
my_dist <- mvdc(frankCopula(param = -0.2279837, dim = 2), margins = c("gamma","gamma"), paramMargins = list(list(shape = 0.6524258, rate = 0.01375649), list(shape = 1.637544, rate = 0.01215565)))

# Generate random sample observations from the multivariate distribution
v <- rMvdc(5000, my_dist)
# Compute the density
pdf_mvd <- dMvdc(v, my_dist)
# Compute the CDF
cdf_mvd <- pMvdc(v, my_dist)

# 3D plain scatterplot of the generated bivariate distribution
par(mfrow = c(1, 2))
scatterplot3d(v[,1],v[,2], pdf_mvd, color="red", main="Density", xlab = "u1", ylab="u2", zlab="pMvdc",pch=".")
scatterplot3d(v[,1],v[,2], cdf_mvd, color="red", main="CDF", xlab = "u1", ylab="u2", zlab="pMvdc",pch=".")
persp(my_dist, dMvdc, xlim = c(-4, 4), ylim=c(0, 2), main = "Density")
contour(my_dist, dMvdc, xlim = c(-4, 4), ylim=c(0, 2), main = "Contour plot")
persp(my_dist, pMvdc, xlim = c(-4, 4), ylim=c(0, 2), main = "CDF")
contour(my_dist, pMvdc, xlim = c(-4, 4), ylim=c(0, 2), main = "Contour plot")

Which produced the following plots:

Density plot for bivariate distribution

CDF plot for bivariate distribution

However the density plot doesn't look correct because the density is supposed to be the highest when var1 = 0 and var2 = 0, however the density is the highest when var1 = 0 and var2 is large.

Another problem is that I'm not sure what to do about var2's distribution! It's obviously not correct using gamma, but it is not a negative binomial or some other standard distribution either, and I think the margins field in the function mvdc only accepts strings of the standard distributions. Is there any way of defining my own distribution as input into the mvdc function?


1 Answer 1


About the perspective and contour plots looking strange: It's true that the maximum of the density is not at $(0,0)$, but also you are plotting only a tiny part of the distribution. Try different xlim and ylim arguments, e.g.,

persp(my_dist, dMvdc, xlim = c(0, 300), ylim = c(0, 300), n.grid = 51)

enter image description here

About custom marginal distributions for the copula model: That's possible simply defining a density function dsomething, a distribution function psomething, and (if you need sampling) a quantile function qsomething in the global environment of R. Here is an example with a Gaussian mixture distribution; I made up some parameter values:

dgmix <- function(x, p1, mean1, sd1, mean2, sd2) {
  p1 * dnorm(x, mean1, sd1) + (1 - p1) * dnorm(x, mean2, sd2)

pgmix <- function(x, p1, mean1, sd1, mean2, sd2) {
  p1 * pnorm(x, mean1, sd1) + (1 - p1) * pnorm(x, mean2, sd2)

curve(dgmix(x, p1 = 0.3, mean1 = 0, sd1 = 20, mean2 = 200, sd2 = 100),
      from = -50, to = 300, n = 1001)

paramMargins <- list(list(shape = 0.652, rate = 0.014),
                     list(p1 = 0.3, mean1 = 0, sd1 = 20,
                          mean2 = 200, sd2 = 100))

my_dist <- mvdc(copula = frankCopula(param = -0.228),
                margins = c("gamma", "gmix"),
                paramMargins = paramMargins)

persp(my_dist, dMvdc, xlim = c(0, 300), ylim = c(-50, 300), n.grid = 51)

enter image description here enter image description here

  • $\begingroup$ A question: How would you go about specifying qgmix? It's basically a case of trying to find the quantile function of the sum of two independent distributions? The only way I can think of how to do this is if we knew the actual formula and integrate? $\endgroup$
    – Kelian
    Commented Jan 10, 2018 at 2:06
  • $\begingroup$ Oh wait not integrate, more like summation, because the distribution is discrete. But wouldn't we still need to know the formula representing the distribution? $\endgroup$
    – Kelian
    Commented Jan 10, 2018 at 3:21
  • $\begingroup$ Unfortunately, the quantile function of a Gaussian mixture does not have a closed form. You will need to use some numerical method (such as Newton-Raphson) with the distribution function. Actually, there are better ways to sample from a Gaussian mixture, but those are harder to use with the copula package for R... $\endgroup$
    – bbrot
    Commented Jan 10, 2018 at 10:43
  • $\begingroup$ For more information, see the following questions: stats.stackexchange.com/questions/177049/…, stats.stackexchange.com/questions/73028/… $\endgroup$
    – bbrot
    Commented Jan 10, 2018 at 10:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.