Implements the Lilliefors-corrected Kolmogorov-Smirnov test for use in
goodness-of-fit tests, suitable when population parameters are unknown and
must be estimated by sample statistics. It uses Monte Carlo simulation to
estimate p-values. Using a modification of
ks.test, it can be used with a variety of continuous
distributions, including normal, lognormal, univariate mixtures of normals,
uniform, loguniform, exponential, gamma, and Weibull distributions. The Monte
Carlo algorithm can run 'in parallel.'
A numeric vector of data values (observed sample).
Character string naming a cumulative distribution function. Case insensitive. Only continuous CDFs are valid. Allowed CDFs include:
Number of replicates to use in simulation algorithm.
Numeric vector of mixture components to consider, for mixture models
For mixture models, character string determining whether to
allow equal-variance mixture components (
Logical value that switches between running Monte Carlo
algorithm in parallel (if
Numeric value to control how many cores to build when running in
The function builds a simulation distribution
D.sim of length
nreps by drawing random samples from the specified continuous
cdf with parameters calculated from the
x. Observed statistic
D and simulated
test statistics are calculated using a simplified version of
nreps = 4999 provides accurate p-values.
nreps = 1999 is sufficient for most cases, and computationally
faster when dealing with more complicated distributions (such as univariate
normal mixtures, gamma, and Weibull). See below for potentially faster
The p-value is calculated as the number of Monte Carlo samples with
test statistics D as extreme as or more extreme than that in the
D.obs, divided by the
nreps number of Monte
Carlo samples. A value of 1 is added to both the numerator and denominator
to allow the observed sample to be represented within the null distribution
(Manly 2004); this has the benefit of avoiding nonsensical
0.000 and accounts for the fact that the p-value is an estimate.
Parameter estimates are calculated for the specified continuous
distribution, using maximum-likelihood estimates. When testing against the
gamma and Weibull distributions,
MASS::fitdistr is used
to calculate parameter estimates using maximum likelihood optimization,
with sensible starting values. Because this incorporates an optimization
routine, the simulation algorithm can be slow if using large
or problematic samples. Warnings often occur during these optimizations,
caused by difficulties estimating sample statistic standard errors. Because
such SEs are not used in the Lilliefors-corrected simulation algorithm,
warnings are suppressed during these optimizations.
Sample statistics for the (univariate) normal mixture distribution
pmixnorm are calculated using package
uses BIC to identify the optimal mixture model for the sample, and the EM
algorithm to calculate parameter estimates for this model. The number of
G (with default allowing up to 9 components),
variance model (whether equal
E or variable
V variance), and
component statistics (
sds, and mixing proportions
pro) are estimated from the sample when calculating
passed internally when creating random Monte Carlo samples. It is possible
that some of these samples may differ in their optimal
example a two-component input sample might yield a three-component random
sample within the simulation distribution). This can be constrained by
specifying that simulation BIC-optimizations only consider
Be aware that constraining
G changes the null hypothesis. The
G = 1:9) null hypothesis is that a sample was drawn from
G = 1:9-component mixture distribution. Specifying a
particular value, such as
G = 2, restricts the null hypothesis to
particular mixture distributions with just
G components, even if
simulated samples might better be represented as different mixture models.
LcKS(cdf = "pmixnorm") test implements two control loops to
avoid errors caused by this constraint and when working with problematic
samples. The first loop occurs during model-selection for the observed
x, and allows for estimation of parameters for the
second-best model when those for the optimal model are not able to be
calculated by the EM algorithm. A second loop occurs during the simulation
algorithm, rejecting samples that cannot be fit by the mixture model
specified by the observed sample
x. Such problematic cases are most
common when the observed or simulated samples have a component(s) with very
small variance (i.e., duplicate observations) or when a Monte Carlo sample
cannot be fit by the specified
Parellel computing can be implemented using
parallel = TRUE, using
the operating-system versatile
foreach infrastructure, using a default
detectCores - 1 number of cores. Parallel computing
is generally advisable for the more complicated cumulative density
functions (i.e., univariate normal mixture, gamma, Weibull), where maximum
likelihood estimation is time-intensive, but is generally not advisable for
density functions with quickly calculated sample statistics (i.e., other
distribution functions). Warnings within the function provide sensible
recommendations, but users are encouraged to experiment to discover their
fastest implementation for their individual cases.
A list containing the following components:
The value of the test statistic D for the observed sample.
Simulation distribution of test statistics, with
p-value of the test, calculated as (∑(D.sim > D.obs) + 1) / (nreps + 1).
The Kolmogorov-Smirnov (such as
ks.test) is only valid as a
goodness-of-fit test when the population parameters are known. This is
typically not the case in practice. This invalidation occurs because
estimating the parameters changes the null distribution of the test
statistic; i.e., using the sample to estimate population parameters brings
the Kolmogorov-Smirnov test statistic D closer to the null
distribution than it would be under the hypothesis where the population
parameters are known. In other words, it is biased and results in increased
Type II error rates. Lilliefors (1967, 1969) provided a solution, using
Monte Carlo simulation to approximate the shape of the null distribution
when the sample statistics are used to estimate population parameters, and
to use this null distribution as the basis for critical values. The
LcKS generalizes this solution for a range of continuous
Phil Novack-Gottshall email@example.com, based on code from Charles Geyer (University of Minnesota).
Lilliefors, H. W. 1967. On the Kolmogorov-Smirnov test for normality with mean and variance unknown. Journal of the American Statistical Association 62(318):399-402.
Lilliefors, H. W. 1969. On the Kolmogorov-Smirnov test for the exponential distribution with mean unknown. Journal of the American Statistical Association 64(325):387-389.
Manly, B. F. J. 2004. Randomization, Bootstrap and Monte Carlo Methods in Biology. Chapman & Hall, Cornwall, Great Britain.
Parsons, F. G., and P. H. Wirsching. 1982. A Kolmogorov-Smirnov goodness-of-fit test for the two-parameter Weibull distribution when the parameters are estimated from the data. Microelectronics Reliability 22(2):163-167.
Distributions for standard cumulative
plunif for the loguniform cumulative
distribution function, and
pmixnorm for the univariate normal
mixture cumulative distribution function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
x <- runif(200) Lc <- LcKS(x, cdf = "pnorm", nreps = 999) hist(Lc$D.sim) abline(v = Lc$D.obs, lty = 2) print(Lc, max = 50) # Print first 50 simulated statistics # Approximate p-value (usually) << 0.05 # Confirmation uncorrected version has increased Type II error rate when # using sample statistics to estimate parameters: ks.test(x, "pnorm", mean(x), sd(x)) # p-value always larger, (usually) > 0.05 # Confirm critical values for normal distribution are correct nreps <- 9999 x <- rnorm(25) Lc <- LcKS(x, "pnorm", nreps = nreps) sim.Ds <- sort(Lc$D.sim) crit <- round(c(.8, .85, .9, .95, .99) * nreps, 0) # Lilliefors' (1967) critical values, using improved values from # Parsons & Wirsching (1982) (for n = 25): # 0.141 0.148 0.157 0.172 0.201 round(sim.Ds[crit], 3) # Approximately the same critical values # Confirm critical values for exponential are the same as reported by Lilliefors (1969) nreps <- 9999 x <- rexp(25) Lc <- LcKS(x, "pexp", nreps = nreps) sim.Ds <- sort(Lc$D.sim) crit <- round(c(.8, .85, .9, .95, .99) * nreps, 0) # Lilliefors' (1969) critical values (for n = 25): # 0.170 0.180 0.191 0.210 0.247 round(sim.Ds[crit], 3) # Approximately the same critical values ## Not run: # Gamma and Weibull tests require functions from the 'MASS' package # Takes time for maximum likelihood optimization of statistics require(MASS) x <- runif(100, min = 1, max = 100) Lc <- LcKS(x, cdf = "pgamma", nreps = 499) Lc$p.value # Confirm critical values for Weibull the same as reported by Parsons & Wirsching (1982) nreps <- 9999 x <- rweibull(25, shape = 1, scale = 1) Lc <- LcKS(x, "pweibull", nreps = nreps) sim.Ds <- sort(Lc$D.sim) crit <- round(c(.8, .85, .9, .95, .99) * nreps, 0) # Parsons & Wirsching (1982) critical values (for n = 25): # 0.141 0.148 0.157 0.172 0.201 round(sim.Ds[crit], 3) # Approximately the same critical values # Mixture test requires functions from the 'mclust' package # Takes time to identify model parameters require(mclust) x <- rmixnorm(200, mean = c(10, 20), sd = 2, pro = c(1,3)) Lc <- LcKS(x, cdf = "pmixnorm", nreps = 499, G = 1:9) # Default G (1:9) takes long time Lc$p.value G <- Mclust(x)$parameters$variance$G # Optimal model has only two components Lc <- LcKS(x, cdf = "pmixnorm", nreps = 499, G = G) # Restricting to likely G saves time # But note changes null hypothesis: now testing against just two-component mixture Lc$p.value # Running 'in parallel' require(doParallel) set.seed(3124) x <- rmixnorm(300, mean = c(110, 190, 200), sd = c(3, 15, .1), pro = c(1, 3, 1)) system.time(LcKS(x, "pgamma")) system.time(LcKS(x, "pgamma", parallel = TRUE)) # Should be faster ## End(Not run)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.