W7
Intermediate 3 sessions • 6 hours Python

Week 7: Hypothesis Testing and Statistical Tests

.ipynb
Follow along in JupyterDownload the complete Week 7 notebook — every code example ready to run.
Download Notebook

Data Science Fundamentals Course

Week 7 Overview

Hypothesis testing is one of the most important statistical tools in data science. It provides a formal framework for making decisions about populations based on sample data. This week you'll learn how to:

  • Formulate proper hypotheses
  • Understand Type I and Type II errors
  • Interpret p-values correctly (and avoid common misinterpretations)
  • Conduct various types of statistical tests
  • Calculate effect sizes
  • Make data-driven conclusions with proper evidence

Hypothesis testing is used everywhere in data science and business:

  • A/B testing for website optimization
  • Quality control in manufacturing
  • Clinical trials for new drugs
  • Evaluating marketing campaign effectiveness
  • Detecting fraud patterns

By the end of Week 7, you will be able to:

  • Formulate null and alternative hypotheses correctly
  • Choose appropriate statistical tests
  • Calculate test statistics and p-values
  • Interpret results in business context
  • Understand Type I/II errors and statistical power
  • Calculate and interpret effect sizes
  • Report findings professionally

Week 7 is divided into three 2-hour sessions:

  • Session 1: Hypothesis Testing Fundamentals and T-tests
  • Session 2: ANOVA and Chi-Square Tests
  • Session 3: Non-parametric Tests and Effect Sizes

SESSION 1: Hypothesis Testing Fundamentals and T-tests

Duration: 2 hours

1.1 Hypothesis Testing Framework

import numpy as np
from scipy import stats
import pandas as pd
import matplotlib.pyplot as plt

print("="*50)
print("HYPOTHESIS TESTING FRAMEWORK")
print("="*50)

print("""
THE BASIC IDEA:
We make a claim about a population and test it using sample data.

STEPS:
1. State hypotheses
2. Choose significance level (α)
3. Calculate test statistic
4. Find p-value
5. Make decision and interpret

KEY CONCEPTS:
""")

print("""
NULL HYPOTHESIS (H₀):
- Status quo or no effect
- What we assume is true initially
- We try to find evidence AGAINST it

ALTERNATIVE HYPOTHESIS (H₁ or Hₐ):
- What we're testing for
- Different from null hypothesis

SIGNIFICANCE LEVEL (α):
- Probability of rejecting H₀ when it's actually true
- Common values: 0.05, 0.01, 0.10
- 0.05 means 5% chance of Type I error

P-VALUE:
- Probability of observing data as extreme (or more extreme) if H₀ is true
- Small p-value: strong evidence against H₀
- NOT the probability that H₀ is true!

DECISION RULE:
- If p-value < α: Reject H₀ (significant result)
- If p-value ≥ α: Fail to reject H₀ (not significant)
""")

# Type I and Type II errors
print("\n" + "="*50)
print("TYPE I AND TYPE II ERRORS")
print("="*50)

print("""
TYPE I ERROR (α - False Positive):
- Reject H₀ when H₀ is actually true
- "Crying wolf" - finding effect that doesn't exist
- Probability = α (significance level)

TYPE II ERROR (β - False Negative):
- Fail to reject H₀ when H₀ is actually false
- Missing real effect
- Probability = β

STATISTICAL POWER:
- Power = 1 - β
- Probability of correctly rejecting false H₀
- Typical target: 0.80 (80% power)

TRUTH TABLE:
H₀ True H₀ False
Reject H₀ Type I Error Correct ✓
Fail to Reject Correct ✓ Type II Error
""")

# Example visualization
fig, ax = plt.subplots(figsize=(10, 6))

# Two normal distributions
x = np.linspace(-4, 4, 1000)
null_dist = stats.norm.pdf(x, 0, 1)
alt_dist = stats.norm.pdf(x, 2, 1)

ax.plot(x, null_dist, 'b-', linewidth=2, label='H₀ Distribution (μ=0)')
ax.plot(x, alt_dist, 'r-', linewidth=2, label='H₁ Distribution (μ=2)')

