DEmixR fits and evaluates two-component
mixture models (normal and lognormal). Rather than the usual
Expectation-Maximization (EM) algorithm, it locates the
maximum-likelihood estimates with a global search — Differential
Evolution, via the DEoptim package — followed by a local
quasi-Newton ("L-BFGS-B") refinement. Global search makes
the fit less sensitive to starting values and local optima, which can be
helpful when the two components overlap strongly.
The code below uses deliberately small data sets and small optimizer settings so that the vignette builds quickly. For real analyses, increase
n_runs,NP, anditermax(see Advanced usage).
| Function | Purpose |
|---|---|
prelim_plots() |
Diagnostic plots (histogram, Q-Q, P-P, log-Q-Q) |
select_best_mixture() |
Compare lognormal vs normal mixtures by BIC |
fit_norm2() |
Fit a two-component normal mixture |
fit_lognorm2() |
Fit a two-component lognormal mixture |
bootstrap_mix2() |
Bootstrap the fitted parameters |
evaluate_init() |
Refine a specific set of starting values |
The objects returned by fit_norm2() /
fit_lognorm2() (class demixr_fit),
bootstrap_mix2() (class demixr_boot) and
select_best_mixture() (class demixr_select)
all carry print() methods, and a demixr_fit
additionally has summary() and plot()
methods.
Start by looking at the data.
set.seed(123)
x <- c(rnorm(150, mean = 0, sd = 1),
rnorm(100, mean = 4, sd = 1))
prelim_plots(x, which = c("hist", "qq"))Passing col_density = NA suppresses the kernel-density
overlay (and the histogram title changes from “Histogram with
density” to “Histogram”):
select_best_mixture() fits both families and keeps the
one with the lower BIC. Its print() method reports the BIC
of each family and the winner.
fit <- fit_norm2(x, n_runs = 1, NP = 25, itermax = 300, quiet = 0)
fit # print.demixr_fit: compact overview
#> Two-component normal mixture (DEmixR)
#> Convergence: successful
#>
#> Parameter estimates:
#> p m1 s1 m2 s2
#> 0.5705 -0.1173 0.8715 3.8607 1.0668
#>
#> logLik = -500.1969 AIC = 1010.3939 BIC = 1028.0012
summary(fit) # summary.demixr_fit: per-component table
#> Two-component normal mixture fitted to n = 250 observations
#>
#> component weight location scale
#> 1 0.5705 -0.1173 0.8715
#> 2 0.4295 3.8607 1.0668
#>
#> logLik = -500.1969, AIC = 1010.3939, BIC = 1028.0012
plot(fit) # plot.demixr_fit: fitted mixture over a histogramThe pieces are also available directly if you need them:
set.seed(123)
y <- c(rlnorm(150, meanlog = 0, sdlog = 0.5),
rlnorm(100, meanlog = 1.6, sdlog = 0.4))
fit_ln <- fit_lognorm2(y, n_runs = 1, NP = 25, itermax = 300, quiet = 0)
fit_ln
#> Two-component lognormal mixture (DEmixR)
#> Convergence: successful
#>
#> Parameter estimates:
#> p m1 s1 m2 s2
#> 0.5491 -0.0879 0.4157 1.5156 0.4387
#>
#> logLik = -453.7858 AIC = 917.5716 BIC = 935.1789
plot(fit_ln)bootstrap_mix2() returns central estimates and
percentile confidence intervals; its print() method shows
both. (B is kept small here for speed.)
set.seed(123)
boot <- bootstrap_mix2(fit_ln, B = 40, parametric = TRUE, quiet = 0)
boot # print.demixr_boot
#> Bootstrap for a two-component lognormal mixture (B = 40, 40 successful)
#>
#> p m1 s1 m2 s2
#> central 0.5452 -0.0789 0.4113 1.5044 0.4412
#> 2.5% 0.4599 -0.1929 0.3571 1.4103 0.3585
#> 97.5% 0.6431 0.0201 0.5015 1.6134 0.4936evaluate_init() runs a single local optimization from
starting values you supply — useful for checking whether a particular
initialization converges. The parameter vector is
c(p, m1, s1, m2, s2).
The chunks in this section are shown for reference and are not executed.
fit_ln <- fit_lognorm2(
y,
NP = 150, # DEoptim population size
n_runs = 20, # independent runs to reduce the chance of a local optimum
itermax = 2000, # maximum iterations per run
parallelType = 1, # parallelize the DEoptim runs
quiet = 2, # verbosity (see below)
par_init = NULL # optional starting values for an extra local search
)Key options
NP: larger populations explore more thoroughly but run
more slowly.n_runs: more runs improve robustness at a roughly
proportional time cost.parallelType: 0 = serial, 1 =
socket cluster (all platforms), 2 = forking
(macOS/Linux).quiet: 0 = silent, 1
= per-run messages plus the DEoptim trace, 2 =
a text progress bar.boot <- bootstrap_mix2(
fit_ln,
B = 500, # number of bootstrap replicates
parametric = TRUE, # parametric (TRUE) or nonparametric (FALSE) resampling
ci_level = 0.90, # confidence level
parallelType = 1,
quiet = 2
)
boot$central # means (normal) or medians (lognormal)
boot$ci # percentile confidence intervalsDEmixR provides a compact workflow for two-component
mixtures: explore the data with prelim_plots(), pick a
family with select_best_mixture(), fit it with
fit_norm2() / fit_lognorm2(), inspect the
result with the
print()/summary()/plot() methods,
and quantify uncertainty with bootstrap_mix2(). The use of
global optimization is intended to make the fit robust to difficult
likelihood surfaces.