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