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 * <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 * <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 * <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 * <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 }