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); } } }