# Critical value at α=0.05
critical_value = stats.norm.ppf(0.95)
ax.axvline(critical_value, color='black', linestyle='--', linewidth=2, label=f'Critical value (α=0.05)')

# Shade Type I error (α)
x_alpha = x[x >= critical_value]
alpha_area = stats.norm.pdf(x_alpha, 0, 1)
ax.fill_between(x_alpha, alpha_area, alpha=0.3, color='blue', label='Type I Error (α)')

# Shade Type II error (β)
x_beta = x[x < critical_value]
beta_area = stats.norm.pdf(x_beta, 2, 1)
ax.fill_between(x_beta, beta_area, alpha=0.3, color='red', label='Type II Error (β)')

ax.set_xlabel('Test Statistic', fontsize=12)
ax.set_ylabel('Probability Density', fontsize=12)
ax.set_title('Type I and Type II Errors', fontsize=14, fontweight='bold')
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

print(f"Critical value: {critical_value:.3f}")
print(f"Type I error (α): 0.05 (5%)")
print(f"Type II error (β): {stats.norm.cdf(critical_value, 2, 1):.3f} (~27%)")
print(f"Power (1-β): {1 - stats.norm.cdf(critical_value, 2, 1):.3f} (~73%)")

1.2 One-Sample T-Test

import numpy as np
from scipy import stats
import pandas as pd

print("="*50)
print("ONE-SAMPLE T-TEST")
print("="*50)

print("""
WHEN TO USE:
- Testing if population mean equals specific value
- Sample size is small (n < 30) or population SD unknown
- Data approximately normally distributed

HYPOTHESES:
- H₀: μ = μ₀ (mean equals specified value)
- H₁: μ ≠ μ₀ (two-tailed, most common)
- Or: μ > μ₀ (one-tailed, right)
- Or: μ < μ₀ (one-tailed, left)
""")

# Example: Factory production
print("\nEXAMPLE: FACTORY PRODUCTION")
print("-"*50)

# Production line target: 500g per package
target_weight = 500

# Sample weights from production
weights = np.array([498, 502, 499, 501, 497, 503, 498, 500, 499, 502,
501, 498, 497, 503, 499, 500, 502, 498, 501, 499])

print(f"Target weight: {target_weight}g")
print(f"Sample: {weights}")
print(f"Sample size: {len(weights)}")
print(f"Sample mean: {weights.mean():.2f}g")
print(f"Sample std dev: {weights.std(ddof=1):.2f}g")

# Conduct one-sample t-test
t_stat, p_value = stats.ttest_1samp(weights, target_weight)

print(f"\nT-Test Results:")
print(f"T-statistic: {t_stat:.4f}")
print(f"P-value: {p_value:.4f}")

# Interpretation
alpha = 0.05
print(f"\nSignificance level (α): {alpha}")

if p_value < alpha:
print(f"Result: REJECT H₀ (p={p_value:.4f} < {alpha})")
print("Conclusion: The mean weight is significantly different from 500g")
else:
print(f"Result: FAIL TO REJECT H₀ (p={p_value:.4f} ≥ {alpha})")
print("Conclusion: No significant difference from target weight")

# Calculate 95% confidence interval
n = len(weights)
se = weights.std(ddof=1) / np.sqrt(n)
t_crit = stats.t.ppf(0.975, df=n-1)
ci_lower = weights.mean() - t_crit * se
ci_upper = weights.mean() + t_crit * se

print(f"\n95% Confidence Interval: [{ci_lower:.2f}, {ci_upper:.2f}]")
print(f"Target {target_weight}g is {'INSIDE' if ci_lower <= target_weight <= ci_upper else 'OUTSIDE'} the CI")

# Example 2: Test score hypothesis
print("\n" + "="*50)
print("EXAMPLE 2: TEST SCORE ANALYSIS")
print("-"*50)

