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