Skip to course content
Free Python statistics course

Statistical Data Analytics with Python

Unit 10.02: smf.ols and smf.logit take the same formula

smf.ols and smf.logit accept the same formula. Only one of them is right for a binary outcome, and neither warns you.

The function name is the whole difference

smf.logit('y ~ x', data=df).fit() fits a logistic regression. Writing smf.ols with the identical formula fits a linear model on the 0/1 column, returns a full summary, and reports no error at all.

The coefficients are on the log-odds scale. A positive value means the predictor raises the log-odds of the outcome; the size is not directly interpretable as a probability change.

Instead of a residual standard error, logistic output reports likelihood. The gap between the null log-likelihood and the fitted one is what the predictors contributed, and prsquared summarises it as a pseudo R-squared — a different quantity from R-squared, not comparable with it.

This block fits churn on tenure and a support-contact indicator.

import numpy as np, pandas as pd
import statsmodels.formula.api as smf

rng = np.random.default_rng(703)
n = 500
d = pd.DataFrame({"tenure": rng.uniform(0, 48, n),
                  "support": rng.binomial(1, 0.35, n)})
p_true = 1 / (1 + np.exp(-(1.4 - 0.07 * d.tenure + 0.9 * d.support)))
d["churn"] = rng.binomial(1, p_true)

model = smf.logit("churn ~ tenure + support", data=d).fit(disp=False)
print(model.summary2().tables[1].round(4).to_string())

print("\nsmf.logit is what makes this logistic. smf.ols on the same formula")
print("fits a linear model and reports no error at all.\n")
print("Coefficients are on the LOG-ODDS scale:")
print(f"  tenure  : {model.params['tenure']:+.4f} log-odds per extra month")
print(f"  support : {model.params['support']:+.4f} log-odds for a support contact\n")
print(f"Log-likelihood     : {model.llf:.1f}")
print(f"Null log-likelihood: {model.llnull:.1f}")
print(f"Pseudo R-squared   : {model.prsquared:.4f}")
print("Logistic output reports likelihood, not a residual standard error.")

Tenure enters at −0.0772 log-odds per extra month and support contact at +0.9927, both with very small p-values. The log-likelihood improves from a null of −346.5 to −282.3, giving a pseudo R-squared of 0.1853. Note the output reports a z statistic rather than t — another sign you are looking at a logistic fit rather than a linear one.

The mistake this prevents

The mistake is writing smf.ols when you meant smf.logit. The output looks plausible, the coefficients are on a different scale from the one you think, and nothing in the printout says so.

Takeaway

Use smf.logit and check that the output reports log-likelihood and a z statistic. Read coefficients as log-odds and convert before interpreting.