# Hypothesis: Class average is 75
hypothesized_mean = 75
test_scores = np.array([78, 82, 76, 74, 88, 91, 73, 71, 85, 79,
81, 75, 84, 77, 80, 72, 86, 79, 83, 75])

t_stat, p_value = stats.ttest_1samp(test_scores, hypothesized_mean)

print(f"Null hypothesis: μ = {hypothesized_mean}")
print(f"Sample mean: {test_scores.mean():.2f}")
print(f"Sample size: {len(test_scores)}")
print(f"\nT-statistic: {t_stat:.4f}")
print(f"P-value: {p_value:.4f}")

if p_value < 0.05:
print(f"Result: Class average is SIGNIFICANTLY DIFFERENT from {hypothesized_mean}")
else:
print(f"Result: Class average is NOT significantly different from {hypothesized_mean}")

# Effect size (Cohen's d)
cohens_d = (test_scores.mean() - hypothesized_mean) / test_scores.std(ddof=1)
print(f"\nEffect size (Cohen's d): {cohens_d:.3f}")
print(f"Interpretation: {'Small' if abs(cohens_d) < 0.5 else 'Medium' if abs(cohens_d) < 0.8 else 'Large'} effect")

1.3 Two-Sample T-Test

import numpy as np
from scipy import stats
import pandas as pd

print("="*50)
print("TWO-SAMPLE T-TEST")
print("="*50)

print("""
WHEN TO USE:
- Comparing means of two independent groups
- Testing if two population means are equal
- Small sample sizes or population SD unknown

HYPOTHESES:
- H₀: μ₁ = μ₂ (means are equal)
- H₁: μ₁ ≠ μ₂ (means are different - two-tailed)

ASSUMPTIONS:
- Both samples approximately normal
- Variances equal (can test with Levene's test)
- Samples are independent
""")

# Example: Treatment effectiveness
print("\nEXAMPLE: DRUG TREATMENT EFFECTIVENESS")
print("-"*50)

# Control group (no treatment)
control = np.array([5.2, 4.8, 5.1, 4.9, 5.0, 4.7, 5.3, 4.9, 5.1, 4.8])

# Treatment group (received drug)
treatment = np.array([3.2, 3.5, 3.1, 3.4, 3.0, 3.6, 3.3, 3.2, 3.4, 3.5])

print(f"Control group (n={len(control)}): {control}")
print(f"Treatment group (n={len(treatment)}): {treatment}")

print(f"\nDescriptive Statistics:")
print(f"Control mean: {control.mean():.2f}, SD: {control.std(ddof=1):.2f}")
print(f"Treatment mean: {treatment.mean():.2f}, SD: {treatment.std(ddof=1):.2f}")
print(f"Difference in means: {control.mean() - treatment.mean():.2f}")

# Test for equal variances (Levene's test)
stat_levene, p_levene = stats.levene(control, treatment)
print(f"\nLevene's Test for Equal Variances:")
print(f"P-value: {p_levene:.4f}")

equal_var = p_levene > 0.05
print(f"Assumption: Variances are {'EQUAL' if equal_var else 'NOT EQUAL'}")

# Conduct two-sample t-test
t_stat, p_value = stats.ttest_ind(control, treatment, equal_var=equal_var)

print(f"\nTwo-Sample T-Test:")
print(f"T-statistic: {t_stat:.4f}")
print(f"P-value: {p_value:.6f}")

alpha = 0.05
if p_value < alpha:
print(f"Result: REJECT H₀ (p={p_value:.6f} < {alpha})")
print("Conclusion: Treatment significantly reduces the outcome")
else:
print(f"Result: FAIL TO REJECT H₀ (p={p_value:.6f} ≥ {alpha})")
print("Conclusion: No significant difference between groups")

# Cohen's d
pooled_std = np.sqrt(((len(control)-1)*control.std(ddof=1)**2 +
(len(treatment)-1)*treatment.std(ddof=1)**2) /
(len(control) + len(treatment) - 2))
cohens_d = (control.mean() - treatment.mean()) / pooled_std

