This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-statistics.git


The following commit(s) were added to refs/heads/master by this push:
     new 02b3084  STATISTICS-67: Add inference module to the user guide
02b3084 is described below

commit 02b30848497ad9d6cecafc8843b9eb9eefdc1c8e
Author: aherbert <aherb...@apache.org>
AuthorDate: Mon Feb 20 13:52:16 2023 +0000

    STATISTICS-67: Add inference module to the user guide
---
 .../src/site/xdoc/index.xml                        |   2 +-
 .../statistics/inference/UserGuideTest.java        | 100 +++++++++++++++
 src/site/site.xml                                  |   1 +
 src/site/xdoc/index.xml                            |  15 +++
 src/site/xdoc/userguide/index.xml                  | 138 +++++++++++++++++++++
 5 files changed, 255 insertions(+), 1 deletion(-)

diff --git a/commons-statistics-inference/src/site/xdoc/index.xml 
b/commons-statistics-inference/src/site/xdoc/index.xml
index 78caeef..ab86ff4 100644
--- a/commons-statistics-inference/src/site/xdoc/index.xml
+++ b/commons-statistics-inference/src/site/xdoc/index.xml
@@ -43,7 +43,7 @@ double alpha = 1e-3;
 // Fail if we can *reject* the null hypothesis with confidence (1 - alpha)
 // that the observed match the expected
 if (ChiSquareTest.withDefaults().test(expected, observed).reject(alpha)) {
-    // Not significant ...
+    // Significant deviation from the expected ...
 }
 </source>
 
diff --git 
a/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/UserGuideTest.java
 
