gov.sandia.cognition.statistics.method.TukeyKramerConfidence Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cognitive-foundry Show documentation
Show all versions of cognitive-foundry Show documentation
A single jar with all the Cognitive Foundry components.
/*
* File: TukeyKramerConfidence.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright May 16, 2011, Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the U.S. Government.
* Export of this program may require a license from the United States
* Government. See CopyrightHistory.txt for complete details.
*
*/
package gov.sandia.cognition.statistics.method;
import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.math.UnivariateStatisticsUtil;
import gov.sandia.cognition.math.matrix.Matrix;
import gov.sandia.cognition.math.matrix.MatrixFactory;
import gov.sandia.cognition.statistics.distribution.StudentizedRangeDistribution;
import gov.sandia.cognition.util.ObjectUtil;
import gov.sandia.cognition.util.Pair;
import java.util.ArrayList;
import java.util.Collection;
/**
* Tukey-Kramer test is the multiple-comparison generalization of the unpaired
* Student's t-test when conducting multiple comparisons. The t-test and
* Tukey's Range test are coincident when a single comparison is made.
* Tukey's Range test is typically used as the post-hoc analysis technique
* after detecting a difference using a 1-way ANOVA. This class implements
* Kramer's generalization to unequal subjects in different treatments.
* @author Kevin R. Dixon
* @since 3.1
*/
@ConfidenceTestAssumptions(
name="Tukey-Kramer Range test",
alsoKnownAs={
"Tukey's Range test",
"Tukey's Honestly Significant Difference test",
"Tukey's HSD test"
},
description={
"Tukey's test determines which treatment is statistically different from a multiple comparison.",
"Tukey's test is a generalization of the paired Student's t-test for multiple comparisons using a population-correction factor."
},
assumptions={
"All data came from same distribution, without considering treatment effects.",
"The observations have equal variance.",
"Measurements are independent and equivalent within a treatment.",
"All observations are independent."
},
nullHypothesis="Each treatment has no effect on the mean outcome of the subjects",
dataPaired=false,
dataSameSize=false,
distribution=StudentizedRangeDistribution.class,
reference={
@PublicationReference(
author="Wikipedia",
title="Tukey's range test",
type=PublicationType.WebPage,
year=2011,
url="http://en.wikipedia.org/wiki/Tukey's_range_test"
)
}
)
public class TukeyKramerConfidence
extends AbstractMultipleHypothesisComparison, TukeyKramerConfidence.Statistic>
{
/**
* Creates a new instance of TukeyKramerConfidence
*/
public TukeyKramerConfidence()
{
super();
}
@Override
public TukeyKramerConfidence clone()
{
return (TukeyKramerConfidence) super.clone();
}
@Override
public TukeyKramerConfidence.Statistic evaluateNullHypotheses(
Collection extends Collection extends Number>> data,
double uncompensatedAlpha)
{
// There are "K" treatments
final int K = data.size();
// Each treatment can have a different number of subjects
ArrayList subjectCounts = new ArrayList( K );
ArrayList treatmentMeans = new ArrayList( K );
double treatmentVariancesSum = 0.0;
// There are "N" total subjects
int N = 0;
for( Collection extends Number> treatment : data )
{
final int Ni = treatment.size();
N += Ni;
subjectCounts.add( Ni );
Pair meanAndVariance = UnivariateStatisticsUtil.computeMeanAndVariance(treatment);
treatmentMeans.add( meanAndVariance.getFirst() );
treatmentVariancesSum += meanAndVariance.getSecond() * (Ni-1);
}
final double meanSquaredResiduals = treatmentVariancesSum / (N-K);
return new TukeyKramerConfidence.Statistic(
uncompensatedAlpha, subjectCounts, treatmentMeans, meanSquaredResiduals );
}
/**
* Statistic from Tukey-Kramer's multiple comparison test
*/
public static class Statistic
extends AbstractMultipleHypothesisComparison.Statistic
{
/**
* Number of subjects in each treatment
*/
protected ArrayList subjectCounts;
/**
* Mean for each treatment
*/
protected ArrayList treatmentMeans;
/**
* Mean-squared difference over all subjects
*/
protected double meanSquaredResiduals;
/**
* Gets the standard errors in the experiment
*/
protected Matrix standardErrors;
/**
* Creates a new instance of Statistic
* @param uncompensatedAlpha
* Uncompensated alpha (p-value threshold) for the multiple comparison
* test
* @param subjectCounts
* Number of subjects in each treatment
* @param treatmentMeans
* Mean for each treatment
* @param meanSquaredResiduals
* Mean-squared difference over all subjects
*/
public Statistic(
final double uncompensatedAlpha,
final ArrayList subjectCounts,
final ArrayList treatmentMeans,
final double meanSquaredResiduals )
{
this.treatmentCount = treatmentMeans.size();
this.uncompensatedAlpha = uncompensatedAlpha;
this.subjectCounts = subjectCounts;
this.treatmentMeans = treatmentMeans;
this.meanSquaredResiduals = meanSquaredResiduals;
this.testStatistics = this.computeTestStatistics(
subjectCounts, treatmentMeans, meanSquaredResiduals);
this.nullHypothesisProbabilities = this.computeNullHypothesisProbabilities(
subjectCounts, this.testStatistics );
}
/**
* Computes the test statistic for all treatments
* @param subjectCounts
* Number of subjects in each treatment
* @param treatmentMeans
* Mean for each treatment
* @param meanSquaredResiduals
* Mean-squared difference over all subjects
* @return
* Test statistics, where the (i,j) element compares treatment "i" to
* treatment "j", the statistic is symmetric
*/
public Matrix computeTestStatistics(
final ArrayList subjectCounts,
final ArrayList treatmentMeans,
final double meanSquaredResiduals )
{
int K = treatmentMeans.size();
Matrix Z = MatrixFactory.getDefault().createMatrix(K,K);
this.standardErrors = MatrixFactory.getDefault().createMatrix(K, K);
for( int i = 0; i < K; i++ )
{
final double yi = treatmentMeans.get(i);
final int ni = subjectCounts.get(i);
for( int j = i+1; j < K; j++ )
{
final int nj = subjectCounts.get(j);
final double yj = treatmentMeans.get(j);
double standardError =
Math.sqrt( meanSquaredResiduals * 0.5 * ((1.0/ni) + (1.0/nj)));
final double zij = Math.abs(yi-yj) / standardError;
Z.setElement(i, j, zij);
Z.setElement(j, i, zij);
this.standardErrors.setElement(i, j, standardError);
this.standardErrors.setElement(j, i, standardError);
}
}
return Z;
}
/**
* Computes null-hypothesis probability for the (i,j) treatment comparison
* @param subjectCounts
* Number of subjects in the experiment
* @param Z
* Test statistic for the (i,j) treatment comparison
* @return
* Null-hypothesis probability for the (i,j) treatment comparison
*/
protected Matrix computeNullHypothesisProbabilities(
final ArrayList subjectCounts,
final Matrix Z )
{
final int K = Z.getNumRows();
final double N = UnivariateStatisticsUtil.computeSum(subjectCounts);
Matrix P = MatrixFactory.getDefault().createMatrix(K, K);
StudentizedRangeDistribution.CDF cdf =
new StudentizedRangeDistribution.CDF( K, N-K );
for( int i = 0; i < K; i++ )
{
// A classifier is equal to itself.
P.setElement(i, i, 1.0);
for( int j = i+1; j < K; j++ )
{
// The difference is symmetric
double zij = Z.getElement(i,j);
double pij = 1.0-cdf.evaluate( zij );
P.setElement(i, j, pij);
P.setElement(j, i, pij);
}
}
return P;
}
@Override
public Statistic clone()
{
Statistic clone = (Statistic) super.clone();
clone.treatmentMeans = ObjectUtil.cloneSmartElementsAsArrayList(
this.getTreatmentMeans() );
clone.subjectCounts = ObjectUtil.cloneSmartElementsAsArrayList(
this.getSubjectCounts());
return clone;
}
/**
* Getter for subjectCounts
* @return
* Number of subjects in the experiment
*/
public ArrayList getSubjectCounts()
{
return this.subjectCounts;
}
/**
* Getter for treatmentMeans
* @return
* Mean for each treatment
*/
public ArrayList getTreatmentMeans()
{
return this.treatmentMeans;
}
/**
* Getter for meanSquaredResiduals
* @return
* Mean-squared difference over all subjects
*/
public double getMeanSquaredResiduals()
{
return this.meanSquaredResiduals;
}
@Override
public boolean acceptNullHypothesis(
final int i,
final int j)
{
return this.getNullHypothesisProbability(i, j) >= this.getUncompensatedAlpha();
}
/**
* Getter for standardErrors
* @return
* Gets the standard errors in the experiment
*/
public Matrix getStandardErrors()
{
return this.standardErrors;
}
}
}