print(f"\nEffect size (Cohen's d): {abs(cohens_d):.3f}")
print(f"Interpretation: {'Small' if abs(cohens_d) < 0.5 else 'Medium' if abs(cohens_d) < 0.8 else 'Large'} effect")

# Paired t-test example
print("\n" + "="*50)
print("PAIRED T-TEST (Within-subject design)")
print("-"*50)

print("""
WHEN TO USE:
- Same subjects measured twice (before/after)
- Dependent/correlated samples
- Examples: weight before/after diet, test scores before/after training
""")

# Before and after training
before = np.array([65, 72, 68, 71, 70, 73, 69, 74, 66, 68])
after = np.array([72, 78, 74, 76, 77, 79, 75, 81, 72, 75])

print(f"\nBefore training: {before}")
print(f"After training: {after}")
print(f"Improvements: {after - before}")

# Paired t-test
t_stat_paired, p_value_paired = stats.ttest_rel(before, after)

print(f"\nPaired T-Test Results:")
print(f"Mean before: {before.mean():.2f}")
print(f"Mean after: {after.mean():.2f}")
print(f"Mean difference: {(after-before).mean():.2f}")
print(f"T-statistic: {t_stat_paired:.4f}")
print(f"P-value: {p_value_paired:.6f}")

if p_value_paired < 0.05:
print("Result: Training SIGNIFICANTLY improved performance")
else:
print("Result: Training did NOT significantly improve performance")

SESSION 2: ANOVA and Chi-Square Tests

Duration: 2 hours

2.1 Analysis of Variance (ANOVA)

import numpy as np
from scipy import stats
import pandas as pd
import matplotlib.pyplot as plt

print("="*50)
print("ONE-WAY ANOVA")
print("="*50)

print("""
WHEN TO USE:
- Comparing means across 3+ groups
- Extension of two-sample t-test
- Testing if at least one group mean differs from others

HYPOTHESES:
- H₀: μ₁ = μ₂ = μ₃ = ... (all means equal)
- H₁: At least one mean differs

ASSUMPTIONS:
- Each group approximately normal
- Variances equal across groups (test with Levene's)
- Independent observations
""")

# Example: Store performance
print("\nEXAMPLE: STORE PERFORMANCE")
print("-"*50)

# Sales from three store locations
store_A = np.array([45, 48, 42, 46, 44, 47, 43, 45, 46, 44])
store_B = np.array([52, 55, 53, 54, 51, 56, 52, 54, 53, 55])
store_C = np.array([40, 42, 39, 41, 38, 43, 40, 39, 42, 41])

print(f"Store A sales: {store_A}")
print(f"Store B sales: {store_B}")
print(f"Store C sales: {store_C}")

print(f"\nDescriptive Statistics:")
print(f"Store A: mean={store_A.mean():.2f}, sd={store_A.std(ddof=1):.2f}")
print(f"Store B: mean={store_B.mean():.2f}, sd={store_B.std(ddof=1):.2f}")
print(f"Store C: mean={store_C.mean():.2f}, sd={store_C.std(ddof=1):.2f}")

# Test homogeneity of variance
stat_levene, p_levene = stats.levene(store_A, store_B, store_C)
print(f"\nLevene's Test for Equal Variances: p={p_levene:.4f}")
print(f"Variances are {'EQUAL' if p_levene > 0.05 else 'NOT EQUAL'}")

# Conduct one-way ANOVA
f_stat, p_value = stats.f_oneway(store_A, store_B, store_C)

print(f"\nOne-Way ANOVA Results:")
print(f"F-statistic: {f_stat:.4f}")
print(f"P-value: {p_value:.6f}")

if p_value < 0.05:
print(f"Result: REJECT H₀")
print("Conclusion: Store performance differs significantly")
else:
print(f"Result: FAIL TO REJECT H₀")
print("Conclusion: No significant difference in store performance")

# Post-hoc test (pairwise comparisons)
if p_value < 0.05:
print("\n" + "-"*50)
print("POST-HOC: PAIRWISE COMPARISONS (T-tests)")
print("-"*50)

