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