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 }