# Bonferroni correction
alpha_corrected = 0.05 / 3 # 3 pairwise comparisons

comparisons = [
("A vs B", store_A, store_B),
("A vs C", store_A, store_C),
("B vs C", store_B, store_C)
]

for name, group1, group2 in comparisons:
t_stat_post, p_post = stats.ttest_ind(group1, group2)
sig = "***" if p_post < alpha_corrected else ""
print(f"{name}: t={t_stat_post:.3f}, p={p_post:.4f} {sig}")

print(f"Note: Bonferroni corrected α = {alpha_corrected:.4f}")

# Chi-Square Test
print("\n" + "="*50)
print("CHI-SQUARE TEST")
print("="*50)

print("""
WHEN TO USE:
- Testing relationships between categorical variables
- Goodness of fit for categorical data
- Independence of two categorical variables

HYPOTHESES (Independence):
- H₀: Variables are independent
- H₁: Variables are associated
""")

# Example: Product preference by gender
print("\nEXAMPLE: PRODUCT PREFERENCE BY GENDER")
print("-"*50)

# Contingency table
observed = np.array([
[45, 30], # Male: Product A (45), Product B (30)
[25, 60] # Female: Product A (25), Product B (60)
])

df_contingency = pd.DataFrame(
observed,
index=['Male', 'Female'],
columns=['Product A', 'Product B']
)

print("Observed frequencies:")
print(df_contingency)

# Chi-square test
chi2_stat, p_chi2, dof, expected = stats.chi2_contingency(observed)

print(f"\nExpected frequencies:")
print(expected)

print(f"\nChi-Square Test Results:")
print(f"Chi-square statistic: {chi2_stat:.4f}")
print(f"P-value: {p_chi2:.6f}")
print(f"Degrees of freedom: {dof}")

if p_chi2 < 0.05:
print(f"Result: REJECT H₀")
print("Conclusion: Product preference is associated with gender")
else:
print(f"Result: FAIL TO REJECT H₀")
print("Conclusion: No association between gender and product preference")

# Cramér's V (effect size)
n = observed.sum()
min_dim = min(observed.shape) - 1
cramers_v = np.sqrt(chi2_stat / (n * min_dim))
print(f"\nEffect size (Cramér's V): {cramers_v:.3f}")
print(f"Interpretation: {'Negligible' if cramers_v < 0.1 else 'Small' if cramers_v < 0.3 else 'Medium' if cramers_v < 0.5 else 'Large'} effect")

SESSION 3: Non-parametric Tests and Effect Sizes

Duration: 2 hours

3.1 Non-Parametric Tests

import numpy as np
from scipy import stats
import pandas as pd

print("="*50)
print("NON-PARAMETRIC TESTS")
print("="*50)

print("""
WHEN TO USE:
- Data not normally distributed
- Small sample sizes
- Ordinal or ranked data
- Violate parametric test assumptions

NON-PARAMETRIC ALTERNATIVES:
- t-test → Mann-Whitney U test (Wilcoxon rank-sum)
- Paired t-test → Wilcoxon signed-rank test
- ANOVA → Kruskal-Wallis test
""")

# Mann-Whitney U Test
print("\nMANN-WHITNEY U TEST (Non-parametric alternative to two-sample t-test)")
print("-"*50)

print("""
WHEN TO USE:
- Two independent groups
- Data not normally distributed or unknown distribution
- Ordinal data or small samples
""")

# Example: Customer satisfaction (non-normal data)
old_method = np.array([3, 2, 4, 2, 3, 1, 3, 2, 4, 1]) # Ranks 1-5
new_method = np.array([5, 4, 5, 4, 4, 5, 3, 4, 5, 4])

print(f"\nOld method satisfaction: {old_method}")
print(f"New method satisfaction: {new_method}")

# Mann-Whitney U test
u_stat, p_mann_whitney = stats.mannwhitneyu(old_method, new_method, alternative='two-sided')

