R Package Rgof

library(Rgof)
Btest = 200 #Number of Simulation Runs for tests
Bpower = 100 #Number of Simulation Runs for power

Note that Btest and Bpower are very small, so that this vignette does not take to long to run. Therefore none of the p values or powers below are trustworthy.

The package Rgof brings together a number of routines for the goodness-of-fit problem for univariate data. We have a data set \(\pmb{x}\), and we want to test whether it was generated by the probability distribution F.

The highlights of this package are:

set.seed(123)

The Methods

  1. Kolmogorov Smirnov (KS) (Massey 1951), (Kolmogorov 1933), (Smirnov 1948)
  2. Kuiper (K) (Kuiper 1960)
  3. Anderson-Darling (AD) (Anderson and Darling 1952), (Anderson and Darling 1954)
  4. Cramer-vonMises (CvM) (Anderson 1962)
  5. Watson (W)
  6. Zhang’s methods (ZA, ZK, ZC) (Zhang 2002)
  7. Wasserstein p=1 (Wassp1) (E del Barrio 1999)

For all of these tests the distribution of the test statistic under the null hypothesis is found via simulation.

  1. Eight variations of chi square tests, using the formulas by Pearson or based on the likelihood ratio test, bins of equal size or equal probability and both a large number and a small number of bins, 50 and 10 by default. The p values are found using the usual chi square approximation to the null distribution. If parameters are estimated this is done either via the method of minimum chi square (Berkson 1980) or via a user-provided estimator. In all cases bins are combined until all of them have an expected count of at least 5.

There is a very large literature on chi square tests, the oldest of the goodness of fit tests. For a survey see (Rolke and Gutierrez-Gongora 2020).

All the methods above are also implemented for discrete data, except for Zhang’s tests, which have no discrete analog.

It is worth noting that these discrete versions are based on the theoretical ideas of the tests and not on the actual formula of calculation for the continuous case. The test statistics can therefore be different even when applied to the same data. For example, the Anderson-Darling test is based on the distance measure

\[A^2=n\int_{-\infty}^{\infty} \frac{(\hat{F}(x)-F(x))^2}{F(x)(1-F(x))}dF(x) \] where \(F\) is the theoretical distribution function under the null hypothesis and \(\hat{F}\) is the empirical distribution function. In the case of continuous data it can be shown that

