using BotSharp.Algorithm.HiddenMarkovModel.MathUtils.Distribution;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BotSharp.Algorithm.HiddenMarkovModel.MathUtils.Statistics
{
///
/// testing many pairs of groups is called multiple comparisons
///
/// In multiple comparisons, each pair of groups are tested to check whether the population mean of their classes are the same (H_0) or different (H_A).
/// T statistic is used to model the sample mean difference distribution of pairwise groups
///
public class MultipleComparisons
{
///
/// The Bonferroni correction suggests that a more stringent significance level is more appropriate for mulitiple comparison tests than ANOVA.
///
/// This adjusts the significance level by the number comparisons being considered
///
///
/// number of groups
///
public static double BonferroniCorrection(double signifiance_level, int k)
{
int K = k * (k - 1) / 2; // number of comparisons
return signifiance_level / K;
}
///
/// Return a matrix of reject H_0, for which rejectH0Matrix[i][j] = true if the pairwise comparison provide enough evidence that group[i] and group[j] does not have the same mean
///
/// Hypotheses for a pair of groups, group[i] and group[j]:
/// H_0 : mu_i = mu_j
/// H_A : mu_i != mu_j
///
/// sampled groupped by classes
/// significance level for the test
/// RejectH0 matrix: rejctH0Matrix[i][j] = true if the test provide enough evidence that group[i] and group[j] does not have the same mean
public static bool[][] RejectH0(double[] sample, int[] grpCat, double significance_level = 0.05)
{
ANOVA anova_output;
ANOVA.RunANOVA(sample, grpCat, out anova_output, significance_level);
Dictionary> groupedSample = new Dictionary>();
for (int i = 0; i < sample.Length; ++i)
{
int grpId = grpCat[i];
double sampleVal = sample[i];
List grp = null;
if (groupedSample.ContainsKey(grpId))
{
grp = groupedSample[grpId];
}
else
{
grp = new List();
groupedSample[grpId] = grp;
}
grp.Add(sampleVal);
}
int k = groupedSample.Count; // number of groups
double alpha_adj = BonferroniCorrection(significance_level, k);
bool[][] rejectH0Matrix = new bool[k][];
for (int i = 0; i < k; ++k)
{
rejectH0Matrix[i] = new bool[k];
}
List groupIdList = groupedSample.Keys.ToList();
for (int i = 0; i < k - 1; ++i)
{
List group1 = groupedSample[groupIdList[i]];
for (int j = i + 1; j < k; ++j)
{
List group2 = groupedSample[groupIdList[j]];
double pValue = PairwiseCompare(group1, group2, anova_output);
bool reject_H0 = pValue < alpha_adj;
rejectH0Matrix[i][j] = reject_H0;
rejectH0Matrix[j][i] = reject_H0;
}
}
return rejectH0Matrix;
}
///
/// Pairwise comparison of group1 and group2
///
/// random sample from class 1
/// random sample from class 2
/// parameters obtained after ANOVA
/// p-value = P(observed or more extreme values | H_0 is true)
public static double PairwiseCompare(List group1, List group2, ANOVA anova)
{
double x_bar1 = Mean.GetMean(group1);
double x_bar2 = Mean.GetMean(group2);
int n1 = group1.Count;
int n2 = group2.Count;
int null_value = 0;
double t = GetTStatistic(x_bar1, x_bar2, n1, n2, null_value, anova.MSE);
double pValue = GetPValue(t, anova.dfE);
return pValue;
}
///
/// Return the t statistic
///
/// point estimate of sample mean in class 1
/// point estimate of sample mean in class 2
/// size of random sample from class 1
/// size of random sample from class 2
/// null value from H_0
/// mean squares error obtained after ANOVA
/// t statistic
private static double GetTStatistic(double x_bar1, double x_bar2, double n1, double n2, double null_value, double MSE)
{
return ((x_bar1 - x_bar2) - null_value) / System.Math.Sqrt(MSE / n1 + MSE / n2);
}
///
/// Return the p-value from the Student's distribution
///
///
/// degrees of freedom error obtained after ANOVA
/// p-value = P(observed or more extreme values | H_0 is true)
private static double GetPValue(double t, int dfE)
{
return StudentT.GetPercentile(System.Math.Abs(t), dfE);
}
}
}