VGAM (version 1.0-4)

mix2normal: Mixture of Two Univariate Normal Distributions


Estimates the five parameters of a mixture of two univariate normal distributions by maximum likelihood estimation.


mix2normal(lphi = "logit", lmu = "identitylink", lsd = "loge",
           iphi = 0.5, imu1 = NULL, imu2 = NULL, isd1 = NULL, isd2 = NULL,
           qmu = c(0.2, 0.8), = TRUE, nsimEIM = 100, zero = "phi")



Link functions for the parameters \(\phi\), \(\mu\), and \(\sigma\). See Links for more choices.


Initial value for \(\phi\), whose value must lie between 0 and 1.

imu1, imu2

Optional initial value for \(\mu_1\) and \(\mu_2\). The default is to compute initial values internally using the argument qmu.

isd1, isd2

Optional initial value for \(\sigma_1\) and \(\sigma_2\). The default is to compute initial values internally based on the argument qmu. Currently these are not great, therefore using these arguments where practical is a good idea.


Vector with two values giving the probabilities relating to the sample quantiles for obtaining initial values for \(\mu_1\) and \(\mu_2\). The two values are fed in as the probs argument into quantile.

Logical indicating whether the two standard deviations should be constrained to be equal. If TRUE then the appropriate constraint matrices will be used.


May be an integer vector specifying which linear/additive predictors are modelled as intercept-only. If given, the value or values can be from the set \(\{1,2,\ldots,5\}\). The default is the first one only, meaning \(\phi\) is a single parameter even when there are explanatory variables. Set zero = NULL to model all linear/additive predictors as functions of the explanatory variables. See CommonVGAMffArguments for more information.


An object of class "vglmff" (see vglmff-class). The object is used by modelling functions such as vglm, and vgam.


Numerical problems can occur and half-stepping is not uncommon. If failure to converge occurs, try inputting better initial values, e.g., by using iphi, qmu, imu1, imu2, isd1, isd2, etc.

This VGAM family function is experimental and should be used with care.


The probability density function can be loosely written as $$f(y) = \phi \, N(\mu_1,\sigma_1) + (1-\phi) \, N(\mu_2, \sigma_2)$$ where \(\phi\) is the probability an observation belongs to the first group. The parameters \(\mu_1\) and \(\mu_2\) are the means, and \(\sigma_1\) and \(\sigma_2\) are the standard deviations. The parameter \(\phi\) satisfies \(0 < \phi < 1\). The mean of \(Y\) is \(\phi \mu_1 + (1-\phi) \mu_2\) and this is returned as the fitted values. By default, the five linear/additive predictors are \((logit(\phi), \mu_1, \log(\sigma_1), \mu_2, \log(\sigma_2))^T\). If = TRUE then \(\sigma_1 = \sigma_2\) is enforced.


McLachlan, G. J. and Peel, D. (2000) Finite Mixture Models. New York: Wiley.

Everitt, B. S. and Hand, D. J. (1981) Finite Mixture Distributions. London: Chapman & Hall.

See Also

uninormal, Normal, mix2poisson.


Run this code
 mu1 <-  99; mu2 <- 150; nn <- 1000
sd1 <- sd2 <- exp(3)
(phi <- logit(-1, inverse = TRUE))
mdata <- data.frame(y = ifelse(runif(nn) < phi, rnorm(nn, mu1, sd1),
                                                rnorm(nn, mu2, sd2)))
fit <- vglm(y ~ 1, mix2normal( = TRUE), data = mdata)

# Compare the results
cfit <- coef(fit)
round(rbind('Estimated' = c(logit(cfit[1], inverse = TRUE),
            cfit[2], exp(cfit[3]), cfit[4]),
            'Truth' = c(phi, mu1, sd1, mu2)), digits = 2)

# Plot the results
xx <- with(mdata, seq(min(y), max(y), len = 200))
plot(xx, (1-phi) * dnorm(xx, mu2, sd2), type = "l", xlab = "y",
     main = "Orange = estimate, blue = truth",
     col = "blue", ylab = "Density")
phi.est <- logit(coef(fit)[1], inverse = TRUE)
sd.est <- exp(coef(fit)[3])
lines(xx, phi*dnorm(xx, mu1, sd1), col = "blue")
lines(xx, phi.est * dnorm(xx, Coef(fit)[2], sd.est), col = "orange")
lines(xx, (1-phi.est) * dnorm(xx, Coef(fit)[4], sd.est), col = "orange")
abline(v = Coef(fit)[c(2,4)], lty = 2, col = "orange")
abline(v = c(mu1, mu2), lty = 2, col = "blue")
# }

Run the code above in your browser using DataCamp Workspace