gov.sandia.cognition.statistics.method.FriedmanConfidence 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: FriedmanConfidence.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright May 3, 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.collection.CollectionUtil;
import gov.sandia.cognition.math.UnivariateStatisticsUtil;
import gov.sandia.cognition.statistics.distribution.ChiSquareDistribution;
import gov.sandia.cognition.statistics.distribution.SnedecorFDistribution;
import gov.sandia.cognition.util.AbstractCloneableSerializable;
import gov.sandia.cognition.util.ObjectUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/**
* The Friedman test determines if the rankings associated with various
* treatments are equal. This is a nonparametric alternative to ANOVA.
* @author Kevin R. Dixon
* @since 3.1
*/
@ConfidenceTestAssumptions(
name="Friedman's test",
alsoKnownAs="",
description={
"Friedman's test determines if the rankings associated with various treatments are equal.",
"This is a nonparametric rank-based alternative to ANOVA, a multiple comparison generalization similar to the difference between Student's t-test and Wilcoxon rank-signed test.",
"Friedman's test tends to have as much power as ANOVA, but without ANOVA's parameteric assumptions"
},
assumptions={
"All data came from same distribution, without considering treatment effects.",
"Measurements are independent and equivalent within a treatment.",
"All observations are independent."
},
nullHypothesis="The treatments have no effect on experimental observations.",
dataPaired=true,
dataSameSize=true,
distribution=SnedecorFDistribution.class,
reference={
@PublicationReference(
author="Janez Demsar",
title="Statistical Comparisons of Classifiers over Multiple Data Sets",
type=PublicationType.Journal,
publication="Journal of Machine Learning Research",
year=2006,
url="http://www.jmlr.org/papers/volume7/demsar06a/demsar06a.pdf"
)
,
@PublicationReference(
author="Wikipedia",
title="Friedman test",
type=PublicationType.WebPage,
year=2011,
url="http://en.wikipedia.org/wiki/Friedman_test",
notes="Our test uses the tighter F-statistic rather than the original chi-square statistic"
)
}
)
public class FriedmanConfidence
extends AbstractCloneableSerializable
implements BlockExperimentComparison
{
/**
* Default instance.
*/
public static final FriedmanConfidence INSTANCE =
new FriedmanConfidence();
/**
* Creates a new instance of FriedmanConfidence
*/
public FriedmanConfidence()
{
}
@Override
@SuppressWarnings("unchecked")
public FriedmanConfidence.Statistic evaluateNullHypothesis(
final Collection extends Number> data1,
final Collection extends Number> data2)
{
return evaluateNullHypothesis( Arrays.asList( data1, data2 ) );
}
@Override
public FriedmanConfidence.Statistic evaluateNullHypothesis(
final Collection extends Collection extends Number>> data )
{
// There are "K" treatments
int K = data.size();
// There are "N" subjects for each treatment
int N = CollectionUtil.getFirst(data).size();
return new FriedmanConfidence.Statistic( K, N, computeTreatmentRankMeans(data) );
}
/**
* Computes the mean rank of the treatments
* @param data
* Collection of treatments, where each treatment must have the same number
* of subjects in each treatment
* @return
* An mean rank for each of the treatments
*/
public static ArrayList computeTreatmentRankMeans(
final Collection extends Collection extends Number>> data )
{
// There are "K" treatments
int K = data.size();
// There are "N" subjects for each treatment
int N = CollectionUtil.getFirst(data).size();
// Thus, there are "N*K" observations in the experiment
// Go through and put everything into an ArrayList, but transposed
ArrayList> dataTranspose =
new ArrayList>( N );
for( int n = 0; n < N; n++ )
{
// This is for each subject
dataTranspose.add( new ArrayList( K ) );
}
ArrayList> allRanks =
new ArrayList>( K );
for( Collection extends Number> treatment : data )
{
if( treatment.size() != N )
{
throw new IllegalArgumentException(
"All treatments must be the same size!" );
}
int n = 0;
for( Number observation : treatment )
{
dataTranspose.get(n).add( observation.doubleValue() );
n++;
}
allRanks.add( new ArrayList( N ) );
}
// Now, go through each subject and compute the ranks for each treatment
int n = 0;
for( Collection subjects : dataTranspose )
{
// For the nth subject, how did the treatments do?
double[] treatmentRanks =
WilcoxonSignedRankConfidence.ranks(subjects);
for( int k = 0; k < K; k++ )
{
// The allRanks transposes things back so that we can easily
// compute the mean and variance for each treatment
allRanks.get(k).add( treatmentRanks[k] );
}
n++;
}
ArrayList treatmentRankMeans = new ArrayList( K );
for( ArrayList treatmentRanks : allRanks )
{
double treatmentRankMean =
UnivariateStatisticsUtil.computeMean(treatmentRanks);
treatmentRankMeans.add( treatmentRankMean );
}
return treatmentRankMeans;
}
/**
* Confidence statistic associated with the Friedman test using the tighter
* F-statistic.
*/
public static class Statistic
extends AbstractConfidenceStatistic
{
/**
* Number of treatments in the experiment
*/
private int treatmentCount;
/**
* Number of subjects in the experiment
*/
private int subjectCount;
/**
* Value of the chi-square error for the treatment ranks
*/
private double chiSquare;
/**
* Degrees of freedom of the chi-square
*/
private double degreesOfFreedom;
/**
* Null-hypothesis using the chi-square statistic
*/
private double chiSquareNullHypothesisProbability;
/**
* F-statistic for the corrected chi-square using Snedecor's F distribution
*/
private double F;
/**
* Mean rank for each treatment
*/
private ArrayList treatmentRankMeans;
/**
* Creates a new instance of Statistic
* @param treatmentCount
* Number of treatments in the experiment
* @param subjectCount
* Number of subjects in the experiment
* @param treatmentRankMeans
* Mean rank for each treatment
*/
public Statistic(
final int treatmentCount,
final int subjectCount,
final ArrayList treatmentRankMeans )
{
this( treatmentCount, subjectCount, treatmentRankMeans,
computeChiSquare(treatmentCount, subjectCount,treatmentRankMeans) );
}
/**
* Creates a new instance of Statistic
* @param treatmentCount
* Number of treatments in the experiment
* @param subjectCount
* Number of subjects in the experiment
* @param treatmentRankMeans
* Mean rank for each treatment
* @param chiSquare
* Value of the chi-square error for the treatment ranks
*/
protected Statistic(
final int treatmentCount,
final int subjectCount,
final ArrayList treatmentRankMeans,
final double chiSquare )
{
this( treatmentCount, subjectCount, treatmentRankMeans, chiSquare,
((subjectCount-1) * chiSquare) / (subjectCount*(treatmentCount-1) - chiSquare));
}
/**
* Creates a new instance of Statistic
* @param treatmentCount
* Number of treatments in the experiment
* @param subjectCount
* Number of subjects in the experiment
* @param treatmentRankMeans
* Mean rank for each treatment
* @param chiSquare
* Value of the chi-square error for the treatment ranks
* @param F
* F-statistic for the corrected chi-square using Snedecor's F distribution
*/
protected Statistic(
final int treatmentCount,
final int subjectCount,
final ArrayList treatmentRankMeans,
final double chiSquare,
final double F )
{
super(1.0 - SnedecorFDistribution.CDF.evaluate(
F, treatmentCount-1.0, (treatmentCount-1.0)*(subjectCount-1.0) ));
this.treatmentCount = treatmentCount;
this.subjectCount = subjectCount;
this.treatmentRankMeans = treatmentRankMeans;
this.chiSquare = chiSquare;
this.degreesOfFreedom = treatmentCount-1.0;
this.chiSquareNullHypothesisProbability =
1.0 - ChiSquareDistribution.CDF.evaluate(chiSquare, treatmentCount-1.0 );
this.F = F;
}
/**
* Computes the chi-square error for the rank means
* @param treatmentCount
* Number of treatments in the experiment
* @param subjectCount
* Number of subjects in the experiment
* @param treatmentRankMeans
* Mean rank for each treatment
* @return
* Value of the chi-square error for the treatment ranks
*/
protected static double computeChiSquare(
final int treatmentCount,
final int subjectCount,
final ArrayList treatmentRankMeans )
{
final double rankMean = UnivariateStatisticsUtil.computeMean(treatmentRankMeans);
final double treatmentSumSquared = UnivariateStatisticsUtil.computeSumSquaredDifference(treatmentRankMeans, 0.0);
final double delta = treatmentSumSquared - treatmentCount*rankMean*rankMean;
final double chiSquare = 12.0*subjectCount/(treatmentCount*(treatmentCount+1.0)) * delta;
return chiSquare;
}
@Override
public FriedmanConfidence.Statistic clone()
{
Statistic clone = (Statistic) super.clone();
clone.treatmentRankMeans = ObjectUtil.cloneSmartElementsAsArrayList(
this.getTreatmentRankMeans() );
return clone;
}
/**
* Getter for treatmentCount
* @return
* Number of treatments in the experiment
*/
public int getTreatmentCount()
{
return this.treatmentCount;
}
/**
* Getter for subjectCount
* @return
* Number of subjects in the experiment
*/
public int getSubjectCount()
{
return this.subjectCount;
}
/**
* Getter for chiSquare
* @return
* Value of the chi-square error for the treatment ranks
*/
public double getChiSquare()
{
return this.chiSquare;
}
/**
* Getter for treatmentRankMeans
* @return
* Mean rank for each treatment
*/
public ArrayList getTreatmentRankMeans()
{
return this.treatmentRankMeans;
}
/**
* Getter for degreesOfFreedom
* @return
* Degrees of freedom of the chi-square
*/
public double getDegreesOfFreedom()
{
return this.degreesOfFreedom;
}
/**
* Getter for chiSquareNullHypothesisProbability
* @return
* Null-hypothesis using the chi-square statistic
*/
public double getChiSquareNullHypothesisProbability()
{
return this.chiSquareNullHypothesisProbability;
}
/**
* Getter for F.
* @return
* F-statistic for the corrected chi-square using Snedecor's F distribution
*/
public double getF()
{
return this.F;
}
@Override
public double getTestStatistic()
{
return this.getF();
}
}
}