b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/UserGuideTest.java
new file mode 100644
index 0000000..e2e62b4
--- /dev/null
+++ 
b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/UserGuideTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.statistics.inference;
+
+import java.util.Arrays;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test code used in the inference section of the user guide.
+ */
+class UserGuideTest {
+    @Test
+    void testChiSquaredTest() {
+        double[] expected = {0.25, 0.5, 0.25};
+        long[] observed = {57, 123, 38};
+        SignificanceResult result = ChiSquareTest.withDefaults()
+                                                 .test(expected, observed);
+        Assertions.assertEquals(0.0316148, result.getPValue(), 1e-4);
+        Assertions.assertTrue(result.reject(0.05));
+        Assertions.assertFalse(result.reject(0.01));
+    }
+
+    @Test
+    void testTTest() {
+        // Generated with:
+        // from scipy.stats import norm, ttest_rel
+        // x = norm(73, 10).rvs(10).astype(int)
+        // y = norm(66, 12).rvs(10).astype(int)
+        // ttest_rel(x, y, alternative='greater')
+        // (repeated until the test was just above the 0.05 significance level)
+        double[] math = {53, 69, 65, 65, 67, 79, 86, 65, 62, 69};
+        double[] science = {75, 65, 68, 63, 55, 65, 73, 45, 51, 52};
+        Assertions.assertEquals(68.0, 
Arrays.stream(math).average().getAsDouble());
+        Assertions.assertEquals(61.2, 
Arrays.stream(science).average().getAsDouble());
+        SignificanceResult result = TTest.withDefaults()
+                                         
.with(AlternativeHypothesis.GREATER_THAN)
+                                         .pairedTest(math, science);
+        Assertions.assertEquals(0.05764, result.getPValue(), 1e-5);
+        Assertions.assertFalse(result.reject(0.05));
+    }
+
+    @Test
+    void testGTestIntrinsic() {
+        // See: http://www.biostathandbook.com/gtestgof.html
+
+        // Allele frequencies: Mpi 90/90, Mpi 90/100, Mpi 100/100
+        long[] observed = {1203, 2919, 1678};
+        // Mpi 90 proportion
+        double p = (2.0 * observed[0] + observed[1]) / (2 * 
Arrays.stream(observed).sum());
+        Assertions.assertEquals(0.459, p, 1e-2);
+
+        // Hardy-Weinberg proportions
+        double[] expected = {p * p, 2 * p * (1 - p), (1 - p) * (1 - p)};
+        Assertions.assertArrayEquals(new double[] {0.211, 0.497, 0.293}, 
expected, 5e-3);
+
+        SignificanceResult result = GTest.withDefaults()
+                                         .withDegreesOfFreedomAdjustment(1)
+                                         .test(expected, observed);
+        Assertions.assertEquals(1.03, result.getStatistic(), 5e-2);
+        Assertions.assertEquals(0.309, result.getPValue(), 5e-3);
+        Assertions.assertFalse(result.reject(0.05));
+    }
+
+    @Test
+    void testAOV() {
+        // See: http://www.biostathandbook.com/onewayanova.html
+
+        double[] tillamook = {0.0571, 0.0813, 0.0831, 0.0976, 0.0817, 0.0859, 
0.0735, 0.0659, 0.0923, 0.0836};
+        double[] newport = {0.0873, 0.0662, 0.0672, 0.0819, 0.0749, 0.0649, 
0.0835, 0.0725};
+        double[] petersburg = {0.0974, 0.1352, 0.0817, 0.1016, 0.0968, 0.1064, 
0.105};
+        double[] magadan = {0.1033, 0.0915, 0.0781, 0.0685, 0.0677, 0.0697, 
0.0764, 0.0689};
+        double[] tvarminne = {0.0703, 0.1026, 0.0956, 0.0973, 0.1039, 0.1045};
+
+        OneWayAnova.Result result = OneWayAnova.withDefaults()
+                                               .test(Arrays.asList(tillamook, 
newport, petersburg, magadan, tvarminne));
+        Assertions.assertEquals(4, result.getDFBG());
+        Assertions.assertEquals(34, result.getDFWG());
+        Assertions.assertEquals(0.001113, result.getMSBG(), 2e-5);
+        Assertions.assertEquals(0.000159, result.getMSWG(), 1e-5);
+        Assertions.assertEquals(7.12, result.getStatistic(), 1e-2);
+        Assertions.assertEquals(2.8e-4, result.getPValue(), 1e-5);
+        Assertions.assertTrue(result.reject(0.001));
+    }
+}
diff --git a/src/site/site.xml b/src/site/site.xml
index a528563..65e41c0 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -49,6 +49,7 @@
       <item name="Overview" href="/userguide/index.html#overview"/>
       <item name="Example Modules" 
href="/userguide/index.html#example-modules"/>
       <item name="Probability Distributions" 
href="/userguide/index.html#distributions"/>
+      <item name="Inference" href="/userguide/index.html#inference"/>
       <item name="Ranking" href="/userguide/index.html#ranking"/>
     </menu>
   </body>
diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml
index 3850790..463e60f 100644
--- a/src/site/xdoc/index.xml
+++ b/src/site/xdoc/index.xml
@@ -42,6 +42,21 @@ double upperTail = t.survivalProbability(2.75);       // 
P(T(29) &gt; 2.75)
 
 PoissonDistribution p = PoissonDistribution.of(4.56);
 int x = p.inverseCumulativeProbability(0.99);
+</source>
+
+      <p>
+        Hypothesis testing can be performed for various statistical tests, for 
example:
+      </p>
+
+<source class="prettyprint">
+double[] math    = {53, 69, 65, 65, 67, 79, 86, 65, 62, 69};   // mean = 68.0
+double[] science = {75, 65, 68, 63, 55, 65, 73, 45, 51, 52};   // mean = 61.2
+
+SignificanceResult result = TTest.withDefaults()
+                                 .with(AlternativeHypothesis.GREATER_THAN)
+                                 .pairedTest(math, science);
+result.getPValue();    // 0.05764
+result.reject(0.05);   // false
 </source>
 
       <p>
