Skip to main content
v2026.11,858 entries · CC-BY 4.0

statsmodels OLS: sm.OLS, smf.ols and How to Read summary()

How to run ordinary least squares in Python with statsmodels: sm.OLS versus smf.ols, the intercept trap, missing data, and what each summary number means.

Written and maintained by CASRAI Editorial Board

Last updated

statsmodels OLS fits an ordinary least squares linear regression in Python through two interfaces: sm.OLS(y, X), which takes arrays and adds no intercept, and smf.ols(formula, data), which takes an R-style formula and does add one. Most first-time errors come from mixing those two defaults, so this guide puts them side by side before walking through the steps and the printed summary.

What statsmodels OLS is used for in research

The OLS class in statsmodels.regression.linear_model estimates the coefficients of a linear model by minimising the sum of squared residuals. Researchers use it when they need the full inferential output of a regression (standard errors, t statistics, p values, confidence intervals, an F test) rather than only predictions. The results object exposes each of those as an attribute, so a table in a paper can be built from code instead of copied from a printout. For reading the numbers themselves, see the CASRAI guide on how to read a regression table.

Install or access

The statsmodels installation page gives two routes:

  • python -m pip install statsmodels
  • conda install -c conda-forge statsmodels

The same page lists the supported stack for the current stable release: Python 3.9 to 3.13, NumPy 1.23.5 or later, SciPy 1.8 or later, pandas 1.4 or later and Patsy 0.5.6 or later. Matplotlib 3 or later is optional and only needed for plots.

Step-by-step: fit a model with sm.OLS

This is the array interface from the official statsmodels OLS notebook. y is the response and X is a table or array of predictors.

  1. Import the API: import statsmodels.api as sm
  2. Add the intercept column yourself: X = sm.add_constant(X)
  3. Build the model: model = sm.OLS(y, X)
  4. Fit it: results = model.fit()
  5. Print the report: print(results.summary())

Step 2 is the one people skip. The class documentation is explicit that an intercept is not included by default and should be added by the user, and that no constant is added by the model unless you are using formulas.

The same model with the formula interface

  1. Import the formula API: import statsmodels.formula.api as smf
  2. Build the model from a DataFrame: mod = smf.ols(formula='Lottery ~ Literacy + Wealth + Region', data=df)
  3. Fit it: res = mod.fit()
  4. Print the report: print(res.summary())

The formula is parsed by Patsy, which includes an intercept by default; write -1 in the formula to remove it. The formula and column names above are the ones used in the statsmodels formula documentation.

sm.OLS and smf.ols compared

Question sm.OLS(y, X) smf.ols(formula, data)
Intercept Not added; call sm.add_constant(X) Added by default; -1 removes it
Text columns as predictors You must encode them yourself Text columns are treated as categorical automatically; C(col) forces a numeric column to be categorical
Dummy-coded levels You build the dummy columns One category is dropped to avoid collinearity with the intercept
Input Response array and predictor array A DataFrame plus a formula string

Output and how to read it

results.summary() prints the report; the same numbers are available as attributes of the results object, which is what you use to build tables programmatically. The RegressionResults documentation defines them as follows.

You want Attribute or method Documented meaning
Coefficients results.params The linear coefficients that minimize the least squares criterion
Standard errors results.bse The standard errors of the parameter estimates
p values results.pvalues The two-tailed p values for the t-stats of the params
Confidence intervals results.conf_int(alpha) Confidence intervals for the parameters
R-squared results.rsquared, results.rsquared_adj R-squared of the model, and its adjusted version
Overall F test results.fvalue F-statistic of the fully specified model
Residuals results.resid The residuals of the model
Predictions results.predict(exog) Calls the model’s predict method with the fitted params as the first argument

Two notes the summary prints

The bottom of the summary carries notes that are easy to scroll past. Note [1] reads: “Standard Errors assume that the covariance matrix of the errors is correctly specified.” In plain terms, the standard errors and p values are only as good as that assumption. If residual variance changes across observations, see the CASRAI guides on the Breusch-Pagan test for heteroscedasticity and robust standard errors (HC0 to HC3). The results object has a get_robustcov_results(cov_type, use_t) method that creates a new results instance with a robust covariance as the default, and HC0_se to HC3_se properties.

