View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math.stat.inference;
18  
19  import org.apache.commons.math.MathException;
20  import org.apache.commons.math.distribution.DistributionFactory;
21  import org.apache.commons.math.distribution.TDistribution;
22  import org.apache.commons.math.distribution.TDistributionImpl;
23  import org.apache.commons.math.stat.StatUtils;
24  import org.apache.commons.math.stat.descriptive.StatisticalSummary;
25  
26  /**
27   * Implements t-test statistics defined in the {@link TTest} interface.
28   * <p>
29   * Uses commons-math {@link org.apache.commons.math.distribution.TDistribution}
30   * implementation to estimate exact p-values.</p>
31   *
32   * @version $Revision: 617953 $ $Date: 2008-02-02 22:54:00 -0700 (Sat, 02 Feb 2008) $
33   */
34  public class TTestImpl implements TTest  {
35  
36      /** Distribution used to compute inference statistics. */
37      private TDistribution distribution;
38      
39      /**
40       * Default constructor.
41       */
42      public TTestImpl() {
43          this(new TDistributionImpl(1.0));
44      }
45      
46      /**
47       * Create a test instance using the given distribution for computing
48       * inference statistics.
49       * @param t distribution used to compute inference statistics.
50       * @since 1.2
51       */
52      public TTestImpl(TDistribution t) {
53          super();
54          setDistribution(t);
55      }
56      
57      /**
58       * Computes a paired, 2-sample t-statistic based on the data in the input 
59       * arrays.  The t-statistic returned is equivalent to what would be returned by
60       * computing the one-sample t-statistic {@link #t(double, double[])}, with
61       * <code>mu = 0</code> and the sample array consisting of the (signed) 
62       * differences between corresponding entries in <code>sample1</code> and 
63       * <code>sample2.</code>
64       * <p>
65       * <strong>Preconditions</strong>: <ul>
66       * <li>The input arrays must have the same length and their common length
67       * must be at least 2.
68       * </li></ul></p>
69       *
70       * @param sample1 array of sample data values
71       * @param sample2 array of sample data values
72       * @return t statistic
73       * @throws IllegalArgumentException if the precondition is not met
74       * @throws MathException if the statistic can not be computed do to a
75       *         convergence or other numerical error.
76       */
77      public double pairedT(double[] sample1, double[] sample2)
78          throws IllegalArgumentException, MathException {
79          if ((sample1 == null) || (sample2 == null ||
80                  Math.min(sample1.length, sample2.length) < 2)) {
81              throw new IllegalArgumentException("insufficient data for t statistic");
82          }
83          double meanDifference = StatUtils.meanDifference(sample1, sample2);
84          return t(meanDifference, 0,  
85                  StatUtils.varianceDifference(sample1, sample2, meanDifference),
86                  (double) sample1.length);
87      }
88  
89       /**
90       * Returns the <i>observed significance level</i>, or 
91       * <i> p-value</i>, associated with a paired, two-sample, two-tailed t-test 
92       * based on the data in the input arrays.
93       * <p>
94       * The number returned is the smallest significance level
95       * at which one can reject the null hypothesis that the mean of the paired
96       * differences is 0 in favor of the two-sided alternative that the mean paired 
97       * difference is not equal to 0. For a one-sided test, divide the returned 
98       * value by 2.</p>
99       * <p>
100      * This test is equivalent to a one-sample t-test computed using
101      * {@link #tTest(double, double[])} with <code>mu = 0</code> and the sample
102      * array consisting of the signed differences between corresponding elements of 
103      * <code>sample1</code> and <code>sample2.</code></p>
104      * <p>
105      * <strong>Usage Note:</strong><br>
106      * The validity of the p-value depends on the assumptions of the parametric
107      * t-test procedure, as discussed 
108      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">
109      * here</a></p>
110      * <p>
111      * <strong>Preconditions</strong>: <ul>
112      * <li>The input array lengths must be the same and their common length must
113      * be at least 2.
114      * </li></ul></p>
115      *
116      * @param sample1 array of sample data values
117      * @param sample2 array of sample data values
118      * @return p-value for t-test
119      * @throws IllegalArgumentException if the precondition is not met
120      * @throws MathException if an error occurs computing the p-value
121      */
122     public double pairedTTest(double[] sample1, double[] sample2)
123         throws IllegalArgumentException, MathException {
124         double meanDifference = StatUtils.meanDifference(sample1, sample2);
125         return tTest(meanDifference, 0, 
126                 StatUtils.varianceDifference(sample1, sample2, meanDifference), 
127                 (double) sample1.length);
128     }
129 
130      /**
131      * Performs a paired t-test evaluating the null hypothesis that the 
132      * mean of the paired differences between <code>sample1</code> and
133      * <code>sample2</code> is 0 in favor of the two-sided alternative that the 
134      * mean paired difference is not equal to 0, with significance level 
135      * <code>alpha</code>.
136      * <p>
137      * Returns <code>true</code> iff the null hypothesis can be rejected with 
138      * confidence <code>1 - alpha</code>.  To perform a 1-sided test, use 
139      * <code>alpha * 2</code></p>
140      * <p>
141      * <strong>Usage Note:</strong><br>
142      * The validity of the test depends on the assumptions of the parametric
143      * t-test procedure, as discussed 
144      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">
145      * here</a></p>
146      * <p>
147      * <strong>Preconditions</strong>: <ul>
148      * <li>The input array lengths must be the same and their common length 
149      * must be at least 2.
150      * </li>
151      * <li> <code> 0 < alpha < 0.5 </code>
152      * </li></ul></p>
153      *
154      * @param sample1 array of sample data values
155      * @param sample2 array of sample data values
156      * @param alpha significance level of the test
157      * @return true if the null hypothesis can be rejected with 
158      * confidence 1 - alpha
159      * @throws IllegalArgumentException if the preconditions are not met
160      * @throws MathException if an error occurs performing the test
161      */
162     public boolean pairedTTest(double[] sample1, double[] sample2, double alpha)
163         throws IllegalArgumentException, MathException {
164         if ((alpha <= 0) || (alpha > 0.5)) {
165             throw new IllegalArgumentException("bad significance level: " + alpha);
166         }
167         return (pairedTTest(sample1, sample2) < alpha);
168     }
169 
170     /**
171      * Computes a <a href="http://www.itl.nist.gov/div898/handbook/prc/section2/prc22.htm#formula"> 
172      * t statistic </a> given observed values and a comparison constant.
173      * <p>
174      * This statistic can be used to perform a one sample t-test for the mean.
175      * </p><p>
176      * <strong>Preconditions</strong>: <ul>
177      * <li>The observed array length must be at least 2.
178      * </li></ul></p>
179      *
180      * @param mu comparison constant
181      * @param observed array of values
182      * @return t statistic
183      * @throws IllegalArgumentException if input array length is less than 2
184      */
185     public double t(double mu, double[] observed)
186     throws IllegalArgumentException {
187         if ((observed == null) || (observed.length < 2)) {
188             throw new IllegalArgumentException("insufficient data for t statistic");
189         }
190         return t(StatUtils.mean(observed), mu, StatUtils.variance(observed),
191                 observed.length);
192     }
193 
194     /**
195      * Computes a <a href="http://www.itl.nist.gov/div898/handbook/prc/section2/prc22.htm#formula">
196      * t statistic </a> to use in comparing the mean of the dataset described by 
197      * <code>sampleStats</code> to <code>mu</code>.
198      * <p>
199      * This statistic can be used to perform a one sample t-test for the mean.
200      * </p><p>
201      * <strong>Preconditions</strong>: <ul>
202      * <li><code>observed.getN() > = 2</code>.
203      * </li></ul></p>
204      *
205      * @param mu comparison constant
206      * @param sampleStats DescriptiveStatistics holding sample summary statitstics
207      * @return t statistic
208      * @throws IllegalArgumentException if the precondition is not met
209      */
210     public double t(double mu, StatisticalSummary sampleStats)
211     throws IllegalArgumentException {
212         if ((sampleStats == null) || (sampleStats.getN() < 2)) {
213             throw new IllegalArgumentException("insufficient data for t statistic");
214         }
215         return t(sampleStats.getMean(), mu, sampleStats.getVariance(),
216                 sampleStats.getN());
217     }
218 
219     /**
220      * Computes a 2-sample t statistic,  under the hypothesis of equal 
221      * subpopulation variances.  To compute a t-statistic without the
222      * equal variances hypothesis, use {@link #t(double[], double[])}.
223      * <p>
224      * This statistic can be used to perform a (homoscedastic) two-sample
225      * t-test to compare sample means.</p>
226      * <p>
227      * The t-statisitc is</p>
228      * <p>
229      * &nbsp;&nbsp;<code>  t = (m1 - m2) / (sqrt(1/n1 +1/n2) sqrt(var))</code>
230      * </p><p>
231      * where <strong><code>n1</code></strong> is the size of first sample; 
232      * <strong><code> n2</code></strong> is the size of second sample; 
233      * <strong><code> m1</code></strong> is the mean of first sample;  
234      * <strong><code> m2</code></strong> is the mean of second sample</li>
235      * </ul>
236      * and <strong><code>var</code></strong> is the pooled variance estimate:
237      * </p><p>
238      * <code>var = sqrt(((n1 - 1)var1 + (n2 - 1)var2) / ((n1-1) + (n2-1)))</code>
239      * </p><p> 
240      * with <strong><code>var1<code></strong> the variance of the first sample and
241      * <strong><code>var2</code></strong> the variance of the second sample.
242      * </p><p>
243      * <strong>Preconditions</strong>: <ul>
244      * <li>The observed array lengths must both be at least 2.
245      * </li></ul></p>
246      *
247      * @param sample1 array of sample data values
248      * @param sample2 array of sample data values
249      * @return t statistic
250      * @throws IllegalArgumentException if the precondition is not met
251      */
252     public double homoscedasticT(double[] sample1, double[] sample2)
253     throws IllegalArgumentException {
254         if ((sample1 == null) || (sample2 == null ||
255                 Math.min(sample1.length, sample2.length) < 2)) {
256             throw new IllegalArgumentException("insufficient data for t statistic");
257         }
258         return homoscedasticT(StatUtils.mean(sample1), StatUtils.mean(sample2),
259                 StatUtils.variance(sample1), StatUtils.variance(sample2),
260                 (double) sample1.length, (double) sample2.length);
261     }
262     
263     /**
264      * Computes a 2-sample t statistic, without the hypothesis of equal
265      * subpopulation variances.  To compute a t-statistic assuming equal
266      * variances, use {@link #homoscedasticT(double[], double[])}.
267      * <p>
268      * This statistic can be used to perform a two-sample t-test to compare
269      * sample means.</p>
270      * <p>
271      * The t-statisitc is</p>
272      * <p>
273      * &nbsp;&nbsp; <code>  t = (m1 - m2) / sqrt(var1/n1 + var2/n2)</code>
274      * </p><p>
275      *  where <strong><code>n1</code></strong> is the size of the first sample
276      * <strong><code> n2</code></strong> is the size of the second sample; 
277      * <strong><code> m1</code></strong> is the mean of the first sample;  
278      * <strong><code> m2</code></strong> is the mean of the second sample;
279      * <strong><code> var1</code></strong> is the variance of the first sample;
280      * <strong><code> var2</code></strong> is the variance of the second sample;  
281      * </p><p>
282      * <strong>Preconditions</strong>: <ul>
283      * <li>The observed array lengths must both be at least 2.
284      * </li></ul></p>
285      *
286      * @param sample1 array of sample data values
287      * @param sample2 array of sample data values
288      * @return t statistic
289      * @throws IllegalArgumentException if the precondition is not met
290      */
291     public double t(double[] sample1, double[] sample2)
292     throws IllegalArgumentException {
293         if ((sample1 == null) || (sample2 == null ||
294                 Math.min(sample1.length, sample2.length) < 2)) {
295             throw new IllegalArgumentException("insufficient data for t statistic");
296         }
297         return t(StatUtils.mean(sample1), StatUtils.mean(sample2),
298                 StatUtils.variance(sample1), StatUtils.variance(sample2),
299                 (double) sample1.length, (double) sample2.length);
300     }
301 
302     /**
303      * Computes a 2-sample t statistic </a>, comparing the means of the datasets
304      * described by two {@link StatisticalSummary} instances, without the
305      * assumption of equal subpopulation variances.  Use 
306      * {@link #homoscedasticT(StatisticalSummary, StatisticalSummary)} to
307      * compute a t-statistic under the equal variances assumption.
308      * <p>
309      * This statistic can be used to perform a two-sample t-test to compare
310      * sample means.</p>
311      * <p>
312       * The returned  t-statisitc is</p>
313      * <p>
314      * &nbsp;&nbsp; <code>  t = (m1 - m2) / sqrt(var1/n1 + var2/n2)</code>
315      * </p><p>
316      * where <strong><code>n1</code></strong> is the size of the first sample; 
317      * <strong><code> n2</code></strong> is the size of the second sample; 
318      * <strong><code> m1</code></strong> is the mean of the first sample;  
319      * <strong><code> m2</code></strong> is the mean of the second sample
320      * <strong><code> var1</code></strong> is the variance of the first sample;  
321      * <strong><code> var2</code></strong> is the variance of the second sample
322      * </p><p>
323      * <strong>Preconditions</strong>: <ul>
324      * <li>The datasets described by the two Univariates must each contain
325      * at least 2 observations.
326      * </li></ul></p>
327      *
328      * @param sampleStats1 StatisticalSummary describing data from the first sample
329      * @param sampleStats2 StatisticalSummary describing data from the second sample
330      * @return t statistic
331      * @throws IllegalArgumentException if the precondition is not met
332      */
333     public double t(StatisticalSummary sampleStats1, 
334             StatisticalSummary sampleStats2)
335     throws IllegalArgumentException {
336         if ((sampleStats1 == null) ||
337                 (sampleStats2 == null ||
338                         Math.min(sampleStats1.getN(), sampleStats2.getN()) < 2)) {
339             throw new IllegalArgumentException("insufficient data for t statistic");
340         }
341         return t(sampleStats1.getMean(), sampleStats2.getMean(), 
342                 sampleStats1.getVariance(), sampleStats2.getVariance(),
343                 (double) sampleStats1.getN(), (double) sampleStats2.getN());
344     }
345     
346     /**
347      * Computes a 2-sample t statistic, comparing the means of the datasets
348      * described by two {@link StatisticalSummary} instances, under the
349      * assumption of equal subpopulation variances.  To compute a t-statistic
350      * without the equal variances assumption, use 
351      * {@link #t(StatisticalSummary, StatisticalSummary)}.
352      * <p>
353      * This statistic can be used to perform a (homoscedastic) two-sample
354      * t-test to compare sample means.</p>
355      * <p>
356      * The t-statisitc returned is</p>
357      * <p>
358      * &nbsp;&nbsp;<code>  t = (m1 - m2) / (sqrt(1/n1 +1/n2) sqrt(var))</code>
359      * </p><p>
360      * where <strong><code>n1</code></strong> is the size of first sample; 
361      * <strong><code> n2</code></strong> is the size of second sample; 
362      * <strong><code> m1</code></strong> is the mean of first sample;  
363      * <strong><code> m2</code></strong> is the mean of second sample
364      * and <strong><code>var</code></strong> is the pooled variance estimate:
365      * </p><p>
366      * <code>var = sqrt(((n1 - 1)var1 + (n2 - 1)var2) / ((n1-1) + (n2-1)))</code>
367      * <p> 
368      * with <strong><code>var1<code></strong> the variance of the first sample and
369      * <strong><code>var2</code></strong> the variance of the second sample.
370      * </p><p>
371      * <strong>Preconditions</strong>: <ul>
372      * <li>The datasets described by the two Univariates must each contain
373      * at least 2 observations.
374      * </li></ul></p>
375      *
376      * @param sampleStats1 StatisticalSummary describing data from the first sample
377      * @param sampleStats2 StatisticalSummary describing data from the second sample
378      * @return t statistic
379      * @throws IllegalArgumentException if the precondition is not met
380      */
381     public double homoscedasticT(StatisticalSummary sampleStats1, 
382             StatisticalSummary sampleStats2)
383     throws IllegalArgumentException {
384         if ((sampleStats1 == null) ||
385                 (sampleStats2 == null ||
386                         Math.min(sampleStats1.getN(), sampleStats2.getN()) < 2)) {
387             throw new IllegalArgumentException("insufficient data for t statistic");
388         }
389         return homoscedasticT(sampleStats1.getMean(), sampleStats2.getMean(), 
390                 sampleStats1.getVariance(), sampleStats2.getVariance(), 
391                 (double) sampleStats1.getN(), (double) sampleStats2.getN());
392     }
393 
394      /**
395      * Returns the <i>observed significance level</i>, or 
396      * <i>p-value</i>, associated with a one-sample, two-tailed t-test 
397      * comparing the mean of the input array with the constant <code>mu</code>.
398      * <p>
399      * The number returned is the smallest significance level
400      * at which one can reject the null hypothesis that the mean equals 
401      * <code>mu</code> in favor of the two-sided alternative that the mean
402      * is different from <code>mu</code>. For a one-sided test, divide the 
403      * returned value by 2.</p>
404      * <p>
405      * <strong>Usage Note:</strong><br>
406      * The validity of the test depends on the assumptions of the parametric
407      * t-test procedure, as discussed 
408      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">here</a>
409      * </p><p>
410      * <strong>Preconditions</strong>: <ul>
411      * <li>The observed array length must be at least 2.
412      * </li></ul></p>
413      *
414      * @param mu constant value to compare sample mean against
415      * @param sample array of sample data values
416      * @return p-value
417      * @throws IllegalArgumentException if the precondition is not met
418      * @throws MathException if an error occurs computing the p-value
419      */
420     public double tTest(double mu, double[] sample)
421     throws IllegalArgumentException, MathException {
422         if ((sample == null) || (sample.length < 2)) {
423             throw new IllegalArgumentException("insufficient data for t statistic");
424         }
425         return tTest( StatUtils.mean(sample), mu, StatUtils.variance(sample),
426                 sample.length);
427     }
428 
429     /**
430      * Performs a <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda353.htm">
431      * two-sided t-test</a> evaluating the null hypothesis that the mean of the population from
432      * which <code>sample</code> is drawn equals <code>mu</code>.
433      * <p>
434      * Returns <code>true</code> iff the null hypothesis can be 
435      * rejected with confidence <code>1 - alpha</code>.  To 
436      * perform a 1-sided test, use <code>alpha * 2</code>
437      * </p><p>
438      * <strong>Examples:</strong><br><ol>
439      * <li>To test the (2-sided) hypothesis <code>sample mean = mu </code> at
440      * the 95% level, use <br><code>tTest(mu, sample, 0.05) </code>
441      * </li>
442      * <li>To test the (one-sided) hypothesis <code> sample mean < mu </code>
443      * at the 99% level, first verify that the measured sample mean is less 
444      * than <code>mu</code> and then use 
445      * <br><code>tTest(mu, sample, 0.02) </code>
446      * </li></ol></p>
447      * <p>
448      * <strong>Usage Note:</strong><br>
449      * The validity of the test depends on the assumptions of the one-sample 
450      * parametric t-test procedure, as discussed 
451      * <a href="http://www.basic.nwu.edu/statguidefiles/sg_glos.html#one-sample">here</a>
452      * </p><p>
453      * <strong>Preconditions</strong>: <ul>
454      * <li>The observed array length must be at least 2.
455      * </li></ul></p>
456      *
457      * @param mu constant value to compare sample mean against
458      * @param sample array of sample data values
459      * @param alpha significance level of the test
460      * @return p-value
461      * @throws IllegalArgumentException if the precondition is not met
462      * @throws MathException if an error computing the p-value
463      */
464     public boolean tTest(double mu, double[] sample, double alpha)
465     throws IllegalArgumentException, MathException {
466         if ((alpha <= 0) || (alpha > 0.5)) {
467             throw new IllegalArgumentException("bad significance level: " + alpha);
468         }
469         return (tTest(mu, sample) < alpha);
470     }
471 
472     /**
473      * Returns the <i>observed significance level</i>, or 
474      * <i>p-value</i>, associated with a one-sample, two-tailed t-test 
475      * comparing the mean of the dataset described by <code>sampleStats</code>
476      * with the constant <code>mu</code>.
477      * <p>
478      * The number returned is the smallest significance level
479      * at which one can reject the null hypothesis that the mean equals 
480      * <code>mu</code> in favor of the two-sided alternative that the mean
481      * is different from <code>mu</code>. For a one-sided test, divide the 
482      * returned value by 2.</p>
483      * <p>
484      * <strong>Usage Note:</strong><br>
485      * The validity of the test depends on the assumptions of the parametric
486      * t-test procedure, as discussed 
487      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">
488      * here</a></p>
489      * <p>
490      * <strong>Preconditions</strong>: <ul>
491      * <li>The sample must contain at least 2 observations.
492      * </li></ul></p>
493      *
494      * @param mu constant value to compare sample mean against
495      * @param sampleStats StatisticalSummary describing sample data
496      * @return p-value
497      * @throws IllegalArgumentException if the precondition is not met
498      * @throws MathException if an error occurs computing the p-value
499      */
500     public double tTest(double mu, StatisticalSummary sampleStats)
501     throws IllegalArgumentException, MathException {
502         if ((sampleStats == null) || (sampleStats.getN() < 2)) {
503             throw new IllegalArgumentException("insufficient data for t statistic");
504         }
505         return tTest(sampleStats.getMean(), mu, sampleStats.getVariance(),
506                 sampleStats.getN());
507     }
508 
509      /**
510      * Performs a <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda353.htm">
511      * two-sided t-test</a> evaluating the null hypothesis that the mean of the
512      * population from which the dataset described by <code>stats</code> is
513      * drawn equals <code>mu</code>.
514      * <p>
515      * Returns <code>true</code> iff the null hypothesis can be rejected with
516      * confidence <code>1 - alpha</code>.  To  perform a 1-sided test, use
517      * <code>alpha * 2.</code></p>
518      * <p>
519      * <strong>Examples:</strong><br><ol>
520      * <li>To test the (2-sided) hypothesis <code>sample mean = mu </code> at
521      * the 95% level, use <br><code>tTest(mu, sampleStats, 0.05) </code>
522      * </li>
523      * <li>To test the (one-sided) hypothesis <code> sample mean < mu </code>
524      * at the 99% level, first verify that the measured sample mean is less 
525      * than <code>mu</code> and then use 
526      * <br><code>tTest(mu, sampleStats, 0.02) </code>
527      * </li></ol></p>
528      * <p>
529      * <strong>Usage Note:</strong><br>
530      * The validity of the test depends on the assumptions of the one-sample 
531      * parametric t-test procedure, as discussed 
532      * <a href="http://www.basic.nwu.edu/statguidefiles/sg_glos.html#one-sample">here</a>
533      * </p><p>
534      * <strong>Preconditions</strong>: <ul>
535      * <li>The sample must include at least 2 observations.
536      * </li></ul></p>
537      *
538      * @param mu constant value to compare sample mean against
539      * @param sampleStats StatisticalSummary describing sample data values
540      * @param alpha significance level of the test
541      * @return p-value
542      * @throws IllegalArgumentException if the precondition is not met
543      * @throws MathException if an error occurs computing the p-value
544      */
545     public boolean tTest( double mu, StatisticalSummary sampleStats,
546             double alpha)
547     throws IllegalArgumentException, MathException {
548         if ((alpha <= 0) || (alpha > 0.5)) {
549             throw new IllegalArgumentException("bad significance level: " + alpha);
550         }
551         return (tTest(mu, sampleStats) < alpha);
552     }
553 
554     /**
555      * Returns the <i>observed significance level</i>, or 
556      * <i>p-value</i>, associated with a two-sample, two-tailed t-test 
557      * comparing the means of the input arrays.
558      * <p>
559      * The number returned is the smallest significance level
560      * at which one can reject the null hypothesis that the two means are
561      * equal in favor of the two-sided alternative that they are different. 
562      * For a one-sided test, divide the returned value by 2.</p>
563      * <p>
564      * The test does not assume that the underlying popuation variances are
565      * equal  and it uses approximated degrees of freedom computed from the 
566      * sample data to compute the p-value.  The t-statistic used is as defined in
567      * {@link #t(double[], double[])} and the Welch-Satterthwaite approximation
568      * to the degrees of freedom is used, 
569      * as described 
570      * <a href="http://www.itl.nist.gov/div898/handbook/prc/section3/prc31.htm">
571      * here.</a>  To perform the test under the assumption of equal subpopulation
572      * variances, use {@link #homoscedasticTTest(double[], double[])}.</p>
573      * <p>
574      * <strong>Usage Note:</strong><br>
575      * The validity of the p-value depends on the assumptions of the parametric
576      * t-test procedure, as discussed 
577      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">
578      * here</a></p>
579      * <p>
580      * <strong>Preconditions</strong>: <ul>
581      * <li>The observed array lengths must both be at least 2.
582      * </li></ul></p>
583      *
584      * @param sample1 array of sample data values
585      * @param sample2 array of sample data values
586      * @return p-value for t-test
587      * @throws IllegalArgumentException if the precondition is not met
588      * @throws MathException if an error occurs computing the p-value
589      */
590     public double tTest(double[] sample1, double[] sample2)
591     throws IllegalArgumentException, MathException {
592         if ((sample1 == null) || (sample2 == null ||
593                 Math.min(sample1.length, sample2.length) < 2)) {
594             throw new IllegalArgumentException("insufficient data");
595         }
596         return tTest(StatUtils.mean(sample1), StatUtils.mean(sample2),
597                 StatUtils.variance(sample1), StatUtils.variance(sample2),
598                 (double) sample1.length, (double) sample2.length);
599     }
600     
601     /**
602      * Returns the <i>observed significance level</i>, or 
603      * <i>p-value</i>, associated with a two-sample, two-tailed t-test 
604      * comparing the means of the input arrays, under the assumption that
605      * the two samples are drawn from subpopulations with equal variances.
606      * To perform the test without the equal variances assumption, use
607      * {@link #tTest(double[], double[])}.
608      * <p>
609      * The number returned is the smallest significance level
610      * at which one can reject the null hypothesis that the two means are
611      * equal in favor of the two-sided alternative that they are different. 
612      * For a one-sided test, divide the returned value by 2.</p>
613      * <p>
614      * A pooled variance estimate is used to compute the t-statistic.  See
615      * {@link #homoscedasticT(double[], double[])}. The sum of the sample sizes
616      * minus 2 is used as the degrees of freedom.</p>
617      * <p>
618      * <strong>Usage Note:</strong><br>
619      * The validity of the p-value depends on the assumptions of the parametric
620      * t-test procedure, as discussed 
621      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">
622      * here</a></p>
623      * <p>
624      * <strong>Preconditions</strong>: <ul>
625      * <li>The observed array lengths must both be at least 2.
626      * </li></ul></p>
627      *
628      * @param sample1 array of sample data values
629      * @param sample2 array of sample data values
630      * @return p-value for t-test
631      * @throws IllegalArgumentException if the precondition is not met
632      * @throws MathException if an error occurs computing the p-value
633      */
634     public double homoscedasticTTest(double[] sample1, double[] sample2)
635     throws IllegalArgumentException, MathException {
636         if ((sample1 == null) || (sample2 == null ||
637                 Math.min(sample1.length, sample2.length) < 2)) {
638             throw new IllegalArgumentException("insufficient data");
639         }
640         return homoscedasticTTest(StatUtils.mean(sample1), 
641                 StatUtils.mean(sample2), StatUtils.variance(sample1),
642                 StatUtils.variance(sample2), (double) sample1.length, 
643                 (double) sample2.length);
644     }
645     
646 
647      /**
648      * Performs a 
649      * <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda353.htm">
650      * two-sided t-test</a> evaluating the null hypothesis that <code>sample1</code> 
651      * and <code>sample2</code> are drawn from populations with the same mean, 
652      * with significance level <code>alpha</code>.  This test does not assume
653      * that the subpopulation variances are equal.  To perform the test assuming
654      * equal variances, use 
655      * {@link #homoscedasticTTest(double[], double[], double)}.
656      * <p>
657      * Returns <code>true</code> iff the null hypothesis that the means are
658      * equal can be rejected with confidence <code>1 - alpha</code>.  To 
659      * perform a 1-sided test, use <code>alpha / 2</code></p>
660      * <p>
661      * See {@link #t(double[], double[])} for the formula used to compute the
662      * t-statistic.  Degrees of freedom are approximated using the
663      * <a href="http://www.itl.nist.gov/div898/handbook/prc/section3/prc31.htm">
664      * Welch-Satterthwaite approximation.</a></p>
665       
666      * <p>
667      * <strong>Examples:</strong><br><ol>
668      * <li>To test the (2-sided) hypothesis <code>mean 1 = mean 2 </code> at
669      * the 95% level,  use 
670      * <br><code>tTest(sample1, sample2, 0.05). </code>
671      * </li>
672      * <li>To test the (one-sided) hypothesis <code> mean 1 < mean 2 </code> at
673      * the 99% level, first verify that the measured  mean of <code>sample 1</code>
674      * is less than the mean of <code>sample 2</code> and then use 
675      * <br><code>tTest(sample1, sample2, 0.02) </code>
676      * </li></ol></p>
677      * <p>
678      * <strong>Usage Note:</strong><br>
679      * The validity of the test depends on the assumptions of the parametric
680      * t-test procedure, as discussed 
681      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">
682      * here</a></p>
683      * <p>
684      * <strong>Preconditions</strong>: <ul>
685      * <li>The observed array lengths must both be at least 2.
686      * </li>
687      * <li> <code> 0 < alpha < 0.5 </code>
688      * </li></ul></p>
689      *
690      * @param sample1 array of sample data values
691      * @param sample2 array of sample data values
692      * @param alpha significance level of the test
693      * @return true if the null hypothesis can be rejected with 
694      * confidence 1 - alpha
695      * @throws IllegalArgumentException if the preconditions are not met
696      * @throws MathException if an error occurs performing the test
697      */
698     public boolean tTest(double[] sample1, double[] sample2,
699             double alpha)
700     throws IllegalArgumentException, MathException {
701         if ((alpha <= 0) || (alpha > 0.5)) {
702             throw new IllegalArgumentException("bad significance level: " + alpha);
703         }
704         return (tTest(sample1, sample2) < alpha);
705     }
706     
707     /**
708      * Performs a 
709      * <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda353.htm">
710      * two-sided t-test</a> evaluating the null hypothesis that <code>sample1</code> 
711      * and <code>sample2</code> are drawn from populations with the same mean, 
712      * with significance level <code>alpha</code>,  assuming that the
713      * subpopulation variances are equal.  Use 
714      * {@link #tTest(double[], double[], double)} to perform the test without
715      * the assumption of equal variances.
716      * <p>
717      * Returns <code>true</code> iff the null hypothesis that the means are
718      * equal can be rejected with confidence <code>1 - alpha</code>.  To 
719      * perform a 1-sided test, use <code>alpha * 2.</code>  To perform the test
720      * without the assumption of equal subpopulation variances, use 
721      * {@link #tTest(double[], double[], double)}.</p>
722      * <p>
723      * A pooled variance estimate is used to compute the t-statistic. See
724      * {@link #t(double[], double[])} for the formula. The sum of the sample
725      * sizes minus 2 is used as the degrees of freedom.</p>
726      * <p>
727      * <strong>Examples:</strong><br><ol>
728      * <li>To test the (2-sided) hypothesis <code>mean 1 = mean 2 </code> at
729      * the 95% level, use <br><code>tTest(sample1, sample2, 0.05). </code>
730      * </li>
731      * <li>To test the (one-sided) hypothesis <code> mean 1 < mean 2, </code>
732      * at the 99% level, first verify that the measured mean of 
733      * <code>sample 1</code> is less than the mean of <code>sample 2</code>
734      * and then use
735      * <br><code>tTest(sample1, sample2, 0.02) </code>
736      * </li></ol></p>
737      * <p>
738      * <strong>Usage Note:</strong><br>
739      * The validity of the test depends on the assumptions of the parametric
740      * t-test procedure, as discussed 
741      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">
742      * here</a></p>
743      * <p>
744      * <strong>Preconditions</strong>: <ul>
745      * <li>The observed array lengths must both be at least 2.
746      * </li>
747      * <li> <code> 0 < alpha < 0.5 </code>
748      * </li></ul></p>
749      *
750      * @param sample1 array of sample data values
751      * @param sample2 array of sample data values
752      * @param alpha significance level of the test
753      * @return true if the null hypothesis can be rejected with 
754      * confidence 1 - alpha
755      * @throws IllegalArgumentException if the preconditions are not met
756      * @throws MathException if an error occurs performing the test
757      */
758     public boolean homoscedasticTTest(double[] sample1, double[] sample2,
759             double alpha)
760     throws IllegalArgumentException, MathException {
761         if ((alpha <= 0) || (alpha > 0.5)) {
762             throw new IllegalArgumentException("bad significance level: " + alpha);
763         }
764         return (homoscedasticTTest(sample1, sample2) < alpha);
765     }
766 
767      /**
768      * Returns the <i>observed significance level</i>, or 
769      * <i>p-value</i>, associated with a two-sample, two-tailed t-test 
770      * comparing the means of the datasets described by two StatisticalSummary
771      * instances.
772      * <p>
773      * The number returned is the smallest significance level
774      * at which one can reject the null hypothesis that the two means are
775      * equal in favor of the two-sided alternative that they are different. 
776      * For a one-sided test, divide the returned value by 2.</p>
777      * <p>
778      * The test does not assume that the underlying popuation variances are
779      * equal  and it uses approximated degrees of freedom computed from the 
780      * sample data to compute the p-value.   To perform the test assuming
781      * equal variances, use 
782      * {@link #homoscedasticTTest(StatisticalSummary, StatisticalSummary)}.</p>
783      * <p>
784      * <strong>Usage Note:</strong><br>
785      * The validity of the p-value depends on the assumptions of the parametric
786      * t-test procedure, as discussed 
787      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">
788      * here</a></p>
789      * <p>
790      * <strong>Preconditions</strong>: <ul>
791      * <li>The datasets described by the two Univariates must each contain
792      * at least 2 observations.
793      * </li></ul></p>
794      *
795      * @param sampleStats1  StatisticalSummary describing data from the first sample
796      * @param sampleStats2  StatisticalSummary describing data from the second sample
797      * @return p-value for t-test
798      * @throws IllegalArgumentException if the precondition is not met
799      * @throws MathException if an error occurs computing the p-value
800      */
801     public double tTest(StatisticalSummary sampleStats1, StatisticalSummary sampleStats2)
802     throws IllegalArgumentException, MathException {
803         if ((sampleStats1 == null) || (sampleStats2 == null ||
804                 Math.min(sampleStats1.getN(), sampleStats2.getN()) < 2)) {
805             throw new IllegalArgumentException("insufficient data for t statistic");
806         }
807         return tTest(sampleStats1.getMean(), sampleStats2.getMean(), sampleStats1.getVariance(),
808                 sampleStats2.getVariance(), (double) sampleStats1.getN(), 
809                 (double) sampleStats2.getN());
810     }
811     
812     /**
813      * Returns the <i>observed significance level</i>, or 
814      * <i>p-value</i>, associated with a two-sample, two-tailed t-test 
815      * comparing the means of the datasets described by two StatisticalSummary
816      * instances, under the hypothesis of equal subpopulation variances. To
817      * perform a test without the equal variances assumption, use
818      * {@link #tTest(StatisticalSummary, StatisticalSummary)}.
819      * <p>
820      * The number returned is the smallest significance level
821      * at which one can reject the null hypothesis that the two means are
822      * equal in favor of the two-sided alternative that they are different. 
823      * For a one-sided test, divide the returned value by 2.</p>
824      * <p>
825      * See {@link #homoscedasticT(double[], double[])} for the formula used to
826      * compute the t-statistic. The sum of the  sample sizes minus 2 is used as
827      * the degrees of freedom.</p>
828      * <p>
829      * <strong>Usage Note:</strong><br>
830      * The validity of the p-value depends on the assumptions of the parametric
831      * t-test procedure, as discussed 
832      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">here</a>
833      * </p><p>
834      * <strong>Preconditions</strong>: <ul>
835      * <li>The datasets described by the two Univariates must each contain
836      * at least 2 observations.
837      * </li></ul></p>
838      *
839      * @param sampleStats1  StatisticalSummary describing data from the first sample
840      * @param sampleStats2  StatisticalSummary describing data from the second sample
841      * @return p-value for t-test
842      * @throws IllegalArgumentException if the precondition is not met
843      * @throws MathException if an error occurs computing the p-value
844      */
845     public double homoscedasticTTest(StatisticalSummary sampleStats1, 
846             StatisticalSummary sampleStats2)
847     throws IllegalArgumentException, MathException {
848         if ((sampleStats1 == null) || (sampleStats2 == null ||
849                 Math.min(sampleStats1.getN(), sampleStats2.getN()) < 2)) {
850             throw new IllegalArgumentException("insufficient data for t statistic");
851         }
852         return homoscedasticTTest(sampleStats1.getMean(),
853                 sampleStats2.getMean(), sampleStats1.getVariance(),
854                 sampleStats2.getVariance(), (double) sampleStats1.getN(), 
855                 (double) sampleStats2.getN());
856     }
857 
858     /**
859      * Performs a 
860      * <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda353.htm">
861      * two-sided t-test</a> evaluating the null hypothesis that 
862      * <code>sampleStats1</code> and <code>sampleStats2</code> describe
863      * datasets drawn from populations with the same mean, with significance
864      * level <code>alpha</code>.   This test does not assume that the
865      * subpopulation variances are equal.  To perform the test under the equal
866      * variances assumption, use
867      * {@link #homoscedasticTTest(StatisticalSummary, StatisticalSummary)}.
868      * <p>
869      * Returns <code>true</code> iff the null hypothesis that the means are
870      * equal can be rejected with confidence <code>1 - alpha</code>.  To 
871      * perform a 1-sided test, use <code>alpha * 2</code></p>
872      * <p>
873      * See {@link #t(double[], double[])} for the formula used to compute the
874      * t-statistic.  Degrees of freedom are approximated using the
875      * <a href="http://www.itl.nist.gov/div898/handbook/prc/section3/prc31.htm">
876      * Welch-Satterthwaite approximation.</a></p>
877      * <p>
878      * <strong>Examples:</strong><br><ol>
879      * <li>To test the (2-sided) hypothesis <code>mean 1 = mean 2 </code> at
880      * the 95%, use 
881      * <br><code>tTest(sampleStats1, sampleStats2, 0.05) </code>
882      * </li>
883      * <li>To test the (one-sided) hypothesis <code> mean 1 < mean 2 </code>
884      * at the 99% level,  first verify that the measured mean of  
885      * <code>sample 1</code> is less than  the mean of <code>sample 2</code>
886      * and then use 
887      * <br><code>tTest(sampleStats1, sampleStats2, 0.02) </code>
888      * </li></ol></p>
889      * <p>
890      * <strong>Usage Note:</strong><br>
891      * The validity of the test depends on the assumptions of the parametric
892      * t-test procedure, as discussed 
893      * <a href="http://www.basic.nwu.edu/statguidefiles/ttest_unpaired_ass_viol.html">
894      * here</a></p>
895      * <p>
896      * <strong>Preconditions</strong>: <ul>
897      * <li>The datasets described by the two Univariates must each contain
898      * at least 2 observations.
899      * </li>
900      * <li> <code> 0 < alpha < 0.5 </code>
901      * </li></ul></p>
902      *
903      * @param sampleStats1 StatisticalSummary describing sample data values
904      * @param sampleStats2 StatisticalSummary describing sample data values
905      * @param alpha significance level of the test
906      * @return true if the null hypothesis can be rejected with 
907      * confidence 1 - alpha
908      * @throws IllegalArgumentException if the preconditions are not met
909      * @throws MathException if an error occurs performing the test
910      */
911     public boolean tTest(StatisticalSummary sampleStats1,
912             StatisticalSummary sampleStats2, double alpha)
913     throws IllegalArgumentException, MathException {
914         if ((alpha <= 0) || (alpha > 0.5)) {
915             throw new IllegalArgumentException("bad significance level: " + alpha);
916         }
917         return (tTest(sampleStats1, sampleStats2) < alpha);
918     }
919     
920     //----------------------------------------------- Protected methods 
921 
922     /**
923      * Gets a DistributionFactory to use in creating TDistribution instances.
924      * @return a distribution factory.
925      * @deprecated inject TDistribution directly instead of using a factory.
926      */
927     protected DistributionFactory getDistributionFactory() {
928         return DistributionFactory.newInstance();
929     }
930     
931     /**
932      * Computes approximate degrees of freedom for 2-sample t-test.
933      * 
934      * @param v1 first sample variance
935      * @param v2 second sample variance
936      * @param n1 first sample n
937      * @param n2 second sample n
938      * @return approximate degrees of freedom
939      */
940     protected double df(double v1, double v2, double n1, double n2) {
941         return (((v1 / n1) + (v2 / n2)) * ((v1 / n1) + (v2 / n2))) /
942         ((v1 * v1) / (n1 * n1 * (n1 - 1d)) + (v2 * v2) /
943                 (n2 * n2 * (n2 - 1d)));
944     }
945 
946     /**
947      * Computes t test statistic for 1-sample t-test.
948      * 
949      * @param m sample mean
950      * @param mu constant to test against
951      * @param v sample variance
952      * @param n sample n
953      * @return t test statistic
954      */
955     protected double t(double m, double mu, double v, double n) {
956         return (m - mu) / Math.sqrt(v / n);
957     }
958     
959     /**
960      * Computes t test statistic for 2-sample t-test.
961      * <p>
962      * Does not assume that subpopulation variances are equal.</p>
963      * 
964      * @param m1 first sample mean
965      * @param m2 second sample mean
966      * @param v1 first sample variance
967      * @param v2 second sample variance
968      * @param n1 first sample n
969      * @param n2 second sample n
970      * @return t test statistic
971      */
972     protected double t(double m1, double m2,  double v1, double v2, double n1,
973             double n2)  {
974             return (m1 - m2) / Math.sqrt((v1 / n1) + (v2 / n2));
975     }
976     
977     /**
978      * Computes t test statistic for 2-sample t-test under the hypothesis
979      * of equal subpopulation variances.
980      * 
981      * @param m1 first sample mean
982      * @param m2 second sample mean
983      * @param v1 first sample variance
984      * @param v2 second sample variance
985      * @param n1 first sample n
986      * @param n2 second sample n
987      * @return t test statistic
988      */
989     protected double homoscedasticT(double m1, double m2,  double v1,
990             double v2, double n1, double n2)  {
991             double pooledVariance = ((n1  - 1) * v1 + (n2 -1) * v2 ) / (n1 + n2 - 2); 
992             return (m1 - m2) / Math.sqrt(pooledVariance * (1d / n1 + 1d / n2));
993     }
994     
995     /**
996      * Computes p-value for 2-sided, 1-sample t-test.
997      * 
998      * @param m sample mean
999      * @param mu constant to test against
1000      * @param v sample variance
1001      * @param n sample n
1002      * @return p-value
1003      * @throws MathException if an error occurs computing the p-value
1004      */
1005     protected double tTest(double m, double mu, double v, double n)
1006     throws MathException {
1007         double t = Math.abs(t(m, mu, v, n));
1008         distribution.setDegreesOfFreedom(n - 1);
1009         return 1.0 - distribution.cumulativeProbability(-t, t);
1010     }
1011 
1012     /**
1013      * Computes p-value for 2-sided, 2-sample t-test.
1014      * <p>
1015      * Does not assume subpopulation variances are equal. Degrees of freedom
1016      * are estimated from the data.</p>
1017      * 
1018      * @param m1 first sample mean
1019      * @param m2 second sample mean
1020      * @param v1 first sample variance
1021      * @param v2 second sample variance
1022      * @param n1 first sample n
1023      * @param n2 second sample n
1024      * @return p-value
1025      * @throws MathException if an error occurs computing the p-value
1026      */
1027     protected double tTest(double m1, double m2, double v1, double v2, 
1028             double n1, double n2)
1029     throws MathException {
1030         double t = Math.abs(t(m1, m2, v1, v2, n1, n2));
1031         double degreesOfFreedom = 0;
1032         degreesOfFreedom = df(v1, v2, n1, n2);
1033         distribution.setDegreesOfFreedom(degreesOfFreedom);
1034         return 1.0 - distribution.cumulativeProbability(-t, t);
1035     }
1036     
1037     /**
1038      * Computes p-value for 2-sided, 2-sample t-test, under the assumption
1039      * of equal subpopulation variances.
1040      * <p>
1041      * The sum of the sample sizes minus 2 is used as degrees of freedom.</p>
1042      * 
1043      * @param m1 first sample mean
1044      * @param m2 second sample mean
1045      * @param v1 first sample variance
1046      * @param v2 second sample variance
1047      * @param n1 first sample n
1048      * @param n2 second sample n
1049      * @return p-value
1050      * @throws MathException if an error occurs computing the p-value
1051      */
1052     protected double homoscedasticTTest(double m1, double m2, double v1,
1053             double v2, double n1, double n2)
1054     throws MathException {
1055         double t = Math.abs(homoscedasticT(m1, m2, v1, v2, n1, n2));
1056         double degreesOfFreedom = (double) (n1 + n2 - 2);
1057         distribution.setDegreesOfFreedom(degreesOfFreedom);
1058         return 1.0 - distribution.cumulativeProbability(-t, t);
1059     }
1060     
1061     /**
1062      * Modify the distribution used to compute inference statistics.
1063      * @param value the new distribution
1064      * @since 1.2
1065      */
1066     public void setDistribution(TDistribution value) {
1067         distribution = value;
1068     }
1069 }