diff --git a/src/site/xdoc/userguide/index.xml 
b/src/site/xdoc/userguide/index.xml
index 4ddcee5..c187a15 100644
--- a/src/site/xdoc/userguide/index.xml
+++ b/src/site/xdoc/userguide/index.xml
@@ -55,6 +55,17 @@
             </li>
           </ul>
         </li>
+        <li>
+          <a href="#inference">Inference</a>
+          <ul>
+            <li>
+              <a href="#inference_overview">Overview</a>
+            </li>
+            <li>
+              <a href="#inference_examples">Examples</a>
+            </li>
+          </ul>
+        </li>
         <li>
           <a href="#ranking">Ranking</a>
         </li>
@@ -78,6 +89,14 @@
           commons-statistics-distribution</a></code> - Provides interfaces
           and classes for probability distributions.
         </li>
+        <li>
+          <code><a href="../commons-statistics-inference/index.html">
+          commons-statistics-inference</a></code> - Provides hypothesis 
testing.
+        </li>
+        <li>
+          <code><a href="../commons-statistics-ranking/index.html">
+          commons-statistics-ranking</a></code> - Provides rank 
transformations.
+        </li>
       </ul>
     </section>
 
@@ -335,6 +354,125 @@ double x2 = chi2.inverseSurvivalProbability(q);
         </p>
       </subsection>
     </section>
