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