\[A^2=-n-\frac1n\sum_{i=1}^n (2i-1)\left(\log F(x_i) +\log[1-F(x_{n+1-i})\right)\] However, for discrete data we have

\[A^2=n\sum_{i=1}^k \frac{(\hat{F}(x_i)-F(x_i))^2}{F(x_i)(1-F(x_i))}\left(F(x_i)-F(x_{i-1}\right)\]

with \(F(x_0)=0\). For the other methods we use the discrete versions of (Choulakian et al. 1994): with \(Z_j=\hat{F}(x_j)-F(x_j)\), \(p_j=F(x_j)-F(x_{j-1})\) and \(t_j=(p_j+p_{j+1})/2\), where \(p_{k+1}=p_1\), they are \(CvM=n\sum_{j=1}^k Z_j^2t_j\), \(W=n\sum_{j=1}^k (Z_j-\bar{Z})^2t_j\) with \(\bar{Z}=\sum_j Z_jt_j\), and the version of the Anderson-Darling statistic actually used is \(A^2=n\sum_{j=1}^{k-1} Z_j^2t_j/(F(x_j)(1-F(x_j)))\). Unlike the weights \(p_j\) in the formula above, the weights \(t_j\) make the statistics invariant under a reversal of the order of the values, and \(W\) invariant under a change of the starting point for circular data. Moreover \(KS=\max_j|Z_j|\), \(K=\max_j Z_j+\max_j(-Z_j)\) (with \(Z_0=0\) included), and \(Wassp1=\sum_j |Z_j|(x_{j+1}-x_j)\).

In the continuous case \(\hat{F}\) is a step function but \(F\) is continuous, and therefore \(A^2>0\). In the discrete case however\(A^2=0\) is possible. This shows that the two cases are fundamentally different and therefore require different formulas for the test statistic.

As for continuous data null distributions are found using simulation. In fact in the case of discrete data none of the tests has a known distribution for the test statistic under the null hypothesis.

  1. Four variations of chi square tests, using the formulas by Pearson and log-likelihood as well as a large number and a small number of bins. Again the routine combines bins until all have expected counts greater than 5, and the chi square approximation is used to find p values. The combination of bins is done in such a way that the bins remain of equal size as much as possible.

In addition there are three tests only available for discrete data:

  1. Data-driven Neyman smooth tests (NS-B and NS-A) (Ledwina 1994), (Rayner and Best 1989). With \(p_j=F(x_j)-F(x_{j-1})\) and the mid-cdf \(u_j=F(x_{j-1})+p_j/2\), the Legendre polynomials in \(2u_j-1\) are made orthonormal with respect to the null probabilities \(p_j\), giving functions \(g_1,..,g_K\) with \(K=\min(10, k-1)\). With \(b_l=\sum_j n_jg_l(x_j)/\sqrt{n}\), where \(n_j\) are the counts, and \(S_m=\sum_{l=1}^m b_l^2\), the statistic is \(S_{m^*}\), where \(m^*\) maximizes \(S_m-m\log n\) (Schwarz’s rule, NS-B) or \(S_m-2m\) (AIC, NS-A).
  2. Berk-Jones (BJ) (Berk and Jones 1979): \(BJ=n\max_j \left[\hat{F}(x_j)\log\frac{\hat{F}(x_j)}{F(x_j)}+(1-\hat{F}(x_j))\log\frac{1-\hat{F}(x_j)}{1-F(x_j)}\right]\), over \(j<k\) with \(0<F(x_j)<1\).

In the power studies (see below) these three tests have the highest average power for discrete data, NS-A especially for alternatives that differ in variance or kurtosis.

These methods can be used for both discrete and histogram data. The main difference between these two is that discrete data has (a countable) number of possible values whereas histogram data has possible ranges of values (the bins). The only method directly affected by this difference is Wassp1, which requires actual values. All other methods ignore the vals argument.

Testing

Discrete (Histogram) Data/Model

Simple Null Hypothesis

We generate a data set of size 1000 from a Binomial distribution with n=20 and success probability 0.5, and then test \(H_0:F=Bin(20, 0.5)\).

vals=0:20 #possible values of random variable
pnull=function()  pbinom(0:20, 20, 0.5)  # cumulative distribution function (cdf)
rnull = function() table(c(0:20, rbinom(1000, 20, 0.5)))-1 
# generate data under the null hypothesis, make sure that vector of counts has 
#same length as vals, possibly 0.
  • Null Hypothesis is true
x = rnull()
# Basic Test
gof_test(x, vals, pnull, rnull, B=Btest)
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#> 
#> Rgof goodness-of-fit tests
#> Data: discrete  | n = 1000  | B = 200 
#> 
#>  method statistic p.value
#>      KS  0.008901  0.9850
#>       K  0.012620  0.9900
#>      AD  0.129200  0.9950
#>     CvM  0.024230  0.9650
#>       W  0.016740  0.9650
#>  Wassp1  0.034570  0.9950
#>    NS-B  0.091530  0.7650
#>    NS-A  0.091530  0.8300
#>      BJ  0.825400  0.9600
#>     l-P  2.601100  0.9978
#>     s-P  2.002500  0.9914
#>     l-L  2.675200  0.9974
#>     s-L  2.061700  0.9905
#Test with adjusted overall p value
gof_test_adjusted_pvalue(x, vals, pnull, rnull, 
          B=c(Btest, 500), maxProcessor = 1)
#> p values of individual tests:
#> KS :  0.985
#> K :  0.985
#> AD :  1
#> CvM :  0.985
#> W :  0.975
#> Wassp1 :  1
#> NS-B :  0.74
#> NS-A :  0.84
#> BJ :  0.95
#> l-P :  0.9978
#> s-P :  0.9873
#> l-L :  0.9974
#> s-L :  0.9857
#> adjusted p value of combined tests: 0.992
  • Null Hypothesis is false
x = table(c(0:20, rbinom(1000, 20, 0.55)))-1
#true p is 0.55, not 0.5
# Basic Test
gof_test(x, vals, pnull, rnull, B=Btest, doMethod = "all")$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W Wassp1   NS-B   NS-A     BJ    l-P    s-P 
#>      0      0      0      0      0      0      0      0      0      0      0 
#>    l-L    s-L 
#>      0      0
#Test with adjusted overall p value
gof_test_adjusted_pvalue(x, vals, pnull, rnull, 
          B=c(Btest, 500), maxProcessor = 1)
#> p values of individual tests:
#> KS :  0
#> K :  0
#> AD :  0
#> CvM :  0
#> W :  0
#> Wassp1 :  0
#> NS-B :  0
#> NS-A :  0
#> BJ :  0
#> l-P :  0
#> s-P :  0
#> l-L :  0
#> s-L :  0
#> adjusted p value of combined tests: 0.028

Arguments of gof_test for discrete data/model:

  • x: vector with counts (histogram heights). Should have a number for each value of vals, possibly 0.

  • vals: all possible values of discrete random variable, that is all x with \(P(X=x)>0\)

  • pnull: function to find values of cumulative distribution function for each value of vals. Function has no arguments.

  • rnull: function to generate data from true density. Function has no arguments. Function needs to insure that output is a vector with same length as vals.

  • B=5000: number of simulation runs

  • w: function to find importance sampling weights, if needed

  • phat: function to estimate parameters

  • TS: function to find values of user-supplied test statistics

  • TSextra: a list that is passed to TS if any additional info is required.

  • nbins=c(50, 10): number of bins for chi square tests. The first one is already given by the data in the discrete case, for the second bins are joined.

  • rate=0, if not 0 sample size is assumed to have come from a Poisson random variable with rate “rate”.

  • minexpcount=5, minimal expected counts for chi square tests.

  • ChiUsePhat=TRUE, if TRUE uses user supplied function phat for parameter estimation. If false uses method of minimum chi square.

  • maxProcessor=1 if greater than 1 number of cores for parallel processing. Parallel processing is usually not be useful for discrete data as the single thread version generally runs faster.

  • doMethods=“all” names of methods to include

The arguments of gof_test_adjusted_pvalue for discrete data/model are the same, except that the number of simulation runs B is two numbers. The first is used for estimating the individual p values, the second for the adjustment.

Random Sample Size

In some fields like high energy physics it is common that the sample size is not fixed but a random variable drawn from a Poisson distribution with a known rate. Our package runs this as follows:

rnull = function() table(c(0:20, rbinom(rpois(1, 650), 20, 0.5)))-1 
x = rnull()
gof_test(x, vals, pnull, rnull, rate=650,
         B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W Wassp1   NS-B   NS-A     BJ    l-P    s-P 
#> 0.1550 0.0050 0.0500 0.0700 0.0150 0.0400 0.1650 0.0350 0.0800 0.0381 0.0504 
#>    l-L    s-L 
#> 0.0166 0.0263

Composite Null Hypothesis

We generate a data set of size 1000 from a binomial distribution with n=20 and success probability p, and then test F=Bin(20, .). p is estimated from data.

vals=0:20
pnull=function(p=0.5)  pbinom(0:20, 20, ifelse(p>0&&p<1, p, 0.5))  
rnull = function(p=0.5) table(c(0:20, rbinom(1000, 20, p)))-1
phat = function(x) sum(0:20*x)/sum(x)/20
  • Null Hypothesis is true
x = table(c(0:20, rbinom(1000, 20, 0.5)))-1  
gof_test(x, vals, pnull, rnull, phat=phat,
         B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W Wassp1   NS-B   NS-A     BJ    l-P    s-P 
#> 0.7150 0.5800 0.7400 0.6800 0.7150 0.7400 0.2500 0.4450 0.9400 0.5678 0.6476 
#>    l-L    s-L 
#> 0.5798 0.6570
  • Null Hypothesis is true
x = table(c(0:20, rbinom(1000, 20, 0.55)))-1 
# p is not 0.5, but data is still from a binomial distribution with n=20
gof_test(x, vals, pnull, rnull, phat=phat,
         B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W Wassp1   NS-B   NS-A     BJ    l-P    s-P 
#> 0.4950 0.4000 0.3700 0.3500 0.3500 0.3800 0.1450 0.3550 0.7950 0.3460 0.2615 
#>    l-L    s-L 
#> 0.3230 0.2624
  • Null Hypothesis is false
x = table(c(rep(0:20, 5), rbinom(1000-21*5, 20, 0.53))) 
# data has to many small and large values to be from a binomial
gof_test(x, vals, pnull, rnull, phat=phat,
         B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W Wassp1   NS-B   NS-A     BJ    l-P    s-P 
#>      0      0      0      0      0      0      0      0      0      0      0 
#>    l-L    s-L 
#>      0      0

The arguments are the same as for the simple hypothesis case, except that the user has to supply a routine phat to estimate the parameters, and the functions pnull and rnull now have one argument, namely the vector with parameter estimates.

The estimation of the parameter(s) in the case of the chi square tests is done either by using the function phat or via the minimum chi square method. The routine uses a general function minimizer. If there are values of the parameter that are not possible this can lead to warnings. It is best to put a check into the pnull function to avoid this issue. As an example the function pnull above checks that the success probability p is in the interval \((0,1)\).

Histogram Data

A variant of discrete data sometimes encountered is data given in the form of a histogram, that is as a set of bins and their counts. The main distinction is that discrete data has specific values, for example the non-negative integers for a Poisson distribution, whereas histogram data has ranges of numbers, the bins. It turns out that, though, that the only method that requires actual values is Wassp1, and for that method one can use the midpoint of the intervals.

As an example consider the following case: we have histogram data and we want to test whether it comes from an exponential rate 1 distribution, truncated to the interval 0-2:

rnull = function() {
  y = rexp(2500, 1) # Exp(1) data
  y = y[y<2][1:1500] # 1500 events on 0-2
  bins = 0:40/20 # binning
  hist(y, bins, plot=FALSE)$counts # find bin counts
}
x = rnull()
bins = 0:40/20
vals = (bins[-1]+bins[-21])/2 #use bin midpoints as values
pnull = function() {
   bins = 1:40/20
   pexp(bins, 1)/pexp(2, 1)
}
  
gof_test(x, vals, pnull, rnull)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W Wassp1   NS-B   NS-A     BJ    l-P    s-P 
#> 0.2364 0.3330 0.2702 0.2868 0.4412 0.2246 0.2436 0.0014 0.2262 0.0766 0.0353 
#>    l-L    s-L 
#> 0.0750 0.0436

Continuous Data

Simple Hypothesis

pnull = function(x) pnorm(x)
rnull = function()  rnorm(1000)
TSextra = list(qnull=function(x) qnorm(x)) #optional quantile function used by chi square tests and Wassp1 test.
  • Null Hypothesis is true
x = rnorm(1000)
#Basic Tests
gof_test(x, NA, pnull, rnull, B=Btest, TSextra=TSextra)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W     ZA     ZK     ZC Wassp1 ES-l-P ES-s-P 
#> 0.9600 0.7600 0.9250 0.8700 0.6800 0.4950 0.7350 0.5050 0.9200 0.1206 0.9298 
#> EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L 
#> 0.4256 0.6931 0.1082 0.9254 0.4847 0.7010
#Adjusted p value
gof_test_adjusted_pvalue(x, NA, pnull, rnull,
            B=c(Btest,500), TSextra=TSextra,
            maxProcessor = 1)
#> p values of individual tests:
#> KS :  0.945
#> K :  0.705
#> AD :  0.905
#> CvM :  0.865
#> W :  0.68
#> ZA :  0.39
#> ZK :  0.695
#> ZC :  0.41
#> Wassp1 :  0.88
#> ES-l-P :  0.1206
#> ES-s-P :  0.9298
#> EP-l-P :  0.4256
#> EP-s-P :  0.6931
#> ES-l-L :  0.1082
#> ES-s-L :  0.9254
#> EP-l-L :  0.4847
#> EP-s-L :  0.701
#> adjusted p value of combined tests: 0.52
  • Null Hypothesis is false
x = rnorm(1000, 0.5) 
gof_test(x, NA, pnull, rnull, B=Btest,
         TSextra=TSextra)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W     ZA     ZK     ZC Wassp1 ES-l-P ES-s-P 
#>      0      0      0      0      0      0      0      0      0      0      0 
#> EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L 
#>      0      0      0      0      0      0

Composite Hypothesis - One Parameter

pnull = function(x, p=0) pnorm(x, p)
TSextra = list(qnull = function(x, p=0) qnorm(x, p))
rnull = function(p)  rnorm(1000, p)
phat = function(x) mean(x)
  • Null Hypothesis is true
x = rnorm(1000) 
gof_test(x, NA, pnull, rnull, phat=phat,
         TSextra=TSextra, B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W     ZA     ZK     ZC Wassp1 ES-l-P ES-s-P 
#> 0.7550 0.6650 0.6350 0.6350 0.6050 0.7500 0.5200 0.8700 0.6400 0.3633 0.2151 
#> EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L 
#> 0.8812 0.8874 0.3320 0.2680 0.8795 0.8897
  • Null Hypothesis is true
x = rnorm(1000, 0.5) 
gof_test(x, NA, pnull, rnull, phat=phat,
         TSextra=TSextra)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W     ZA     ZK     ZC Wassp1 ES-l-P ES-s-P 
#> 0.2858 0.2930 0.2876 0.2800 0.2892 0.7516 0.4462 0.6824 0.2442 0.4387 0.4176 
#> EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L 
#> 0.1561 0.7744 0.2160 0.4322 0.1116 0.7751
  • Null Hypothesis is false
x = rnorm(1000, 0.5, 2) 
gof_test(x, NA, pnull, rnull, phat=phat,
         TSextra=TSextra, B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W     ZA     ZK     ZC Wassp1 ES-l-P ES-s-P 
#>      0      0      0      0      0      0      0      0      0      0      0 
#> EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L 
#>      0      0      0      0      0      0

The arguments of gof_test are the same as in the discrete case, except that vals=NA. The functions pnull and rnull are functions of one variable in the case of a simple hypothesis and of two variables in the case of parameeter estimation.

Composite Hypothesis - Multiple Parameters

pnull = function(x, p=c(0, 1)) pnorm(x, p[1], ifelse(p[2]>0, p[2], 0.001))
TSextra = list(qnull = function(x, p=c(0, 1)) qnorm(x, p[1], ifelse(p[2]>0, p[2], 0.001)))
rnull = function(p=c(0, 1))  rnorm(1000, p[1], ifelse(p[2]>0, p[2], 0.001))
phat = function(x) c(mean(x), sd(x))
  • Null Hypothesis is true
x = rnorm(1000) 
gof_test(x, NA, pnull, rnull, phat=phat,
         TSextra=TSextra, B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W     ZA     ZK     ZC Wassp1 ES-l-P ES-s-P 
#> 0.5350 0.3100 0.2900 0.3000 0.2700 0.7900 0.7800 0.8900 0.2900 0.4463 0.2066 
#> EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L 
#> 0.6077 0.3573 0.4828 0.2013 0.5757 0.3655
  • Null Hypothesis is true
x = rnorm(1000, 0.5) 
gof_test(x, NA, pnull, rnull, phat=phat,
         TSextra=TSextra, B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W     ZA     ZK     ZC Wassp1 ES-l-P ES-s-P 
#> 0.8150 0.8450 0.5900 0.6100 0.6200 0.7250 0.6350 0.8050 0.5400 0.3993 0.4363 
#> EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L 
#> 0.7008 0.7411 0.3719 0.3859 0.6677 0.7311
  • Null Hypothesis is true
x = rnorm(1000, 0.5, 2) 
gof_test(x, NA, pnull, rnull, phat=phat,
         TSextra=TSextra, B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W     ZA     ZK     ZC Wassp1 ES-l-P ES-s-P 
#> 0.6200 0.6750 0.8550 0.8100 0.7900 0.8100 0.8450 0.7100 0.8600 0.6993 0.6028 
#> EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L 
#> 0.5430 0.9580 0.6256 0.5512 0.4961 0.9580
  • Null Hypothesis is false
x = rt(1000, 2) 
gof_test(x, NA, pnull, rnull, phat=phat,
         TSextra=TSextra, B=Btest)$p.value
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#>     KS      K     AD    CvM      W     ZA     ZK     ZC Wassp1 ES-l-P ES-s-P 
#>      0      0      0      0      0      0      0      0      0      0      0 
#> EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L 
#>      0      0      0      0      0      0

Power Estimation

For estimating the power of the various tests one also has to provide the routine ralt, which generates data under the alternative hypothesis:

Discrete Data/Model

Simple Null Hypothesis

vals = 0:10
pnull = function() pbinom(0:10, 10, 0.5)
rnull =function () table(c(0:10, rbinom(100, 10, 0.5)))-1
ralt =function (p=0.5) table(c(0:10, rbinom(100, 10, p)))-1
P=gof_power(pnull, vals, rnull, ralt, 
  param_alt=seq(0.5, 0.6, 0.02), B=Bpower, 
  nbins=c(11, 5), maxProcessor = 1)
plot_power(P, "p", Smooth=FALSE)

In all cases the arguments are the same as for gof_test. In addition we now have

  • ralt: a routine with one parameter that generates data under some alternative hypothesis.

  • param_alt: values to be passed to ralt. This allows the calculation of the power for many different values.

  • alpha=0.05: type I error probability for tests.

  • CI=FALSE: if TRUE confidence intervals based on the number of MC simulation runs are found.

  • list.with.everything: this can be a list that has all the functions like pnull, rnull, etc. Usually this was generated by a call to Rgof::case_studies.

  • B=1000 the number of simulation runs.

It is also possible to pre-define the desired confidence level and run the power routine until this level is achieved, using the routine gof_power_adaptive:

gof_power_adaptive(pnull, vals, rnull, ralt, 
  param_alt=0.5, nbins=c(11, 5), 
  conf.level=0.9, maxProcessor = 1)
#> Error in `gof_power_adaptive()`:
#> ! could not find function "gof_power_adaptive"

Composite Null Hypothesis

vals = 0:10
pnull = function(p=0.5) pbinom(0:10, 10, ifelse(0<p&p<1,p,0.001))
rnull = function (p=0.5) table(c(0:10, rbinom(100, 10, ifelse(0<p&p<1,p,0.001))))-1
phat = function(x) sum(0:10*x)/sum(x)/10
  • Null Hypothesis is true
ralt =function (p=0.5) table(c(0:10, rbinom(100, 10, p)))-1
gof_power(pnull, vals, rnull, ralt, c(0.5, 0.6), phat=phat,
        B=Bpower, nbins=c(11, 5), maxProcessor = 1)
#>       KS    K   AD  CvM    W Wassp1 NS-B NS-A   BJ  l-P  s-P
#> 0.5 0.07 0.04 0.02 0.06 0.06   0.03 0.02 0.04 0.02 0.02 0.02
#> 0.6 0.08 0.03 0.03 0.05 0.05   0.00 0.01 0.01 0.06 0.03 0.03

Note that power estimation in the case of a composite hypothesis (aka with parameters estimated) is much slower than the simple hypothesis case.

  • Null Hypothesis is false
ralt =function (p=0.5) table(c(0:10, rep(0:10, 2), rbinom(78, 10, p)))-1
gof_power(pnull, vals, rnull, ralt, 0.5, phat=phat,
        B=Bpower, nbins=c(11, 5), maxProcessor = 1)
#>     KS      K     AD    CvM      W Wassp1   NS-B   NS-A     BJ    l-P    s-P 
#>   0.48   0.64   0.99   0.49   0.47   0.97   1.00   1.00   1.00   0.64   0.48

Continuous Data/Model

Simple Null Hypothesis

pnull = function(x) pnorm(x)
TSextra = list(qnull = function(x) qnorm(x))
rnull = function() rnorm(100)
ralt = function(mu=0) rnorm(100, mu)
gof_power(pnull, NA, rnull, ralt, c(0, 1), 
          TSextra=TSextra, B=Bpower, maxProcessor = 1)
#>     KS   K   AD CvM    W   ZA   ZK   ZC Wassp1 ES-l-P ES-s-P EP-l-P EP-s-P
#> 0 0.05 0.1 0.09 0.1 0.08 0.08 0.08 0.11   0.12   0.04   0.04   0.03   0.04
#> 1 1.00 1.0 1.00 1.0 1.00 1.00 1.00 1.00   1.00   1.00   1.00   1.00   1.00
#>   ES-l-L ES-s-L EP-l-L EP-s-L
#> 0   0.04   0.05   0.06   0.04
#> 1   1.00   1.00   1.00   1.00

Composite Null Hypothesis

pnull = function(x, p=c(0,1)) pnorm(x, p[1], ifelse(p[2]>0, p[2], 0.01))
TSextra = list(qnull = function(x, p=c(0,1)) qnorm(x, p[1], ifelse(p[2]>0, p[2], 0.01)))
rnull = function(p=c(0,1)) rnorm(500, p[1], p[2])
ralt = function(mu=0) rnorm(100, mu)
phat = function(x) c(mean(x), sd(x))
gof_power(pnull, NA, rnull, ralt, c(0, 1), phat= phat, 
          TSextra=TSextra, B=Bpower, maxProcessor=1)
#>     KS    K   AD  CvM    W   ZA   ZK   ZC Wassp1 ES-l-P ES-s-P EP-l-P EP-s-P
#> 0 0.97 0.99 0.02 0.01 0.03 0.56 0.01 0.00   1.00   0.08   0.08   0.05   0.07
#> 1 0.97 0.99 0.06 0.06 0.08 0.59 0.00 0.03   0.99   0.05   0.03   0.08   0.06
#>   ES-l-L ES-s-L EP-l-L EP-s-L
#> 0   0.07   0.08   0.06   0.10
#> 1   0.07   0.06   0.08   0.08
ralt = function(df=1) {
# t distribution truncated at +- 5  
  x=rt(1000, df)
  x=x[abs(x)<5]
  x[1:100]
}  
gof_power(pnull, NA, rnull, ralt, c(2, 50), phat=phat, 
          Range=c(-5,5), TSextra=TSextra, B=Bpower, maxProcessor=1)
#>      KS K   AD  CvM    W   ZA   ZK   ZC Wassp1 ES-l-P ES-s-P EP-l-P EP-s-P
#> 2  1.00 1 0.53 0.54 0.60 0.90 0.19 0.11   0.99   0.19   0.18   0.13   0.18
#> 50 0.95 1 0.02 0.06 0.07 0.51 0.01 0.01   0.55   0.05   0.04   0.04   0.05
#>    ES-l-L ES-s-L EP-l-L EP-s-L
#> 2    0.20   0.20   0.13   0.20
#> 50   0.05   0.04   0.03   0.07

Power with

Running other tests

It is very easy for a user to add other goodness-of-fit tests to the package.

Example

Say we wish to use tests that are variants of the Cramer-vonMises test, using the integrated absolute difference of the empirical and the theoretical distribution function:

\[\int_{-\infty}^{\infty} \vert F(x) - \hat{F}(x) \vert^p dF(x)\] For continuous data we have the routine

newTScont = function(x, pnull, param) {
   Fx=sort(pnull(x))
   n=length(x)
   out = c(sum(abs( (2*1:n-1)/2/n-Fx )),sum(sqrt(abs( (2*1:n-1)/2/n-Fx ))))
   names(out) = c("CvM alt 1", "CvM alt 2")
   out
}

This routine has to have three or four arguments x, pnull, param and (optionally) TSextra. x is the data and pnull a function that finds the cdf at x. param has to be the estimated parameters in the case of a composite null hypothesis, and is ignored in the case of a simple null hypothesis. Tsextra has to be a list of additional items needed for the calculation of the test statistic, if any.

Note that the return object has to be a named vector.

Then we can run this test with

pnull = function(x) punif(x)
rnull = function() runif(500)
x = rnull()
Rgof::gof_test(x, NA, pnull, rnull, TS=newTScont)
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#> 
#> Rgof goodness-of-fit tests
#> Data: continuous  | n = 500  | B = 5000 
#> 
#>     method statistic p.value
#>  CvM alt 1    7.3942  0.3510
#>  CvM alt 2   57.3140  0.3262

Say we want to find the power of this test when the true distribution is a linear:

ralt = function(slope=0) {
  if(slope==0) y=runif(500)
    else y=(slope-1+sqrt((1-slope)^2+4*slope* runif(500)))/2/slope
}
gof_power(pnull, NA, rnull, ralt, TS=newTScont, param_alt=round(seq(0, 0.5, length=3), 3), 
          Range=c(0,1), B=Bpower, maxProcessor = 1)
#>      CvM alt 1 CvM alt 2
#> 0         0.11      0.10
#> 0.25      0.91      0.91
#> 0.5       1.00      1.00

for discrete data we will write the routine using Rcpp:

(For reasons to avoid issues with CRAN submission this routine is already part of Rgof)

#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector newTSdisc(IntegerVector x, 
                      Function pnull,  
                      NumericVector param,
                      NumericVector vals) {
    
  Rcpp::CharacterVector methods=CharacterVector::create("CvM alt");    
  int const nummethods=methods.size();
  int k=x.size(), n, i;
  NumericVector TS(nummethods), ecdf(k), Fx(k);
  double tmp;
  TS.names() =  methods;
  Fx=pnull(param);
  n=0;
  for(i=0;i<k;++i) n = n + x[i];
  ecdf(0) = double(x(0))/double(n);  
  for(i=1;i<k;++i) {
    ecdf(i) = ecdf(i-1) + x(i)/double(n);
  }

  tmp = std::abs(ecdf[0]-Fx(0))*Fx(0);
  for(i=1;i<k;++i) 
     tmp = tmp + std::abs(ecdf(i)-Fx(i))*(Fx(i)-Fx(i-1));
  TS(0) = tmp;
 
  return TS;
}

The routine has to have four or five arguments x, pnull, param, vals and (optionally) TSextra. The output vector has to have names.

Note that one drawback of writing the routine in Rcpp is that it is then not possible to use multiple processors.

As an example we will test whether some data comes from a Binomial distribution with n=10 trials. The success parameter p will be estimated from the data:

vals=0:10
pnull = function(p) pbinom(0:10, 10, p) 
rnull = function(p) table(c(0:10,rbinom(10000, 10, p)))-1
phat=function(x) sum(0:10*x)/100000
x = rnull(0.5)
gof_test(x, vals, pnull, rnull, phat=phat, TS=Rgof::newTSdisc)
#> maxProcessor set to 1 because parallel overhead would dominate this short computation
#> 
#> Rgof goodness-of-fit tests
#> Data: discrete  | n = 10000  | B = 5000 
#> 
#>   method statistic p.value
#>  CvM alt  0.001353  0.8000
#>      l-P  6.947000  0.6426
#>      s-P  6.947000  0.6426
#>      l-L  6.938600  0.6435
#>      s-L  6.938600  0.6435
#> 
#> Estimated parameters:
#> [1] 0.50249

For the power calculations we will consider data that is actually a mixture of two Binomials:

ralt = function(tau=0) {
   x=rbinom(5000, 10, 0.5-tau)
   y=rbinom(5000, 10, 0.5+tau) 
   table(c(0:10,x,y))-1
}
gof_power(pnull, vals, rnull, ralt,
    TS=Rgof::newTSdisc, phat=phat, 
    param_alt=round(seq(0, 0.05, length=3), 3),
    B=Bpower, maxProcessor = 1)
#>       CvM alt
#> 0        0.05
#> 0.025    0.23
#> 0.05     1.00

If the new routine can also calculate p values use the argument With.p.value=TRUE to indicate that. In that case the return object should be a (vector of) p values.

Adjusted p values for Several Tests

As no single test can be relied upon to consistently have good power, it is reasonable to employ several of them. We could then reject the null hypothesis if any of the tests does so, that is, if the smallest p-value is less than the desired type I error probability \(\alpha\).

This procedure clearly suffers from the problem of simultaneous inference, and the true type I error probability will be much larger than \(\alpha\). It is however possible to adjust the p value so it does achieve the desired \(\alpha\). This can be done as follows:

We generate a number of data sets under the null hypothesis. Generally about 1000 will be sufficient. Then for each simulated data set we apply the tests we wish to include, and record the smallest p value. Here is an example. Say the null hypothesis specifies a uniform \([0.1]\) and a sample size of 250.

pnull=function(x) punif(x)
rnull=function() runif(250)
pvals=matrix(0,1000,16)
for(i in 1:1000) 
  pvals[i, ]=Rgof::gof_test(rnull(), NA, pnull,
                            rnull,B=Btest)$p.values

Note this is not run because of CRAN time constraints. The resulting matrix is in Rgof::pvaluecdf.

Next we find the smallest p value in each run for two selections of four methods. One is the selection found to be best above, namely the methods by Wilson, Anderson-Darling, Zhang’s ZC and a chi square test with a small number of bins and using Pearson’s formula. As a second selection we use the methods by Kolmogorov-Smirnov, Kuiper, Anderson-Darling and Cramer-vonMises. It can be checked that for this null hypothesis these methods are highly correlated.

colnames(pvals)=names(Rgof::gof_test(rnull(), NA, pnull, rnull,B=10)$p.values)
p1=apply(pvals[, c("W", "ZC", "AD", "ES-s-P" )], 1, min)
p2=apply(pvals[, c("KS", "K", "AD", "CvM")], 1, min)

Next we find the empirical distribution function for the two sets of p values and draw their graphs. We also add the curve for the cases of four identical tests and the case of four independent tests, which of course is the Bonferroni correction. The data for the cdf is in the inst/extdata directory of the package

tmp=Rgof::pvaluecdf
Tests=factor(c(rep("Identical Tests", nrow(tmp)),
        rep("Correlated Selection", nrow(tmp)),
        rep("Best Selection", nrow(tmp)),
        rep("Independent Tests", nrow(tmp))),
        levels=c("Identical Tests",  "Correlated Selection", 
                 "Best Selection", "Independent Tests"),
        ordered = TRUE)
dta=data.frame(x=c(tmp[,1],tmp[,1],tmp[,1],tmp[,1]),
          y=c(tmp[,1],tmp[,3],tmp[,2],1-(1-tmp[,1])^4),
          Tests=Tests)
ggplot2::ggplot(data=dta, ggplot2::aes(x=x,y=y,col=Tests))+
  ggplot2::geom_line(linewidth=1.2)+
  ggplot2::labs(x="p value", y="CDF")+
  ggplot2::scale_color_manual(values=c("blue","red", "Orange", "green"))

Here is how to find these adjusted p values with Rgof:

x=rnull()
Rgof::gof_test_adjusted_pvalue(x, NA, pnull, rnull, 
              B=c(1000,500), maxProcessor = 1)
#> p values of individual tests:
#> KS :  0.444
#> K :  0.14
#> AD :  0.547
#> CvM :  0.59
#> W :  0.25
#> ZA :  0.707
#> ZK :  0.402
#> ZC :  0.622
#> ES-l-P :  0.1164
#> ES-s-P :  0.1274
#> EP-l-P :  0.1994
#> EP-s-P :  0.0048
#> ES-l-L :  0.1001
#> ES-s-L :  0.1351
#> EP-l-L :  0.2174
#> EP-s-L :  0.0067
#> adjusted p value of combined tests: 0.054

Weighted Data

Sometimes the data/model uses importance sampling weights. This can be done as follows. Say we want to test whether the data comes from a standard normal distribution, truncated to [-3,3] and with weights from a t distribution with 3 degrees of freedom:

\(H_0: F=N(0,1)\), \(X\sim t(3)\)

df=3
pnull=function(x) (pnorm(x)-pnorm(-3))/(2*pnorm(3)-1)
rnull=function() {x=rt(2000, df);x=x[abs(x)<3];sort(x[1:1000])}
w=function(x) (dnorm(x)/(2*pnorm(3)-1))/(dt(x,df)/(2*pt(3,df)-1))
x=sort(rnull())
plot(x, w(x), type="l", ylim=c(0, 2*max(w(x))))

ralt=function(m=0) {x=rt(2000,df)+m;x=x[abs(x)<3];sort(x[1:1000])}
set.seed(111)
Rgof::gof_power(pnull, NA, rnull, ralt, w=w, param_alt = c(0,0.2), Range=c(-3,3),B=Bpower, maxProcessor = 1)
#>       KS    K  CvM   AD
#> 0   0.06 0.07 0.04 0.03
#> 0.2 1.00 0.98 1.00 1.00

It should be noted that these tests are quite sensitive to the size of the weights and to the sample size, so one should always do a simulation study to verify that they work in the case under consideration.

Hybrid Tests: Null Distribution Available Only via Simulation

Sometimes it is possible to generate data from the distribution under the null hypothesis, but its cdf can not be calculated. In this case the routines hybrid_test and hybrid_power generate a (usually large) Monte Carlo data set under the null hypothesis and run the two-sample tests of the package R2sample on the data and the Monte Carlo data set. The p values are found with the parametric bootstrap. If parameters are estimated, the Monte Carlo data set is generated with the parameters estimated from the data, and in each bootstrap run the parameters are estimated again from the bootstrap data set, so the dependence between the data and the Monte Carlo data is reproduced. These routines require the package R2sample. If the cdf can be calculated, gof_test should be used, as it generally has higher power. The chi-square tests use the chi-square approximation and treat the Monte Carlo data as an independent sample, so their p values are only approximate when parameters are estimated.

Say we wish to test whether data comes from a normal distribution with mean and standard deviation estimated, pretending that we can not evaluate the normal cdf:

rnull=function(p) rnorm(200, p[1], p[2])
phat=function(x) c(mean(x), sd(x))
x=rt(200, 4)
Rgof::hybrid_test(x, rnull=rnull, phat=phat, nMC=5, B=Bpower, maxProcessor=1)
#> 
#> Rgof hybrid goodness-of-fit tests
#> Data: continuous  | n = 200  | nMC = 1000  | B = 100 
#> 
#>    method statistic p.value
#>        KS    0.0920  0.0000
#>    Kuiper    0.1720  0.0000
#>       CvM    0.3616  0.0000
#>        AD    2.2415  0.0000
#>        ZA   -3.2780  0.0000
#>        ZK    4.6310  0.0000
#>        ZC   -3.2650  0.0000
#>    Wassp1    0.2753  0.0000
#>     EppsS   18.8390  0.0000
#>       HHG    4.7110  0.0000
#>  ES large   31.0800  0.0195
#>  ES small   12.6600  0.0130
#>  EP large   33.0000  0.1041
#>  EP small   21.8400  0.0094
#> 
#> Estimated parameters:
#> [1] -0.07757627  1.62349243

The argument nMC is the size of the Monte Carlo data set, or, if it is at most 10, its size as a multiple of the sample size.

Power Graphs

It is easy to generate power graphs with the routine plot_power. Say we wish to generate a power graph for the case of a uniform distribution if the data actually comes from a linear one:

rnull=function() runif(n)
pnull=function(x) punif(x)
TSextra(qnull=function(x) qunif(x))
ralt=function(a=0.3) {
    if(a==0) return(runif(n))
    (-(1-a)+sqrt((1-a)^2+4*a*runif(n)))/2/a
}
pwr=Rgof::gof_power(pnull, NA, rnull, ralt,
        param_alt =seq(0.01, 0.5, length=21),
        Range=c(0,1))
Rgof::plot_power(pwr, "Uniform vs Linear")

Case Studies

The package includes the routine run.studies, which provides 110 case studies each for the continuous and the discrete case. This allows the user to easily compare the power of the methods included in the package to a different one of their choice.

The 120 studies fall into 5 types. In the first four, with 20 cases each, we have data sets that differ in exactly one population parameter: either mean, variance, skewness or kurtosis. In type 5 (=“mixed”) any of the four parameters can be different. The first 20 of these have fixed parameters and the last 20 have parameters estimated from the data.

As an example consider a type 1 (=“mean”) study. Study #1 has one data set from a uniform distribution on \([0,1]\). Therefore we have mean=0.5, variance=1/12, skewness=0 and kurtosis=1.8. Next we find a distribution with the same variance, skewness and kurtosis, but with a mean of 0.53. Their densities look as follows:

f=Rgof::case_studies("uniform", "mean", n=1e4)
#> Error:
#> ! 'case_studies' is not an exported object from 'namespace:Rgof'
x=0:100/100
dta=data.frame(x=c(x,x), 
               y=c(f$dnull(x), Rgof::funs_list[["cont"]][["uniform"]][["mean"]]$density(x)),
          Distribution=rep(c("Uniform", 
                           "Alternative"), each=101))
#> Error:
#> ! object 'f' not found
ggplot(dta, aes(x, y, col=Distribution)) +
  geom_line() +
  scale_y_continuous(limits = c(0, 2)) +
  labs(y="Density")
#> Error in `ggplot()`:
#> ! could not find function "ggplot"

These alternative distributions are designed so that for a true type I error of \(\alpha=0.05\) the best method as a power of between \(70\%\) and \(90\%\).

The package includes two example “new” tests, both simple chi-square tests, for either continuous (myTS_cont) or discrete data (myTS_disc). Either can return the value of the test statistic, or a p value, depending on what is specified in TSextra.

These cases can be run easily with the routine run.studies:

TSextra=list(nbins=5, statistic=FALSE)
Rgof::run.studies(1:2, 1:2,  
        TS=Rgof::myTS_cont, TSextra=TSextra, 
        With.p.value = TRUE)
#> Average rank of a method:
#>     ZC     ZA     ZK     AD EP-l-P ES-l-P EP-l-L EP-s-P ES-l-L ES-s-P EP-s-L 
#>  100.0   94.4   88.9   79.2   61.8   61.1   56.2   55.6   54.9   47.9   46.5 
#> ES-s-L Chi_C5 Wassp1      K    CvM      W     KS 
#>   41.7   34.7   33.3   30.6   22.9   22.9   17.4
#>              Chi_C5    KS     K    AD   CvM     W    ZA    ZK    ZC Wassp1
#> uniform/mean  0.614 0.448 0.203 0.739 0.529 0.118 0.825 0.813 0.840  0.560
#> linear/mean   0.298 0.182 0.096 0.508 0.253 0.091 0.842 0.788 0.885  0.249
#> uniform/mean  0.109 0.082 0.148 0.310 0.090 0.130 0.802 0.757 0.873  0.122
#> linear/mean   0.099 0.047 0.104 0.167 0.047 0.100 0.699 0.641 0.793  0.065
#>              ES-l-P ES-s-P EP-l-P EP-s-P ES-l-L ES-s-L EP-l-L EP-s-L
#> uniform/mean  0.431  0.684  0.431  0.684  0.426  0.682  0.426  0.682
#> linear/mean   0.470  0.287  0.423  0.334  0.368  0.288  0.382  0.319
#> uniform/mean  0.130  0.120  0.165  0.120  0.138  0.114  0.169  0.114
#> linear/mean   0.239  0.113  0.178  0.117  0.197  0.110  0.154  0.113

Arguments of run.studies:

Arguments of routine to calculate new test:

Continuous data
- x: the data set - pnull: routine to calculate the cdf
- p: vector with parameter estimates, for composite hypotheses.
- TSextra: (optional): a list passed to the routine with any object needed to do the calculation.

Discrete data Same as for continuous data plus vals, a vector of the values of the discrete random variable.

The output of the routine has to be a named vector with either the test statistic(s) or the p value(s).

The case studies are as follows. As discussed above, there are 20 studies with one distribution chosen from the usual list, and the second so it matches the three of the four parameters mean, variance, skewness and kurtosis but differs in the fourth. The distributions are:

  1. uniform
  2. linear
  3. quadratic
  4. uniform-betabump
  5. sine
  6. betaaa
  7. beta2a
  8. triangular
  9. uniformmixture
  10. betamixture
  11. normal-pure
  12. normal-mix1
  13. normal-mix2
  14. normal-mix3
  15. normal-mix4
  16. gamma1
  17. gamma2
  18. gammamixture
  19. exponential-mixture
  20. noncentral

For the exact definitions run case.studies:

Rgof::case_studies("noncentral")[2:4]
#> Error:
#> ! 'case_studies' is not an exported object from 'namespace:Rgof'

In addition there are another 30 case studies where most of the parameters are different:

  1. uniform.linear\(\hspace{3cm}\) U[0,1] vs a linear model on [0,1] with slope s.

  2. uniform.quadratic\(\hspace{2.5cm}\) U[0,1] vs a quadratic model with vertex at 0.5 and some curvature a.

  3. uniform.bump\(\hspace{3.1cm}\) U[0,1] vs U[0,1]+N(0.5,0.05).

  4. uniform.sine\(\hspace{3.3cm}\) U[0,1] vs U[0,1]+Sine wave

  5. beta22.betaaa\(\hspace{3cm}\) Beta(2,2) vs Beta(a,a)

  6. beta22.beta2a\(\hspace{3cm}\) Beta(2,2) vs Beta(2,a)

  7. uniform.uniformmixture\(\hspace{1.9cm}\) U[0,1] vs. \(\alpha\)U[0,1/2]+(1-\(\alpha\))U[1/2,1]

  8. uniform.betamixture\(\hspace{2.5cm}\) U[0,1] vs. \(\alpha\)U[0,1/2]+(1-\(\alpha\))Beta(2,2)

  9. uniform.triangular\(\hspace{2.9cm}\) U[0,1] vs. triangular

  10. double.exponential\(\hspace{3.5cm}\) with different rates.

  11. normal.onestretch\(\hspace{3.1cm}\) N(0,1) vs 1/2N(0,1)+1/2N(0, \(\sigma\))

  12. normal.t\(\hspace{4.2cm}\) N(0,1) vs t(df)

  13. normal.outlier1\(\hspace{3.1cm}\) N(0,1) vs N(0,1)+N(5, 1)

  14. normal.outlier2\(\hspace{3.1cm}\) N(0,1) vs N(0,1)+U[-5,-3]+U[3,5]

  15. normal.normalmixture\(\hspace{3.1cm}\) N(0,1) vs N(-a,1)+N(a,1)

  16. exponential.gamma\(\hspace{2.3cm}\) Exp(1) vs Gamma(1,b)

  17. exponential.weibull\(\hspace{2.5cm}\) Exp(1) vs Weibull(1,b)

  18. exponential.bump\(\hspace{2.7cm}\) Exp(1) vs Exp(1)+N(0.5,0.05)

  19. chisquare.noncentral\(\hspace{2.3cm}\) \(\chi^2(5)\) vs. \(\chi^2(5, \tau)\)

  20. gamma.gammamixture\(\hspace{2.3cm}\) \(\Gamma(2, 3)\) vs \((1-\alpha)\Gamma(2, 3)+ \alpha\Gamma(3,3)\)

The last 10 case studies include parameter estimation:

  1. normal.t.est\(\hspace{3.1cm}\) \(N(\mu, \sigma)\) vs \(t(5)\), with mean and standard deviation estimated.

  2. exponential.weibull.est\(\hspace{3.1cm}\) \(Exp(\lambda)\) vs Weibull(1.2, 1), rate estimated

  3. trunc.exponential.linear.est\(\hspace{3.1cm}\) 0-1 truncate exponential with rate \(\lambda\) vs linear, rate estimated

  4. exponential.gamma.est\(\hspace{3.1cm}\) \(Exp(\lambda)\) vs \(\Gamma(1.2, 1)\), rate estimated

  5. normal.cauchy.est\(\hspace{3.1cm}\) \(N(0,\sigma)\) vs Cauchy, both truncated to the interval \([-3.5, 3.5\), variance estimated

  6. betaa1.betaab.est\(\hspace{3.1cm}\) Beta(a, 1) vs Beta(1, 1.2), shape1 estimated

  7. betaa1.betaaa.est\(\hspace{3.1cm}\) Beta(a, 1) vs Beta(1.2, 1.2), shape1 estimated

  8. trans-beta.est\(\hspace{3.1cm}\) \(g(x)=(\exp(x)-1)/(e-1);g(X)~Beta(a,1)\) vs. \(h(x)=(\exp(hx)-1)/(\exp(a)-1);h(X)~Beta(1,1)\), a estimated

  9. double.exponential.est\(\hspace{3.1cm}\) double exponential rate \(\lambda\) vs. double gamma(1.6, 1), rate estimated

  10. pareto.est\(\hspace{3.1cm}\) \(f(x)=\alpha/(x+1)^{\alpha + 1}\) vs Gamma(x, 1.07, 8), \(\alpha\) estimated.

  11. betamixture1.est\(\hspace{3.1cm}\) \(f(x)=a*dbeta(x, 1, 1)+(1-a)*dbeta(x, 2, 2)\), mixing ratio a estimated.

  12. “betamixture2.est\(\hspace{3.1cm}\) \(f(x)=a*dbeta(x, 3, 1)+(1-a)*dbeta(x, 1, 3)\), mixing ratio a estimated.

  13. betamixture3.est\(\hspace{3.1cm}\) \(f(x)=a*dbeta(x, 2, 2)+(1-a)*dbeta(x, 2, 5)\), mixing ratio a estimated.

  14. normalmixture.est\(\hspace{3.1cm}\) f(x)=a*pnorm(x)+(1-a)*pnorm(x, 2), mixing ratio a estimated.

  15. laplace1.est\(\hspace{3.1cm}\) f(x, p)=function(x, p=c(0, 1)) exp(-abs(x - p[1]) / p[2]) / (2 * p[2]), location and scale estimated. Alternative is a mixture of normals.

  16. laplace2.est\(\hspace{3.1cm}\) f(x, p)=exp(-abs(x - p[1]) / p[2]) / (2 * p[2]), alternative is a double gamma distribution.

  17. truncexp1.est\(\hspace{3.1cm}\) f(x,l,a)=dexp(x, l)/pexp(a, l), upper limit a and rate l estimated.

  18. truncexp2.est\(\hspace{3.1cm}\) f(x, l)=dexp(x, l)/(pexp(2, l)-pexp(1, l)), rate l estimated.

  19. gammamixture1.est\(\hspace{3.1cm}\) f(x, a)=a*dgamma(x, 1, 1)+(1-a)*dgamma(x, 3, 1), mixing ratio a estimated.

  20. gammamixture2.est\(\hspace{3.1cm}\) f(x, a)=a*dgamma(x, 3, 1)+(1-a)*dgamma(x, 10, 1), mixing ratio a estimated.

For the discrete versions of case studies 55-57 the parameters are estimated with the grouped-data maximum likelihood estimator, which maximizes \(\sum_j n_j\log\left(F(b_j)-F(b_{j-1})\right)\) over the bins \((b_{j-1},b_j]\) (for 57 the upper limit is the upper edge of the last nonempty bin). The continuous estimators applied to the bin midpoints (the median, the maximum) take only a few distinct values, and the parametric bootstrap then does not hold its level.

Generally a user will wish to apply their test to all the case studies. This can be done easily with:

Rgof::run.studies(TS=myTS_cont, TSextra=TSextra, With.p.value=TRUE)

run.studies can also be used to run the studies for the included methods but for different values of the sample size n and/or alpha. Note, however, that these studies are designed so that for the pre-chosen sample sizes and \(\alpha=0.05\) the power of the best method is generally larger than \(70\%\) and less than \(90\%\), so as to make comparisons meaningfull.

Rgof::run.studies(data_type="disc", alpha=0.1)

or a user can recreate the file Rgof::power_study:

Rgof::run.studies(data_type="disc", RerunIncludedCases = TRUE)

References

Anderson, T W. 1962. “On the Distribution of the Two-Sample Cramer-von Mises Criterion.” Annals of Mathematical Statistics 33 (3): 1148–59.
Anderson, T W, and D A Darling. 1952. “Asymptotic Theory of Certain Goodness-of-Fit Criteria Based on Stochastic Processes.” Annals of Mathematical Statistics 23: 193–212.
Anderson, T W, and D A Darling. 1954. “A Test of Goodness-of-Fit.” JASA 49: 765–69.
Berk, R H, and D H Jones. 1979. “Goodness-of-Fit Test Statistics That Dominate the Kolmogorov Statistics.” Zeitschrift für Wahrscheinlichkeitstheorie Und Verwandte Gebiete 47: 47–59.
Berkson, J. 1980. “Minimum Chi-Square, Not Maximum Likelihood.” Ann. Math. Stat 8 (3): 457–87.
Choulakian, V., R. A. Lockhart, and M. A. Stephens. 1994. “Cramer-von Mises Statistics for Discrete Distributions.” The Canadian Journal of Statistics 22 (1): 125–37.
E del Barrio, C Matran, J A Cuesta-Albertos. 1999. “Tests of Goodness of Fit Based on the L2-Wasserstein Distance.” Annals of Statistics 1230-1239: 27.
Kolmogorov, A. 1933. “Sulla Determinazione Empirica Di Una Legge Di Distribuzione.” G. Ist. Ital. Attuari. 4: 83–91.
Kuiper, N H. 1960. “Tests Concerning Random Points on a Circle.” Proceedings of the Koninklijke Nederlandse Akademie van Wetenschappen 63: 38–47.
Ledwina, T. 1994. “Data-Driven Version of Neyman’s Smooth Test of Fit.” JASA 89: 1000–1005.
Massey, F J. 1951. “The Kolmogorov-Smirnov Test for Goodness-of-Fit.” JASA 46: 68–78.
Rayner, J C W, and D J Best. 1989. Smooth Tests of Goodness of Fit. Oxford University Press.
Rolke, Wolfgang, and Cristian Gutierrez-Gongora. 2020. “A Chi-Square Goodness-of-Fit Test for Continuous Distributions Against a Known Alternative.” Computational Statistics, ahead of print. https://doi.org/10.1007/s00180-020-00997-x.
Smirnov, N. 1948. “Table for Estimating the Goodness of Fit of Empirical Distributions.” Annals of Mathematical Statistics 19: 279–81.
Zhang, J. 2002. “Powerful Goodness-of-Fit Tests Based on Likelihood Ratio.” Journal of the RSS (Series B) 64: 281–94.