+    <section name="Inference" id="inference">
+      <p>
+        The <code>commons-statistics-inference</code> module provides 
hypothesis testing.
+      </p>
+      <subsection name="Overview" id="inference_overview">
+        <p>
+          The module provides test classes that implement a single, or family, 
of statistical
+          tests. Each test class provides methods to compute a test statistic 
and a p-value for the
+          significance of the statistic. These can be computed together using 
a <code>test</code>
+          method and returned as a
+          <a 
href="../commons-statistics-inference/apidocs/org/apache/commons/statistics/inference/DiscreteDistribution.html">SignificanceResult</a>.
+          The <code>SignificanceResult</code> has a method that can be used to 
<code>reject</code>
+          the null hypothesis at the provided significance level. Test classes 
may extend the
+          <code>SignificanceResult</code> to return more information about the 
test result,
+          for example the computed degrees of freedom.
+        </p>
+        <p>
+          Alternatively a <code>statistic</code> method is provided to compute 
<i>only</i> the
+          statistic as a <code>double</code> value. This statistic can be 
compared to a pre-computed
+          critical value, for example from a table of critical values.
+        </p>
+        <p>
+          A test is obtained using the <code>withDefaults()</code> method to 
return the test with
+          all options set to their default value. Any test options can be 
configured using
+          property change methods to return a new instance of the test. Tests 
that support an
+          <a 
href="../commons-statistics-inference/apidocs/org/apache/commons/statistics/inference/AlternativeHypothesis.html">
+          alternate hypothesis</a> will use a two-sided test by default. Test 
that support multiple
+          <a 
href="../commons-statistics-inference/apidocs/org/apache/commons/statistics/inference/PValueMethod.html">
+          p-value methods</a> will default to an appropriate computation for 
the size of the input
+          data. Unless otherwise noted test instances are immutable.
+        </p>
+      </subsection>
+      <subsection name="Examples" id="inference_examples">
+        <p>
+          A chi-square test that the observed counts conform to the expected 
frequencies.
+        </p>
+<source class="prettyprint">
+double[] expected = {0.25, 0.5, 0.25};
+long[] observed = {57, 123, 38};
+
+SignificanceResult result = ChiSquareTest.withDefaults()
+                                         .test(expected, observed);
+result.getPValue();    // 0.0316148
+result.reject(0.05);   // true
+result.reject(0.01);   // false
+</source>
+        <p>
+          A paired t-test that the student's marks in the math exam were 
greater than the science
+          exam. This fails to reject the null hypothesis (that there was no 
difference) with
+          95% confidence.
+        </p>
+<source class="prettyprint">
+double[] math    = {53, 69, 65, 65, 67, 79, 86, 65, 62, 69};   // mean = 68.0
+double[] science = {75, 65, 68, 63, 55, 65, 73, 45, 51, 52};   // mean = 61.2
+
+SignificanceResult result = TTest.withDefaults()
+                                 .with(AlternativeHypothesis.GREATER_THAN)
+                                 .pairedTest(math, science);
+result.getPValue();    // 0.05764
+result.reject(0.05);   // false
+</source>
+        <p>
+          A G-test that the allele frequencies conform to the expected 
Hardy-Weinberg proportions.
+          This is an example of an intrinsic hypothesis where the expected 
frequencies are computed
+          using the observations and the degrees of freedom must be adjusted.
+          The data is from McDonald (1989) Selection component analysis
+          of the Mpi locus in the amphipod Platorchestia platensis.
+          <i>Heredity</i> <b>62</b>: 243-249.
+        </p>
+<source class="prettyprint">
+// Allele frequencies: Mpi 90/90, Mpi 90/100, Mpi 100/100
+long[] observed = {1203, 2919, 1678};
+// Mpi 90 proportion
+double p = (2.0 * observed[0] + observed[1]) /
+           (2 * Arrays.stream(observed).sum());   // 5325 / 11600 = 0.459
+
+// Hardy-Weinberg proportions
+double[] expected = {p * p, 2 * p * (1 - p), (1 - p) * (1 - p)};
+// 0.211, 0.497, 0.293
+
+SignificanceResult result = GTest.withDefaults()
+                                 .withDegreesOfFreedomAdjustment(1)
+                                 .test(expected, observed);
+result.getStatistic();   // 1.03
+result.getPValue();      // 0.309
+result.reject(0.05);     // false
+</source>
+        <p>
+          A one-way analysis of variance test. This is an example where the 
result has more
+          information than the test statistic and the p-value.
+          The data is from McDonald <i>et al</i> (1991) Allozymes and 
morphometric characters of
+          three species of Mytilus in the Northern and Southern Hemispheres.
+          <i>Marine Biology</i> <b>111</b>: 323-333.
+        </p>
+<source class="prettyprint">
+double[] tillamook = {0.0571, 0.0813, 0.0831, 0.0976, 0.0817, 0.0859, 0.0735, 
0.0659, 0.0923, 0.0836};
+double[] newport = {0.0873, 0.0662, 0.0672, 0.0819, 0.0749, 0.0649, 0.0835, 
0.0725};
+double[] petersburg = {0.0974, 0.1352, 0.0817, 0.1016, 0.0968, 0.1064, 0.105};
+double[] magadan = {0.1033, 0.0915, 0.0781, 0.0685, 0.0677, 0.0697, 0.0764, 
0.0689};
+double[] tvarminne = {0.0703, 0.1026, 0.0956, 0.0973, 0.1039, 0.1045};
+
+Collection&lt;double[]&gt; data = Arrays.asList(tillamook, newport, 
petersburg, magadan, tvarminne);
+OneWayAnova.Result result = OneWayAnova.withDefaults()
+                                       .test(data);
+result.getStatistic();   // 7.12
+result.getPValue();      // 2.8e-4
+result.reject(0.001);    // true
+</source>
+      <p>
+        The result also provides the between and within group degrees of 
freedom and the mean
+        squares allowing reporting of the results in a table:
+      </p>
+      <table>
+        <tr><th></th><th>degrees of freedom</th><th>mean 
square</th><th>F</th><th>p</th></tr>
+        <tr><td>between 
groups</td><td>4</td><td>0.001113</td><td>7.12</td><td>2.8e-4</td></tr>
+        <tr><td>within 
groups</td><td>34</td><td>0.000159</td><td></td><td></td></tr>
+      </table>
+      </subsection>
+    </section>
     <section name="Ranking" id="ranking">
       <p>
         The <code>commons-statistics-ranking</code> module provides rank 
transformations.

Reply via email to