How to Interpret a statsmodels OLS Summary
Lesson 10 of 16 · Data Manipulation
Reading a statsmodels OLS Summary, Line by Line
Scene: your thesis supervisor's office. You slide a printout across the desk: one regression of a fund's monthly excess return on the market's. Your supervisor circles the intercept and asks: "So does this fund have alpha or not? And where does that number come from?" The table has some thirty numbers on it. In this lesson you learn which five carry the answer, how each one is computed, and the one-line bug that makes statsmodels quietly drop the intercept you are being asked about.
What it is: OLS (ordinary least squares) fits the straight line that makes the sum of squared vertical gaps between the data and the line as small as possible. statsmodels is the Python library econometricians use for it, because unlike scikit-learn it reports the inference: standard errors, t-statistics, p-values and confidence intervals.
The model
fund_t = α + β × mkt_t + ε_t
α (const): alpha, the fund's return when mkt_t = 0
β (mkt): beta, % move in the fund per 1% in mkt
ε_t: what the market does not explain
fund, mkt: monthly excess returns, in %
The one line statsmodels does not do for you
R and Stata add an intercept automatically. sm.OLS does not. If you pass the market column alone, statsmodels fits a line forced through the origin: there is no alpha to test, the slope absorbs it, and the R-squared switches to an "uncentered" version that is not comparable with anything. The fix is one function call that prepends a column of 1s named const:
# X gets two columns: const (all 1s) and mkt
X = sm.add_constant(df[["mkt"]])
# y first, then X
fit = sm.OLS(df["fund"], X).fit()
print(fit.summary())
(The formula interface, smf.ols("fund ~ mkt", data=df), adds the intercept for you. Use one style consistently.)
The summary, block by block
Here is the table this lesson's data produces, with the numbers you will reproduce.
Top block: the fit as a whole
| Line | Value | Plain English |
|---|---|---|
| No. Observations | 60 | five years of months |
| Df Residuals | 58 | n minus the number of coefficients: 60 - 2 |
| Df Model | 1 | slopes, not counting the constant |
| R-squared | 0.896 | the market explains 89.6% of the variance of the fund's returns |
| Adj. R-squared | 0.894 | R² penalised for regressors: 1 - (1 - 0.896) × 59/58 |
| F-statistic | 500.4 | tests "all slopes are zero" at once |
| Prob (F-statistic) | 3.31e-30 | its p-value |
| Log-Likelihood, AIC, BIC | -122.0, 248.0, 252.2 | for comparing models: lower AIC or BIC is better |
| Covariance Type | nonrobust | the classic standard errors, which assume well-behaved errors |
Middle block: one row per coefficient. This is the part your supervisor circled.
| coef | std err | t | P>|t| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| const | 0.4369 | 0.244 | 1.793 | 0.078 | -0.051 | 0.925 |
| mkt | 1.1429 | 0.051 | 22.369 | 0.000 | 1.041 | 1.245 |
- coef: the estimate. Alpha is 0.44% a month; beta is 1.14.
- std err: how much the estimate would wobble from sample to sample. Smaller is more precise.
- t: the estimate measured in standard errors, t = coef / std err. For alpha: 0.4369 / 0.2437 = 1.79.
- P>|t|: the two-sided p-value for the null "this coefficient is 0", read from a t distribution with 58 degrees of freedom. 0.078 is above 0.05, so at the 5% level you cannot reject an alpha of zero.
- [0.025, 0.975]: the 95% confidence interval, coef ± 2.002 × std err (2.002 is the 97.5% point of t with 58 df). Alpha's interval, -0.051 to 0.925, contains zero: the same verdict as the p-value, seen from another side.
With one regressor the F-test and the t-test on the slope are the same test: F = t² = 22.369² = 500.4.
Bottom block: diagnostics on the residuals
- Omnibus and Jarque-Bera (JB): tests of normal residuals. High p-values (0.640, 0.612) mean no evidence against normality.
- Skew (0.23) and Kurtosis (2.57, where a normal distribution has 3): the shape of the residuals.
- Durbin-Watson (1.75): about 2 means no autocorrelation in the residuals; well below 2 means positive autocorrelation, and then the standard errors above are too small (the next lesson fixes that).
- Cond. No. (4.79): large values (statsmodels warns above 1,000) signal near-collinear regressors or badly scaled data.
The answer for your supervisor
Alpha is 0.44% a month, about 5.2% a year (0.44 × 12), which sounds impressive. But its t-statistic is 1.79 and its p-value 0.078: not significant at 5%. Five years of monthly data cannot tell this alpha apart from zero. Beta, by contrast, is pinned down tightly at 1.14 (t = 22.4). The data were generated with a true alpha of 0.25% a month; a 60-month sample is simply too short to prove it.
Your Task
The starter fits the regression and prints the summary plus a short "reading" block. YOUR TURN marks the line that builds X: it passes the market column alone, so the summary shows "R-squared (uncentered)", no const row, and the reading block reports that alpha is missing.
Predict before you run: once you add the constant, will beta move up, down, or stay the same, and will the R-squared line change its name? Then wrap the X line in sm.add_constant(...) and check the reading block against the table above.
Related terms in the glossary
Further reading
Where to go deeper. Free means a full, legal copy is online.
Chapters 2 to 4: the simple regression, the t-test on a coefficient and the F-test, in exactly the vocabulary of this summary table.