print(f"\nMann-Whitney U Test:")
print(f"U-statistic: {u_stat:.4f}")
print(f"P-value: {p_mann_whitney:.6f}")

if p_mann_whitney < 0.05:
print("Result: Methods have SIGNIFICANTLY different satisfaction ratings")
else:
print("Result: No significant difference in satisfaction ratings")

# Wilcoxon Signed-Rank Test
print("\n" + "="*50)
print("WILCOXON SIGNED-RANK TEST (Non-parametric paired t-test)")
print("-"*50)

print("""
WHEN TO USE:
- Paired/dependent samples
- Data not normally distributed
- Ordinal or ranked data
""")

# Before and after (ordinal data)
before = np.array([2, 3, 2, 1, 3, 2, 1, 2, 3, 2])
after = np.array([4, 5, 4, 3, 5, 4, 3, 4, 5, 4])

print(f"\nBefore: {before}")
print(f"After: {after}")
print(f"Differences: {after - before}")

# Wilcoxon signed-rank test
w_stat, p_wilcoxon = stats.wilcoxon(before, after)

print(f"\nWilcoxon Signed-Rank Test:")
print(f"W-statistic: {w_stat:.4f}")
print(f"P-value: {p_wilcoxon:.6f}")

if p_wilcoxon < 0.05:
print("Result: Significant improvement after intervention")
else:
print("Result: No significant improvement")

# Kruskal-Wallis Test
print("\n" + "="*50)
print("KRUSKAL-WALLIS TEST (Non-parametric ANOVA)")
print("-"*50)

print("""
WHEN TO USE:
- Three or more groups
- Data not normally distributed
- Ordinal data or unknown distribution
""")

# Example: Customer ratings for three products
product_A = np.array([2, 3, 2, 1, 3, 2, 4, 2, 3, 1])
product_B = np.array([4, 5, 4, 3, 5, 4, 5, 4, 5, 3])
product_C = np.array([3, 4, 3, 2, 4, 3, 4, 3, 4, 2])

print(f"\nProduct A ratings: {product_A}")
print(f"Product B ratings: {product_B}")
print(f"Product C ratings: {product_C}")

# Kruskal-Wallis test
h_stat, p_kruskal = stats.kruskal(product_A, product_B, product_C)

print(f"\nKruskal-Wallis Test:")
print(f"H-statistic: {h_stat:.4f}")
print(f"P-value: {p_kruskal:.6f}")

if p_kruskal < 0.05:
print("Result: Products have SIGNIFICANTLY different ratings")
else:
print("Result: No significant difference in product ratings")

3.2 Effect Sizes and Practical Significance

import numpy as np
from scipy import stats
import pandas as pd

print("="*50)
print("EFFECT SIZES")
print("="*50)

print("""
WHY EFFECT SIZE MATTERS:
- P-value tells if effect exists (significant)
- Effect size tells how LARGE the effect is
- Large sample can detect tiny (insignificant) effects
- Small sample might miss large (important) effects

PRACTICAL vs STATISTICAL SIGNIFICANCE:
- Statistical significance: Effect exists (p < 0.05)
- Practical significance: Effect is large enough to matter
""")

# Cohen's d
print("\n" + "="*50)
print("COHEN'S D (for comparing means)")
print("="*50)

print("""
INTERPRETATION:
- d = 0.2: Small effect
- d = 0.5: Medium effect
- d = 0.8: Large effect

CALCULATION:
Cohen's d = (Mean₁ - Mean₂) / Pooled SD
""")

# Example
group1 = np.array([85, 88, 82, 90, 86, 84, 87, 89, 83, 85])
group2 = np.array([78, 80, 75, 82, 79, 77, 81, 83, 76, 79])

mean1, mean2 = group1.mean(), group2.mean()
sd1, sd2 = group1.std(ddof=1), group2.std(ddof=1)
n1, n2 = len(group1), len(group2)

pooled_sd = np.sqrt(((n1-1)*sd1**2 + (n2-1)*sd2**2) / (n1+n2-2))
cohens_d = (mean1 - mean2) / pooled_sd

