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