using BotSharp.Algorithm.HiddenMarkovModel.MathUtils.Distribution; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BotSharp.Algorithm.HiddenMarkovModel.MathUtils.Statistics { /// /// Hypothesis testing framework: /// 1. Start with a null hypothesis (null_value) that represents the status quo (i.e. common believe). /// 2. Create an alternative hypothesis (H_A) that represents the research questions, i.e. what is being tested for. /// 3. Conduct a hypothesis test under the assumption that the null hypothesis is true, either via simulation or theoretical methods (i.e. methods that rely on Central Limit Theorem) /// 4. If thte test results suggest that the data do not provide convincing evidence for the alternative hypothesis, we stick with the null hypothesis. If the do, then we reject /// the null hyptothesis in favor of the alternative /// /// p-value = P(observed or more extreme outcome | null_value true) /// p-value is the probability of observing data at least as favorable to the alternative hypothesis as our current data set, if the null hyptothesis was true /// 1. If the p-value is low (lower than the significance level, alpha, which is usually 5%) we say the it would be very unlikely to observe the data if the null hypothesis were true, and hence reject H_0 /// 2. If the p-value is high (higher than alpha) we say that is likely to observe the data even if the null hypothesis were true, and hence do not reject H_0 /// /// Steps for Hypothesis testing for a single mean: /// 1. Set the hypotheses: H_0: mu = null value /// H_A: mu < or > or != null value /// 2. Calculate the point estimate (usually the sample mean) /// 3. Check CLT (i.e., Central Limit Theorem) condictions: /// I. Independence: Sampled observations must be independent (random sample/assignment & if sampling without replacement, n < 10% of population) /// II. Sample size/skew: n>=30, larger if the population distribution is very skewed /// 4. Draw sample distribution, shade p-value, calculate test statistics Z = (point_estimate - null_value) / SE /// 5. Make a decision, and interpret it in context of the research question: /// if p-value < alpha, reject H_0; the data provide convincing evidence for H_A /// if p-value > alpha, do not reject H_0; the data do not provide convincing evidence for H_A /// /// There are two types of decision errors in hypothesis testing: /// Type I error is rejecting H_0 when H_0 is true /// Type II error is failing to reject H_0 when H_A is true /// (Usually from a social point of view, Type I error is the worst error as it means rejecting something that is true and status quo, but this depends on scenario and personal preferences) /// By definition: /// P(Type I error | H_0 is true) = alpha, where alpha is the significance_level => prefer small significance level, increasing significance level increases the Type I error rate. /// On the other hand, decreasing significance_level increases the Type II error /// /// The power of a test is the probability of correctly reject H_0, the probability of doing so is (1-beta), where beta = P(Type II error | H_A is true) /// beta depends on the effect size, which is the difference between point estimate and the null_value => if the effect size is large, then beta is small /// /// Real differences between the point estimate and null_value are easier to detect with larger sample. However, very large samples will result in a statistical significance even /// for tiny differences between sample mean (i.e. point estimate) and the null value (the difference refers to the effect size), even when the difference is not practically significant. /// /// Note that in case the sample size is smaller than 30, the CLT does not hold and Student's t distribution should be used for the population statistics instead of normal distribution /// public class HypothesisTesting { /// /// Two-sided or one-sided test for a single mean /// /// A two-sided hypothesis with threshold of alpha (i.e. significance level) is equivalent to a confidence interval of CL (i.e. confidence level) = 1 - alpha /// A one-sided hypothesis with threshold of alpha is equivalent to a confidence interval of CL = 1 - alpha * 2 /// /// If H_0 is rejected, a confidence interval that agrees with the result of the hypothesis test should not include the null_value /// If H_0 is failed to be rejected, a confidence interval that agrees with the result of the hypothesis should include the null_value /// /// value sample for the varabiel /// The null hypothesis value that true population mean, mu = null_value /// /// True if the test is one-sided /// True if the null hypothesis H_0 : (mu == null_value) is rejected public bool RejectH0_ByCI(double[] values, double null_value, double significance_level = 0.05, bool one_sided = false) { double confidence_level = 1 - significance_level * (one_sided ? 2 : 1); double[] confidence_interval = ConfidenceInterval.GetConfidenceInterval(values, confidence_level); return null_value < confidence_interval[0] || null_value > confidence_interval[1]; } /// /// Two-sided or one-sided test for a single mean /// /// Given that: /// H_0 : mu = null_value /// H_A : mu != null_value /// /// By Central Limit Theorem: /// sample_mean ~ N(mu, SE) /// /// p-value = (sample_mean is at least ||null_value-point_estimate|| away from the null_value) | mu = null_value) /// if(p-value < significance_level) reject H_0 /// /// /// /// /// True if the test is one_sided /// public static bool RejectH0(double[] sample, double null_value, out double pValue, double significance_level = 0.05, bool one_sided = false, bool useStudentT = false) { double pointEstimate = Mean.GetMean(sample); double standardError = StandardError.GetStandardError(sample); //SE is the estimated standard deviation of the true population mean, mu double test_statistic = System.Math.Abs(pointEstimate - null_value) / standardError; //This assumes that H_0 is true, that is, the true population mean, mu = null_value double percentile = 0; if (sample.Length < 30 || useStudentT) //if sample size is smaller than 30, then CLT for population statistics such as sample mean no longer holds and Student's t distribution should be used in place of the normal distribution { percentile = StudentT.GetPercentile(test_statistic, sample.Length - 1); } else { percentile = Gaussian.GetPercentile(test_statistic); } pValue = pValue = (1 - percentile) * (one_sided ? 1 : 2); return pValue < significance_level; } /// /// Two-sided or one-sided test for a single statistic /// /// Given that: /// H_0 : mu = null_value /// H_A : mu != null_value /// /// By Central Limit Theorem: /// sample_mean ~ N(mu, SE) /// /// p-value = (sample_mean is at least ||null_value-point_estimate|| away from the null_value) | mu = null_value) /// if(p-value < significance_level) reject H_0 /// /// point estimate of the population statistics (e.g., sample mean, sample median, etc.) /// /// standard error of the population statistics /// /// /// public static bool RejectH0(double point_estimate, double null_value, double SE, int sampleSize, out double pValue, double significance_level = 0.05, bool one_sided = false, bool useStudentT = false) { double test_statistic = System.Math.Abs(point_estimate - null_value) / SE; //This assumes that H_0 is true, that is, the true population mean, mu = null_value double percentile = 0; if (sampleSize < 30 || useStudentT) //if sample size is smaller than 30, then CLT for population statistics such as sample mean no longer holds and Student's t distribution should be used in place of the normal distribution { percentile = StudentT.GetPercentile(test_statistic, sampleSize - 1); } else { percentile = Gaussian.GetPercentile(test_statistic); } pValue = (1 - percentile) * (one_sided ? 1 : 2); return pValue < significance_level; } /// /// Two-sided test for whether statitics of two variables are equal in the true population, var1 and var2 are independent /// /// Hypotheses are: /// H_0: mu_var1 = mu_var2 /// H_1: mu_var1 != mu_var2 /// /// The hypotheses can be written as /// H_0: mu_var1 - mu_var2 = 0 /// H_1: mu_var1 - mu_var2 != 0 /// /// By Central Limt Theorem: /// sample_mean_var1 - sample_mean_var2 ~ N(0, SE), where null_value = 0 and SE is the standard error of the sampling distribution /// /// value sample for variable 1 /// value sample for variable 2 /// /// public bool RejectH0_ByCI(double[] sample_for_var1, double[] sample_for_var2, double significance_level = 0.05, bool one_sided = false) { double confidence_level = 1 - significance_level * (one_sided ? 2 : 1); double[] confidence_interval = ConfidenceInterval.GetConfidenceIntervalForDiff(sample_for_var1, sample_for_var2, confidence_level); double null_value = 0; return null_value < confidence_interval[0] || null_value > confidence_interval[1]; } /// /// Two-sided or one-sided test for whether statitics of two variables are equal in the true population, var1 and var2 are paired and dependent /// /// Hypotheses are: /// H_0: mu_var1 = mu_var2 /// H_1: mu_var1 != mu_var2 /// /// The hypotheses can be written as /// H_0: mu_var1 - mu_var2 = 0 /// H_1: mu_var1 - mu_var2 != 0 /// /// By Central Limt Theorem: /// sample_mean_var1 - sample_mean_var2 ~ N(0, SE), where null_value = 0 and SE is the standard error of the sampling distribution /// /// a random sample consisting data paired together, var1 and var2, var1 and var2 are not independent /// True if the test is one-sided /// /// public bool RejectH0_PairedData_ByCI(Tuple[] sample_for_paired_data, double significance_level = 0.05, bool one_sided = false) { int sample_size = sample_for_paired_data.Length; double[] diff = new double[sample_size]; for (int i = 0; i < sample_size; ++i) { diff[i] = sample_for_paired_data[i].Item1 - sample_for_paired_data[i].Item2; } double confidence_level = 1 - significance_level * (one_sided ? 2 : 1); double[] confidence_interval = ConfidenceInterval.GetConfidenceInterval(diff, confidence_level); double null_value = 0; return null_value < confidence_interval[0] || null_value > confidence_interval[1]; } /// /// Two-sided or one-sided test for whether statitics of two variables are equal in the true population, var1 and var2 are independent /// /// Hypotheses are: /// H_0: mu_var1 = mu_var2 /// H_1: mu_var1 != mu_var2 /// /// The hypotheses can be written as /// H_0: mu_var1 - mu_var2 = 0 /// H_1: mu_var1 - mu_var2 != 0 /// /// By Central Limt Theorem: /// sample_mean_var1 - sample_mean_var2 ~ N(0, SE), where null_value = 0 and SE is the standard error of the sampling distribution /// /// p-value = (sample_mean is at least ||null_value-point_estimate|| away from the null_value) | mu = null_value) /// /// value sample for variable 1 /// value sample for variable 2 /// True if the test is one-sided /// /// public bool RejectH0(double[] sample_for_var1, double[] sample_for_var2, out double pValue, double significance_level = 0.05, bool one_sided = false, bool useStudentT = false) { double pointEstimate = Mean.GetMean(sample_for_var1) - Mean.GetMean(sample_for_var2); double null_value = 0; double SE = StandardError.GetStandardError(sample_for_var1, sample_for_var2); double test_statistic = System.Math.Abs(pointEstimate - null_value) / SE; double percentile = 0; if (sample_for_var1.Length < 30 || sample_for_var2.Length < 30 || useStudentT) //if sample size is smaller than 30, then CLT for population statistics such as sample mean no longer holds and Student's t distribution should be used in place of the normal distribution { int df = System.Math.Min(sample_for_var1.Length - 1, sample_for_var2.Length - 1); percentile = StudentT.GetPercentile(test_statistic, df); } else { percentile = Gaussian.GetPercentile(test_statistic); } pValue = (1 - percentile) * (one_sided ? 1 : 2); return pValue < significance_level; } /// /// Two-sided or one-sided test for whether statitics of two variables are equal in the true population, var1 and var2 are paired and dependent /// /// Hypotheses are: /// H_0: mu_var1 = mu_var2 /// H_1: mu_var1 != mu_var2 /// /// The hypotheses can be written as /// H_0: mu_var1 - mu_var2 = 0 /// H_1: mu_var1 - mu_var2 != 0 /// /// By Central Limt Theorem: /// sample_mean_var1 - sample_mean_var2 ~ N(0, SE), where null_value = 0 and SE is the standard error of the sampling distribution /// /// p-value = (sample_mean is at least ||null_value-point_estimate|| away from the null_value) | mu = null_value) /// /// a random sample consisting data paired together, var1 and var2, var1 and var2 are not independent /// True if the test is one-sided /// /// public bool RejectH0_PairedData(Tuple[] sample_for_paired_data, out double pValue, double significance_level = 0.05, bool one_sided = false, bool useStudentT = false) { int sample_size = sample_for_paired_data.Length; double[] diff = new double[sample_size]; for (int i = 0; i < sample_size; ++i) { diff[i] = sample_for_paired_data[i].Item1 - sample_for_paired_data[i].Item2; } double point_estimate = Mean.GetMean(diff); double null_value = 0; double SE = StandardError.GetStandardError(diff); double test_statistic = System.Math.Abs(point_estimate - null_value) / SE; double percentile = 0; if (sample_for_paired_data.Length < 30 || useStudentT) //if sample size is smaller than 30, then CLT for population statistics such as sample mean no longer holds and Student's t distribution should be used in place of the normal distribution { percentile = StudentT.GetPercentile(test_statistic, sample_for_paired_data.Length - 1); } else { percentile = Gaussian.GetPercentile(test_statistic); } pValue = (1 - percentile) * (one_sided ? 1 : 2); return pValue < significance_level; } /// /// Check whether variable 1 is truely greater than variable 2 at 0.95 statistical significance confidence level, var1 and var2 are independent /// /// value sample for variable 1 /// value sample for variable 2 /// /// public bool AreGreater(double[] sample_for_var1, double[] sample_for_var2, double confidence_level = 0.95) { double[] confidence_interval_for_var1 = ConfidenceInterval.GetConfidenceInterval(sample_for_var1, confidence_level); double[] confidence_interval_for_var2 = ConfidenceInterval.GetConfidenceInterval(sample_for_var2, confidence_level); return confidence_interval_for_var1[0] > confidence_interval_for_var2[1]; } /// /// Check whether variable 1 is truely less than variable 2 at 0.95 statistical significance confidence level /// /// value sample for variable 1 /// value sample for variable 2 /// /// public bool AreLessThan(double[] sample_for_var1, double[] sample_for_var2, double confidence_level = 0.95) { double[] confidence_interval_for_var1 = ConfidenceInterval.GetConfidenceInterval(sample_for_var1, confidence_level); double[] confidence_interval_for_var2 = ConfidenceInterval.GetConfidenceInterval(sample_for_var2, confidence_level); return confidence_interval_for_var1[1] < confidence_interval_for_var2[0]; } } }