Skip to content

How to run a Welch two-sample t-test in SciPy (with Code)

The Short Answer (TL;DR)

Call scipy.stats.ttest_ind with equal_var=False to compare the means of two independent samples without assuming equal population variances. Report the estimated mean difference and its confidence interval alongside the two-sided p-value.

from scipy import stats
a, b = [4.2, 5.1, 4.8, 5.5, 6.0, 5.2], [6.5, 7.4, 8.1, 6.9, 9.0, 7.8, 8.5, 7.1]
result = stats.ttest_ind(a, b, equal_var=False, alternative="two-sided", nan_policy="raise"); print(result)

Detailed Implementation

This example uses synthetic data and does not need a network connection. Install the recorded package versions in a separate Python environment before running it.

python -m pip install numpy==2.5.4 scipy==1.18.1
from pathlib import Path
import numpy as np
from scipy import stats

# Two independent synthetic groups, measured in the same units.
a = np.array([4.2, 5.1, 4.8, 5.5, 6.0, 5.2])
b = np.array([6.5, 7.4, 8.1, 6.9, 9.0, 7.8, 8.5, 7.1])
result = stats.ttest_ind(a, b, equal_var=False, alternative="two-sided",
                        nan_policy="raise")
difference = a.mean() - b.mean()
interval = result.confidence_interval(confidence_level=0.95)
report = (
    f"Sample sizes: {a.size} and {b.size}\n"
    f"Mean difference (A - B): {difference:.6f}\n"
    f"Welch t: {result.statistic:.6f}\n"
    f"Degrees of freedom: {result.df:.6f}\n"
    f"Two-sided p-value: {result.pvalue:.8g}\n"
    f"95% CI for mean difference: [{interval.low:.6f}, {interval.high:.6f}]\n"
)
print(report)
Path("welch-test-output.txt").write_text(report, encoding="utf-8")

The output reports sample sizes 6 and 8, a negative difference A minus B, the Welch statistic, fractional degrees of freedom, a two-sided p-value and a 95% confidence interval entirely below zero for these synthetic data. The saved text preserves the displayed report.

Which observations belong in this test?

Each sample contains observations from a separate group. Independence concerns how measurements were obtained, not whether their values look different. Repeated measurements of the same subjects require a paired or repeated-measures analysis. Strong dependence within groups also invalidates the ordinary standard error.

How should the p-value be interpreted?

The two-sided p-value measures tail extremeness under the equal-means null model and the test assumptions. It is not the probability that the null hypothesis is true, the probability the result will replicate, or a measure of practical importance. Decide the question and any significance threshold before inspecting the result.

What should be checked with small samples?

Inspect skew, outliers and the sampling design. Welch adjusts for unequal variances, but it does not make every small or contaminated sample suitable for a t approximation. The example rejects missing values rather than silently dropping observations; choose and document a missing-data strategy for real measurements.

Mathematical Context

Let the sample means be xbar1 and xbar2, the unbiased sample variances be s1 squared and s2 squared, and the sample sizes be n1 and n2. The standard error is the square root of s1 squared/n1+s2 squared/n2; the t statistic divides the estimated mean difference by that standard error. Welch uses an approximate t reference distribution with degrees of freedom nu=(u1+u2)^2/[u1^2/(n1-1)+u2^2/(n2-1)], where uj=sj squared/nj. The 95% confidence interval is the difference plus or minus t_(0.975,nu) times the standard error. Approximately normal independent populations support the small-sample calculation; larger samples can improve the approximation under suitable moment and sampling conditions.

\[ t=\frac{\bar{x}_1-\bar{x}_2}{\sqrt{s_1^2/n_1+s_2^2/n_2}} \]

Reproducibility

Executed with Python 3.12.14; numpy 2.5.4, scipy 1.18.1. Automated checks confirm the stated output properties.

Primary documentation

Related guides