print(f"\nGroup 1: mean={mean1:.2f}, sd={sd1:.2f}")
print(f"Group 2: mean={mean2:.2f}, sd={sd2:.2f}")
print(f"\nCohen's d = ({mean1:.2f} - {mean2:.2f}) / {pooled_sd:.2f}")
print(f"Cohen's d = {cohens_d:.3f}")

effect_interpretation = "Small" if abs(cohens_d) < 0.5 else "Medium" if abs(cohens_d) < 0.8 else "Large"
print(f"\nInterpretation: {effect_interpretation} effect")

# Other effect sizes
print("\n" + "="*50)
print("OTHER EFFECT SIZES")
print("="*50)

print("""
R² (Coefficient of Determination):
- Proportion of variance explained
- 0 to 1 (0% to 100%)
- Small: 0.01, Medium: 0.06, Large: 0.14

Cramér's V (for chi-square):
- Small: 0.1, Medium: 0.3, Large: 0.5

Eta² (for ANOVA):
- Proportion of variance between groups
- Similar scale to R²

Odds Ratio:
- For categorical data
- Ratio of odds in two groups
""")

# Example: R-squared
print("\nEXAMPLE: R-SQUARED FOR CORRELATION")
print("-"*50)

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
y = 2*x + np.random.normal(0, 2, 10)

correlation = np.corrcoef(x, y)[0, 1]
r_squared = correlation ** 2

print(f"Correlation coefficient (r): {correlation:.3f}")
print(f"R-squared: {r_squared:.3f}")
print(f"Interpretation: {r_squared*100:.1f}% of variance in y explained by x")

# Reporting results
print("\n" + "="*50)
print("HOW TO REPORT RESULTS")
print("="*50)

print("""
COMPLETE RESULT REPORT SHOULD INCLUDE:

1. Test name and type (one-tailed vs two-tailed)
2. Sample descriptive statistics
3. Test statistic and value
4. Degrees of freedom (if applicable)
5. P-value (exact if p > 0.001, otherwise p < 0.001)
6. Effect size
7. Confidence interval
8. Conclusion

EXAMPLE REPORT:
"A two-sample t-test comparing treatment group (M=85.2, SD=4.3, n=10)
with control group (M=79.8, SD=5.1, n=10) revealed a significant difference,
t(18)=2.84, p=0.011, d=1.01. The 95% CI [3.12, 12.64] does not include zero,
indicating treatment significantly improved outcomes with a large effect size."
""")

# Real-world reporting
print("\n" + "-"*50)
print("REAL-WORLD EXAMPLE")
print("-"*50)

data1 = np.array([45, 48, 42, 46, 44, 47, 43, 45])
data2 = np.array([52, 55, 53, 54, 51, 56, 52, 54])

t_stat, p_value = stats.ttest_ind(data1, data2)
n1, n2 = len(data1), len(data2)
mean1, mean2 = data1.mean(), data2.mean()
sd1, sd2 = data1.std(ddof=1), data2.std(ddof=1)

pooled_sd = np.sqrt(((n1-1)*sd1**2 + (n2-1)*sd2**2) / (n1+n2-2))
cohens_d = (mean1 - mean2) / pooled_sd

se = pooled_sd * np.sqrt(1/n1 + 1/n2)
df = n1 + n2 - 2
t_crit = stats.t.ppf(0.975, df)
ci_lower = (mean1 - mean2) - t_crit * se
ci_upper = (mean1 - mean2) + t_crit * se

report = f"""
PROFESSIONAL REPORT:
A two-sample t-test comparing Method A (M={mean1:.1f}, SD={sd1:.2f}, n={n1})
with Method B (M={mean2:.1f}, SD={sd2:.2f}, n={n2}) revealed a significant
difference, t({df})={t_stat:.2f}, p={p_value:.4f}, d={cohens_d:.2f}.
The 95% CI [{ci_lower:.1f}, {ci_upper:.1f}] does not include zero.
Method B shows significantly better performance with a large effect size.
"""