Note [2] appears when the condition number is large. The official OLS notebook shows it for the Longley data: “The condition number is large, 4.86e+09. This might indicate that there are strong multicollinearity or other numerical problems.” That warning points you to perfect multicollinearity and related checks. For the hypothesis tests behind the t and F columns, see linear regression hypothesis testing.

Troubleshooting

The coefficients look wrong or there is no const row

You used sm.OLS without sm.add_constant. Without a constant column the model has no intercept, which changes the other coefficients. Either add the constant or switch to smf.ols.

Missing values

For sm.OLS, the missing argument accepts ‘none’, ‘drop’ or ‘raise’. The default is ‘none’, which performs no NaN check, so pass missing='drop' or missing='raise' deliberately if your data may contain NaN. The formula documentation’s own example removes incomplete rows before fitting, with df = df[['Lottery','Literacy','Wealth','Region']].dropna().

A constant is already in your data

The hasconst argument controls how the model treats a constant: True skips the check and sets k_constant to 1, False sets it to 0. Leave it at the default unless you have a reason to override detection.

Large condition number warning

See Note [2] above. It signals possible multicollinearity or numerical problems among the predictors, so inspect the predictors before relying on individual coefficients.

Free alternatives

These are Python libraries that fit least-squares models. Check what each documents before assuming it returns the same inferential output as statsmodels.

Tool What its documentation says
scikit-learn LinearRegression “Ordinary least squares Linear Regression”; the fit_intercept parameter (default True) sets whether to calculate the intercept
SciPy scipy.stats.linregress Calculates a linear least-squares regression for two sets of measurements
NumPy numpy.linalg.lstsq Returns the least-squares solution to a linear matrix equation

FAQ

Does statsmodels OLS include an intercept?

Not through sm.OLS: add it with sm.add_constant. Through smf.ols it is included by default and -1 in the formula removes it.

Should I use sm.OLS or smf.ols?

Use smf.ols when your data is a DataFrame and you want automatic categorical handling and an intercept; use sm.OLS when you already have a design matrix.

How do I get coefficients, p values and confidence intervals out of the results?

Use results.params, results.pvalues and results.conf_int(), as in the table above.

How are NaN values handled?

In sm.OLS the default missing='none' does no NaN check; choose ‘drop’ or ‘raise’ explicitly. The statsmodels formula example drops incomplete rows with dropna() before fitting.

For a related statsmodels workflow, see ANOVA in Python with statsmodels.

Sources

  • statsmodels documentation, OLS class (stable): https://www.statsmodels.org/stable/generated/statsmodels.regression.linear_model.OLS.html, checked 2026-10-29
  • statsmodels documentation, Installing statsmodels: https://www.statsmodels.org/stable/install.html, checked 2026-10-29
  • statsmodels documentation, Ordinary Least Squares example notebook: https://www.statsmodels.org/stable/examples/notebooks/generated/ols.html, checked 2026-10-29
  • statsmodels documentation, Fitting models using R-style formulas: https://www.statsmodels.org/stable/example_formulas.html, checked 2026-10-29
  • statsmodels documentation, RegressionResults: https://www.statsmodels.org/stable/generated/statsmodels.regression.linear_model.RegressionResults.html, checked 2026-10-29
  • scikit-learn documentation, LinearRegression: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html, checked 2026-10-29
  • SciPy documentation, scipy.stats.linregress: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html, checked 2026-10-29
  • NumPy documentation, numpy.linalg.lstsq: https://numpy.org/doc/stable/reference/generated/numpy.linalg.lstsq.html, checked 2026-10-29

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about statsmodels OLS: sm.OLS, smf.ols and How to Read summary()

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →

Ask CASRAI · Regulatory Radar

Research-admin question? Get an answer that links its sources.

An AI assistant specialized in research administration. Every answer links its sources to check before you act. 2 questions free, no account. $29/month after.

  • Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.
  • Every answer numbers its sources and links each one, so you can check the source yourself.