Added exact binomial test implementation.
Contributed by Thorsten Schaefer JIRA: MATH-1034 git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1527777 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7cc91e9f22
commit
22cad3d1a9
|
@ -51,6 +51,9 @@ If the output is not quite correct, check for invisible trailing spaces!
|
||||||
</properties>
|
</properties>
|
||||||
<body>
|
<body>
|
||||||
<release version="x.y" date="TBD" description="TBD">
|
<release version="x.y" date="TBD" description="TBD">
|
||||||
|
<action dev="psteitz" type="add" issue="MATH-1034" due-to="Thorsten Schaefer">
|
||||||
|
Added exact binomial test implementation.
|
||||||
|
</action>
|
||||||
<action dev="tn" type="add" issue="MATH-1018" due-to="Ajo Fod">
|
<action dev="tn" type="add" issue="MATH-1018" due-to="Ajo Fod">
|
||||||
Added overloaded constructors for subclasses of "RealDistribution" implementations
|
Added overloaded constructors for subclasses of "RealDistribution" implementations
|
||||||
which do not require an explicit "inverseCumulativeAccuracy". The default accuracy will
|
which do not require an explicit "inverseCumulativeAccuracy". The default accuracy will
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.math3.stat.inference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an alternative hypothesis for a hypothesis test.
|
||||||
|
*
|
||||||
|
* @version $Id$
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public enum AlternativeHypothesis {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a two-sided test. H0: p=p0, H1: p ≠ p0
|
||||||
|
*/
|
||||||
|
TWO_SIDED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a right-sided test. H0: p ≤ p0, H1: p > p0.
|
||||||
|
*/
|
||||||
|
GREATER_THAN,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a left-sided test. H0: p ≥ p0, H1: p < p0.
|
||||||
|
*/
|
||||||
|
LESS_THAN
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.math3.stat.inference;
|
||||||
|
|
||||||
|
import org.apache.commons.math3.distribution.BinomialDistribution;
|
||||||
|
import org.apache.commons.math3.exception.MathIllegalArgumentException;
|
||||||
|
import org.apache.commons.math3.exception.MathInternalError;
|
||||||
|
import org.apache.commons.math3.exception.NotPositiveException;
|
||||||
|
import org.apache.commons.math3.exception.NullArgumentException;
|
||||||
|
import org.apache.commons.math3.exception.OutOfRangeException;
|
||||||
|
import org.apache.commons.math3.exception.util.LocalizedFormats;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements binomial test statistics.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Exact test for the statistical significance of deviations from a
|
||||||
|
* theoretically expected distribution of observations into two categories.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/Binomial_test">Binomial test (Wikipedia)</a>
|
||||||
|
* @version $Id$
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
public class BinomialTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the null hypothesis can be rejected with the given
|
||||||
|
* confidence level.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <strong>Preconditions</strong>:
|
||||||
|
* <ul>
|
||||||
|
* <li>Number of trials must be ≥ 0.</li>
|
||||||
|
* <li>Number of successes must be ≥ 0.</li>
|
||||||
|
* <li>Number of successes must be ≤ number of trials.</li>
|
||||||
|
* <li>Probability must be ≥ 0 and ≤ 1.
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param numberOfTrials number of trials performed
|
||||||
|
* @param numberOfSuccesses number of successes observed
|
||||||
|
* @param probability assumed probability of a single trial under the null hypothesis
|
||||||
|
* @param alternativeHypothesis type of hypothesis being evaluated (one- or two-sided)
|
||||||
|
* @param confidenceLevel confidence level of the test
|
||||||
|
* @return true if the null hypothesis can be rejected with confidence {@code confidenceLevel}
|
||||||
|
* @throws NotPositiveException if {@code numberOfTrials} or {@code numberOfSuccesses}
|
||||||
|
* is negative
|
||||||
|
* @throws OutOfRangeException if {@code probability} is not between 0 and 1
|
||||||
|
* @throws MathIllegalArgumentException if
|
||||||
|
* {@code numberOfTrials} < {@code numberOfSuccesses} or if {@code alternateHypothesis}
|
||||||
|
* is null.
|
||||||
|
* @see AlternativeHypothesis
|
||||||
|
*/
|
||||||
|
public boolean binomialTest(int numberOfTrials, int numberOfSuccesses, double probability,
|
||||||
|
AlternativeHypothesis alternativeHypothesis, double confidenceLevel) {
|
||||||
|
double pValue = binomialTest(numberOfTrials, numberOfSuccesses, probability, alternativeHypothesis);
|
||||||
|
return pValue < 1 - confidenceLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the <i>observed significance level</i>, or <a href=
|
||||||
|
* "http://www.cas.lancs.ac.uk/glossary_v1.1/hyptest.html#pvalue">
|
||||||
|
* p-value</a>, associated with a <a
|
||||||
|
* href="http://en.wikipedia.org/wiki/Binomial_test"> Binomial test</a>.
|
||||||
|
* <p>
|
||||||
|
* The number returned is the smallest significance level at which one can
|
||||||
|
* reject the null hypothesis. The form of the hypothesis depends on
|
||||||
|
* {@code alternativeHypothesis}.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* <strong>Preconditions</strong>:
|
||||||
|
* <ul>
|
||||||
|
* <li>Number of trials must be ≥ 0.</li>
|
||||||
|
* <li>Number of successes must be ≥ 0.</li>
|
||||||
|
* <li>Number of successes must be ≤ number of trials.</li>
|
||||||
|
* <li>Probability must be ≥ 0 and ≤ 1.
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param numberOfTrials number of trials performed
|
||||||
|
* @param numberOfSuccesses number of successes observed
|
||||||
|
* @param probability assumed probability of a single trial under the null hypothesis
|
||||||
|
* @param alternativeHypothesis type of hypothesis being evaluated (one- or two-sided)
|
||||||
|
* @return p-value
|
||||||
|
* @throws NotPositiveException if {@code numberOfTrials} or {@code numberOfSuccesses}
|
||||||
|
* is negative
|
||||||
|
* @throws OutOfRangeException if {@code probability} is not between 0 and 1
|
||||||
|
* @throws MathIllegalArgumentException if
|
||||||
|
* {@code numberOfTrials} < {@code numberOfSuccesses} or if {@code alternateHypothesis}
|
||||||
|
* is null.
|
||||||
|
* @see AlternativeHypothesis
|
||||||
|
*/
|
||||||
|
public double binomialTest(int numberOfTrials, int numberOfSuccesses, double probability,
|
||||||
|
AlternativeHypothesis alternativeHypothesis) {
|
||||||
|
if (numberOfTrials < 0) {
|
||||||
|
throw new NotPositiveException(numberOfTrials);
|
||||||
|
}
|
||||||
|
if (numberOfSuccesses < 0) {
|
||||||
|
throw new NotPositiveException(numberOfSuccesses);
|
||||||
|
}
|
||||||
|
if (probability < 0 || probability > 1) {
|
||||||
|
throw new OutOfRangeException(probability, 0, 1);
|
||||||
|
}
|
||||||
|
if (numberOfTrials < numberOfSuccesses) {
|
||||||
|
throw new MathIllegalArgumentException(
|
||||||
|
LocalizedFormats.BINOMIAL_INVALID_PARAMETERS_ORDER,
|
||||||
|
numberOfTrials, numberOfSuccesses);
|
||||||
|
}
|
||||||
|
if (alternativeHypothesis == null) {
|
||||||
|
throw new NullArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
final BinomialDistribution distribution = new BinomialDistribution(numberOfTrials, probability);
|
||||||
|
switch (alternativeHypothesis) {
|
||||||
|
case GREATER_THAN:
|
||||||
|
return 1 - distribution.cumulativeProbability(numberOfSuccesses - 1);
|
||||||
|
case LESS_THAN:
|
||||||
|
return distribution.cumulativeProbability(numberOfSuccesses);
|
||||||
|
case TWO_SIDED:
|
||||||
|
int criticalValueLow = 0;
|
||||||
|
int criticalValueHigh = numberOfTrials;
|
||||||
|
double pTotal = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
double pLow = distribution.probability(criticalValueLow);
|
||||||
|
double pHigh = distribution.probability(criticalValueHigh);
|
||||||
|
|
||||||
|
if (pLow == pHigh) {
|
||||||
|
pTotal += 2 * pLow;
|
||||||
|
criticalValueLow++;
|
||||||
|
criticalValueHigh--;
|
||||||
|
} else if (pLow < pHigh) {
|
||||||
|
pTotal += pLow;
|
||||||
|
criticalValueLow++;
|
||||||
|
} else {
|
||||||
|
pTotal += pHigh;
|
||||||
|
criticalValueHigh--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (criticalValueLow > numberOfSuccesses || criticalValueHigh < numberOfSuccesses) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pTotal;
|
||||||
|
default:
|
||||||
|
throw new MathInternalError(LocalizedFormats. OUT_OF_RANGE_SIMPLE, alternativeHypothesis,
|
||||||
|
AlternativeHypothesis.TWO_SIDED, AlternativeHypothesis.LESS_THAN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.math3.stat.inference;
|
||||||
|
|
||||||
|
import org.apache.commons.math3.exception.MathIllegalArgumentException;
|
||||||
|
import org.apache.commons.math3.exception.NotPositiveException;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test cases for the BinomialTest class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class BinomialTestTest {
|
||||||
|
|
||||||
|
protected BinomialTest testStatistic = new BinomialTest();
|
||||||
|
|
||||||
|
private static int successes = 51;
|
||||||
|
private static int trials = 235;
|
||||||
|
private static double probability = 1.0 / 6.0;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBinomialTestPValues() {
|
||||||
|
Assert.assertEquals(0.04375, testStatistic.binomialTest(
|
||||||
|
trials, successes, probability, AlternativeHypothesis.TWO_SIDED), 1E-4);
|
||||||
|
Assert.assertEquals(0.02654, testStatistic.binomialTest(
|
||||||
|
trials, successes, probability, AlternativeHypothesis.GREATER_THAN), 1E-4);
|
||||||
|
Assert.assertEquals(0.982, testStatistic.binomialTest(
|
||||||
|
trials, successes, probability, AlternativeHypothesis.LESS_THAN), 1E-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBinomialTestExceptions() {
|
||||||
|
try {
|
||||||
|
testStatistic.binomialTest(10, -1, 0.5, AlternativeHypothesis.TWO_SIDED);
|
||||||
|
Assert.fail("Expected not positive exception");
|
||||||
|
} catch (NotPositiveException e) {
|
||||||
|
// expected exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
testStatistic.binomialTest(10, 11, 0.5, AlternativeHypothesis.TWO_SIDED);
|
||||||
|
Assert.fail("Expected illegal argument exception");
|
||||||
|
} catch (MathIllegalArgumentException e) {
|
||||||
|
// expected exception;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
testStatistic.binomialTest(10, 11, 0.5, null);
|
||||||
|
Assert.fail("Expected illegal argument exception");
|
||||||
|
} catch (MathIllegalArgumentException e) {
|
||||||
|
// expected exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBinomialTestAcceptReject() {
|
||||||
|
double confidenceLevel95 = 0.95;
|
||||||
|
double confidenceLevel99 = 0.99;
|
||||||
|
|
||||||
|
Assert.assertTrue(testStatistic.binomialTest(trials, successes, probability, AlternativeHypothesis.TWO_SIDED, confidenceLevel95));
|
||||||
|
Assert.assertTrue(testStatistic.binomialTest(trials, successes, probability, AlternativeHypothesis.GREATER_THAN, confidenceLevel95));
|
||||||
|
Assert.assertFalse(testStatistic.binomialTest(trials, successes, probability, AlternativeHypothesis.LESS_THAN, confidenceLevel95));
|
||||||
|
|
||||||
|
Assert.assertFalse(testStatistic.binomialTest(trials, successes, probability, AlternativeHypothesis.TWO_SIDED, confidenceLevel99));
|
||||||
|
Assert.assertFalse(testStatistic.binomialTest(trials, successes, probability, AlternativeHypothesis.GREATER_THAN, confidenceLevel99));
|
||||||
|
Assert.assertFalse(testStatistic.binomialTest(trials, successes, probability, AlternativeHypothesis.LESS_THAN, confidenceLevel95));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue