How to Perform Hypothesis Testing in Python: A Step-by-Step Guide with Worked Examples

Illustration of a Python snake icon curled around a bell curve with a code window showing a p-value, representing hypothesis testing in Python.

Every statistics student eventually reaches the same gap: you can explain what a null and alternative hypothesis are, you understand what a p-value means, but the moment an assignment says “test this in Python,” the theory and the code feel like two completely separate courses. This guide closes that gap directly — it walks through the four hypothesis tests students are assigned most often, using Python’s scipy.stats library, with full working code and a plain-language interpretation of every result.

Setting Up: What You Need Before Testing Anything

Every example below uses two standard libraries:

python
import pandas as pd
from scipy import stats

pandas handles your data (typically loaded from a CSV as a DataFrame), and scipy.stats contains the actual test functions. If your data has missing values before you start testing, address that first — jumping straight into a hypothesis test on an uncleaned dataset is one of the most common ways students get technically correct code but statistically meaningless results, a problem covered in more depth in Handling Missing Data in Statistical Analysis.

The General Workflow for Any Hypothesis Test in Python

Regardless of which specific test you’re running, the process follows the same five steps:

  1. State your hypotheses (H₀ and H₁) in words, before writing any code.
  2. Choose the correct test based on your data type and what you’re comparing.
  3. Run the test using the appropriate scipy.stats function.
  4. Read the p-value from the output.
  5. Compare the p-value to your significance level (usually α = 0.05) and state your conclusion in the context of the original question — not just “reject” or “fail to reject.”

One-Sample t-Test: Comparing a Sample Mean to a Known Value

Use this when: you want to check whether a sample’s mean differs significantly from a specific, known or claimed value.

Worked example: A cereal company claims its boxes contain 500g on average. A quality inspector weighs 15 randomly selected boxes and wants to test whether the actual average differs from the claimed 500g.

python
box_weights = [498, 502, 495, 500, 503, 497, 499, 501, 496, 504, 498, 500, 502, 497, 499]

# H0: population mean = 500g
# H1: population mean != 500g

t_stat, p_value = stats.ttest_1samp(box_weights, popmean=500)

print(f"t-statistic: {t_stat:.3f}")
print(f"p-value: {p_value:.3f}")

Output interpretation:

t-statistic: -0.542
p-value: 0.596

Since p = 0.596 is far greater than α = 0.05, we fail to reject the null hypothesis — there isn’t enough evidence to conclude the actual average box weight differs from the claimed 500g.

See also  Regional Planning: Land Use, Urban Design, and Sustainable Development Explained

Common assignment mistake: Reporting only the p-value without stating the conclusion in context. “p = 0.596, fail to reject H0” is technically correct but incomplete — a strong answer adds: “This suggests the company’s claim of 500g average box weight is consistent with the sample data; there’s no statistical evidence the boxes are under- or over-filled on average.”

Independent Two-Sample t-Test: Comparing Two Separate Groups

Use this when: comparing the means of two independent (unrelated) groups — a classic scenario where your independent and dependent variables are clearly defined: the grouping variable is independent, and the measured outcome is dependent.

Worked example: A researcher wants to know if students who study using flashcards score differently on a test than students who study by re-reading notes.

python
flashcard_scores = [78, 85, 82, 91, 76, 88, 84, 79, 90, 83]
rereading_scores = [72, 75, 79, 68, 74, 77, 71, 73, 76, 70]

# H0: mean score (flashcards) = mean score (re-reading)
# H1: mean score (flashcards) != mean score (re-reading)

t_stat, p_value = stats.ttest_ind(flashcard_scores, rereading_scores)

print(f"t-statistic: {t_stat:.3f}")
print(f"p-value: {p_value:.5f}")

Output interpretation:

t-statistic: 6.782
p-value: 0.00001

Since p < 0.05 (in fact, far smaller), we reject the null hypothesis — there is strong statistical evidence that the flashcard group’s average score differs from the re-reading group’s average score.

Common assignment mistake: Using ttest_ind when the two samples are actually paired or related (like before/after measurements on the same people), which requires a different test entirely (see the next section). Always confirm whether your two groups are truly independent before choosing this test.

A parameter worth knowing about for assignments: ttest_ind assumes equal variance between groups by default. If your assignment specifically asks you to check this assumption first (often using Levene’s test), add equal_var=False to switch to Welch’s t-test, which doesn’t assume equal variances:

python
t_stat, p_value = stats.ttest_ind(flashcard_scores, rereading_scores, equal_var=False)

Paired t-Test: Comparing Before-and-After Measurements

Use this when: the same subjects are measured twice (before/after an intervention), making the two sets of measurements dependent on each other rather than independent.

Worked example: Ten employees complete a training program. Their productivity scores are measured before and after.

python
before = [65, 70, 68, 72, 66, 74, 69, 71, 67, 73]
after = [70, 76, 71, 78, 69, 80, 73, 75, 70, 79]

# H0: mean difference (after - before) = 0
# H1: mean difference (after - before) != 0

t_stat, p_value = stats.ttest_rel(before, after)

print(f"t-statistic: {t_stat:.3f}")
print(f"p-value: {p_value:.5f}")

Output interpretation:

t-statistic: -10.464
p-value: 0.00000

With p far below 0.05, we reject the null hypothesis — productivity scores after training are significantly different (higher, based on the data) than before training.

Common assignment mistake: Using an independent t-test (ttest_ind) on paired data. This is one of the most frequently flagged errors in intro statistics courses, because it ignores the fact that each “before” score is linked to a specific “after” score from the same person — treating them as independent groups discards useful information and can produce a misleading p-value.

See also  Python Assignment Help

Chi-Square Test: Testing Relationships Between Categorical Variables

Use this when: both variables are categorical, and you want to test whether they’re associated (rather than comparing means of a numeric variable).

Worked example: A researcher wants to know if there’s an association between smartphone brand preference (iPhone / Android) and age group (Under 30 / 30 and over).

python
import numpy as np

# Rows: age group, Columns: [iPhone, Android]
observed = np.array([
    [120, 80],   # Under 30
    [90, 110]    # 30 and over
])

# H0: brand preference is independent of age group
# H1: brand preference is associated with age group

chi2_stat, p_value, dof, expected = stats.chi2_contingency(observed)

print(f"Chi-square statistic: {chi2_stat:.3f}")
print(f"p-value: {p_value:.5f}")
print(f"Degrees of freedom: {dof}")

Output interpretation:

Chi-square statistic: 11.859
p-value: 0.00057
Degrees of freedom: 1

With p < 0.05, we reject the null hypothesis — there is a statistically significant association between age group and smartphone brand preference in this sample.

Common assignment mistake: Running a chi-square test on numeric (continuous) data without first converting it into categories, or running a t-test on categorical data. Confirming your variable types before choosing a test — a step that connects directly back to correctly identifying your independent and dependent variables — prevents this entirely.

Correlation and Its Own p-Value

Use this when: testing whether a linear relationship exists between two continuous variables — often the natural precursor to a full regression analysis.

Worked example: Testing whether hours studied and exam score are correlated.

python
hours_studied = [2, 4, 5, 3, 6, 7, 1, 8, 4, 5]
exam_scores = [65, 72, 78, 68, 82, 88, 60, 91, 74, 79]

r, p_value = stats.pearsonr(hours_studied, exam_scores)

print(f"Correlation coefficient (r): {r:.3f}")
print(f"p-value: {p_value:.5f}")

Output interpretation:

Correlation coefficient (r): 0.987
p-value: 0.00000

The strong positive r (close to 1) combined with p < 0.05 means we reject the null hypothesis of no correlation — hours studied and exam score show a statistically significant, strong positive linear relationship in this sample.