print(report)

Hypothesis Testing Checklist

  • Define H₀ and H₁ clearly before analyzing data
  • Choose significance level (α) in advance
  • Check test assumptions before conducting test
  • Select appropriate test based on:
  • Number of groups (1, 2, or 3+)
  • Independence of samples
  • Data distribution normality
  • Data type (continuous vs categorical)
  • Report: test statistic, p-value, effect size, CI
  • Interpret p-value correctly (NOT probability H₀ is true)
  • Consider practical significance, not just statistical
  • Report effect size even if not significant
  • Use confidence intervals alongside p-values

Week 7 Summary

By completing Week 7, you have learned:

  • Hypothesis testing framework: H₀, H₁, α, p-value
  • Type I error (α): False positive rate
  • Type II error (β): False negative rate
  • Statistical power: 1 - β
  • Interpreting p-values correctly
  • One-sample t-test: testing against a hypothesized mean
  • Two-sample t-test: comparing two independent groups
  • Paired t-test: comparing dependent/related samples
  • Checking assumptions: normality, equal variances
  • One-way ANOVA: comparing 3+ groups
  • Post-hoc tests: pairwise comparisons after ANOVA
  • Chi-square test: independence of categorical variables
  • Contingency tables and frequency analysis
  • Mann-Whitney U test: non-parametric alternative to t-test
  • Wilcoxon signed-rank test: non-parametric paired test
  • Kruskal-Wallis test: non-parametric ANOVA
  • Effect sizes: Cohen's d, R², Cramér's V
  • Practical vs statistical significance
  • Professional reporting of results

Week 7 Assignments

Assignment 1: Hypothesis Testing Scenarios

Conduct hypothesis tests on provided scenarios:

  • Formulate appropriate null and alternative hypotheses
  • Choose correct statistical test with justification
  • Check test assumptions
  • Conduct test and report results
  • Interpret p-value and effect size
  • Make business recommendations based on findings
  • Report: 5 different hypothesis tests with full analysis

Assignment 2: A/B Testing Analysis

Analyze an A/B test (real or simulated):

  • Define control and treatment groups
  • Calculate descriptive statistics for each group
  • Conduct appropriate statistical test
  • Calculate effect size and confidence interval
  • Determine statistical and practical significance
  • Create visualizations of results
  • Write business report with recommendations

Assignment 3: Comprehensive Statistical Analysis

Perform complete statistical analysis on real dataset:

  • Test assumptions for different groups
  • Conduct multiple hypothesis tests:
  • At least 1 parametric test (t-test or ANOVA)
  • At least 1 categorical test (chi-square)
  • At least 1 non-parametric test if needed
  • Calculate all effect sizes
  • Create professional report with:
  • Summary of findings
  • Statistical evidence
  • Practical implications
  • Business recommendations
  • Appropriate visualizations
  • Conduct t-tests with different sample sizes and observe p-value changes
  • Calculate statistical power for different effect sizes
  • Compare parametric vs non-parametric test results on same data
  • Perform post-hoc tests after ANOVA with different correction methods
  • Analyze contingency tables and interpret associations
  • Design A/B tests with specified power and effect size
  • Report results using proper APA format
  • Create visualizations for different test results
  • Calculate sample size needed for desired power

Additional Resources

Books

  • Chapter 7 (continued): Statistical Inference - "Python for Data Analysis" by Wes McKinney
  • Statistics Done Wrong by Alex Reinhart
  • The Book of Why by Judea Pearl - Understanding causality

Online Resources

  • scipy.stats documentation: https://docs.scipy.org/doc/scipy/reference/stats.html
  • StatQuest with Josh Starmer (YouTube): Excellent visual explanations
  • P-value explained: https://www.nature.com/articles/506150a
  • Effect size guide: https://en.wikipedia.org/wiki/Effect_size

Tools and Calculators

  • G*Power: Statistical power analysis calculator
  • Stat Trek: Online statistics calculators
  • Real Statistics Resource Pack for Excel