Written and maintained by CASRAI Editorial Board
Last updated
scipy.stats is the statistics module of the SciPy library for Python. It holds probability distributions, summary statistics, hypothesis tests, correlation measures and resampling methods, and it returns result objects you can read field by field. This guide maps research questions to the right function, then walks one complete workflow (a normality check followed by an independent-samples t-test) using the signatures in the SciPy 1.18.0 reference.
What scipy.stats is used for in research
The SciPy reference groups the module into probability distributions, summary statistics, frequency statistics, hypothesis tests, resampling and multiple-testing tools. It states plainly that statistics is a very large area and that some topics are out of scope for SciPy, so it is a toolkit of building blocks, not a full modelling environment. For regression models with formula interfaces and ANOVA tables, see ANOVA in Python with statsmodels.
Which function for which question
The function groupings in the official reference translate directly into a task map:
| Research question | Functions in scipy.stats |
|---|---|
| One sample against a value, or paired measurements | ttest_1samp, ttest_rel, wilcoxon, binomtest, chisquare |
| Two independent groups | ttest_ind, mannwhitneyu, ks_2samp |
| Three or more groups | f_oneway, kruskal |
| Is the data normal? | shapiro, probplot |
| Association between two variables | pearsonr, spearmanr, kendalltau, linregress |
| Categorical tables | chi2_contingency, fisher_exact |
| Resampling instead of formulas | permutation_test, bootstrap, monte_carlo_test |
| Many tests at once | combine_pvalues, false_discovery_control |
| Transforming skewed data | boxcox, yeojohnson |
Distributions such as norm, gamma, beta, binom and poisson are also in the module, and the reference notes that the fit method of the univariate continuous distributions uses maximum likelihood estimation.
Install or access (official source only)
The scipy.org install page gives two routes. With pip, create and activate a virtual environment, then run:
python -m pip install scipy
With conda, run conda install scipy (or mamba install scipy); the page recommends Miniforge and the conda-forge channel. To pin the same versions across a team, see sharing a reproducible conda environment.
Step-by-step: normality check, then independent-samples t-test
This example compares a measurement in two independent groups. The numbers are made up for illustration; the outputs shown were produced by running exactly this code with SciPy 1.18.0.
- Import the module and enter the data:
from scipy import stats a = [5.1, 4.9, 6.2, 5.8, 5.5, 6.0, 5.3, 5.7] b = [6.1, 6.8, 5.9, 7.2, 6.5, 6.9, 6.3, 7.0] - Check each group for normality with
shapiro, whose null hypothesis is that the data were drawn from a normal distribution:stats.shapiro(a) # statistic=0.9788, pvalue=0.9569 stats.shapiro(b) # statistic=0.9564, pvalue=0.7754Neither p-value gives evidence against normality here. With samples this small the test has little power, so also look at a plot (
probplot). More on the idea in normality of distribution. - Run the t-test. Student’s version is the default (
equal_var=True). Passingequal_var=Falseruns Welch’s t-test, which does not assume equal population variances:res = stats.ttest_ind(a, b, equal_var=False) res - Read the confidence interval for the difference in means:
res.confidence_interval(confidence_level=0.95) - If normality is doubtful, run the rank-based alternative:
stats.mannwhitneyu(a, b)
Output and how to read it
ttest_ind returns a TtestResult with statistic, pvalue and df (the df field was added in SciPy 1.11.0), plus a confidence_interval() method. For the example above:
| Field | Value from the run | How to read it |
|---|---|---|
statistic |
-4.514 | (mean of a – mean of b) / standard error. Negative because group a has the smaller mean; the docs state the statistic is positive when the mean of a is larger. |
pvalue |
0.000487 | Two-sided by default (alternative='two-sided'). See p-value. |
df |
13.99 | Fractional because Welch’s test was used. The documented Student example shows df=998.0 against 997.46 for Welch. |
confidence_interval() |
-1.512 to -0.538 | Interval for the difference in means (a minus b) at the 95% level by default. |
The Mann-Whitney run returned a statistic of 3.0 and a p-value of about 0.0011. For the underlying logic, see the t-test guide; for distribution-free comparisons, see the Kolmogorov-Smirnov test and permutation tests.
Troubleshooting
My result is nan
The default is nan_policy='propagate', which returns NaN if the input contains NaN. Use nan_policy='omit' to drop missing values, or 'raise' to stop with an error. Decide this on purpose: omitting values changes the sample you are testing.
Shapiro-Wilk with more than 5000 observations
The documentation says that for N > 5000 the W statistic is accurate but the p-value may not be. For large samples, rely on a Q-Q plot (probplot) rather than the p-value.
Student or Welch?
The default assumes equal population variances. If you cannot justify that, set equal_var=False.
Resampling p-values
ttest_ind accepts method=PermutationMethod or MonteCarloMethod (added in SciPy 1.15.0). The documentation cautions that permutation tests can be slow and are not necessarily more accurate than the analytical test.
ImportError or a missing module
Install SciPy into the same environment that runs your script: activate the virtual environment first, then use python -m pip install scipy so pip and the interpreter match.
Free alternatives
| Tool | Relationship to scipy.stats |
|---|---|
| statsmodels (Python) | Python package for model-based analyses such as ANOVA tables; see ANOVA in Python with statsmodels. |
For a worked regression across tools, see linear regression with Excel, R and Python.
FAQ
What is scipy.stats?
It is the statistics module of SciPy: probability distributions, summary statistics, hypothesis tests, correlation and resampling functions for Python.
How do I run a t-test in scipy.stats?
Use scipy.stats.ttest_ind(a, b) for two independent groups, ttest_rel for paired data and ttest_1samp for one sample against a value. Add equal_var=False for Welch’s test.
How do I get a confidence interval from ttest_ind?
Call confidence_interval(confidence_level=0.95) on the returned result; it gives low and high bounds for the difference in means.
Does scipy.stats replace statsmodels?
No. SciPy states that there are statistical topics out of scope for SciPy, so for model-based analyses such as ANOVA tables you can pair it with statsmodels.
Sources (official docs)
- SciPy 1.18.0 reference, Statistical functions (scipy.stats): docs.scipy.org/doc/scipy/reference/stats.html, checked 2026-10-29
- scipy.stats.ttest_ind: docs.scipy.org/doc/scipy/reference/generated/scipy.stats.ttest_ind.html, checked 2026-10-29
- scipy.stats.shapiro: docs.scipy.org/doc/scipy/reference/generated/scipy.stats.shapiro.html, checked 2026-10-29
- Installing SciPy: scipy.org/install, checked 2026-10-29