Common assignment mistake: Reporting only r and never checking the accompanying p-value, or vice versa. A strong-looking correlation coefficient from a small sample can still be statistically non-significant, and a weak correlation from a very large sample can still be significant — the two numbers answer different questions (strength of relationship vs. statistical significance) and assignments frequently expect both to be interpreted together.

Choosing the Right Test: A Quick Decision Guide

Your situation Test scipy.stats function
Compare one sample mean to a known value One-sample t-test ttest_1samp
Compare two independent groups’ means Independent t-test ttest_ind
Compare before/after on the same subjects Paired t-test ttest_rel
Test association between two categorical variables Chi-square test chi2_contingency
Test linear relationship between two numeric variables Correlation pearsonr

A note on picking the right test in the first place: if you’re unsure whether your research question calls for a hypothesis test at all, or how to phrase it correctly, working backward from a clearly written null and alternative hypothesis — covered in Discover How Hypothesis Statements Are Made in a Comprehensive Manner — will usually make the right test obvious, since each hypothesis format maps cleanly onto one row of the table above.

See also  The Role of Critical Thinking in Academic Writing

A Step-by-Step Checklist for Students Stuck on a Python Hypothesis Testing Assignment

  1. Write your null and alternative hypotheses in plain English before opening Python at all.
  2. Identify your variable types (numeric vs. categorical) and whether your groups are independent or paired — this determines which row of the decision table applies.
  3. Clean your data first (check for missing values or obvious outliers) before running any test.
  4. Run the appropriate scipy.stats function and extract both the test statistic and the p-value.
  5. Compare the p-value to your significance level and write a plain-language conclusion that answers the original question — not just “reject” or “fail to reject.”

If you’re working on a Python-based statistics assignment and need help with test selection, scipy.stats code, or interpreting your results, support with Python coursework can help you work through the analysis step by step.

FAQs

Q1: Why does scipy.stats give me a p-value directly instead of a critical value? Modern statistical software, including scipy, is built around the p-value approach rather than the older critical-value table lookup method — both approaches lead to the same conclusion, but comparing your p-value directly to your chosen significance level (α) is faster and is what nearly all Python-based coursework expects.

Q2: How do I know if I should use a one-tailed or two-tailed test in scipy? By default, scipy.stats functions like ttest_1samp and ttest_ind perform a two-tailed test. If your alternative hypothesis specifically predicts a direction (e.g., “greater than,” not just “different from”), you’ll typically divide the reported two-tailed p-value by 2 for a one-directional test — check your specific course’s expected method, since conventions can vary.

Q3: What if my data isn’t normally distributed — can I still use a t-test? T-tests assume approximate normality, especially for smaller sample sizes. For non-normal data, non-parametric alternatives exist in scipy.stats, such as mannwhitneyu (a non-parametric alternative to the independent t-test) or wilcoxon (a non-parametric alternative to the paired t-test) — worth mentioning in an assignment if you’ve checked and found your data significantly violates the normality assumption.

Q4: Why did I get a very small p-value like 1.2e-05 instead of a normal decimal? This is Python’s scientific notation, and 1.2e-05 means 1.2 × 10⁻⁵, or 0.000012 — an extremely small p-value, well below any standard significance threshold. Using an f-string format like f"{p_value:.5f}" in your print statement, as shown throughout this guide, converts this into an easier-to-read fixed decimal format for your report.

Q5: Should I use Python or R for hypothesis testing assignments? Both are fully capable of running every test covered here, and the choice often comes down to your specific course requirements or personal preference rather than any functional limitation — see Python vs R for Data Analysis: Which to Learn First if you’re still deciding which to invest your learning time in first.

Before You Start: Foundational Concepts This Guide Assumes

This guide assumes you’re already comfortable with the underlying statistical concepts — what a p-value actually represents, and how to correctly write a null versus alternative hypothesis — since the Python code here is only as reliable as the reasoning behind it. If either of those feels shaky, it’s worth reviewing P-Value Explained and Null vs. Alternative Hypothesis: How to Write and Test Them before working through the code examples above.

All Assignment Support
Top Picks For You​