资讯动态

Statsmodels一元线性回归:从跑通到读懂的完整指南

发布时间:2026/10/13 15:39:38 来源:尧图企业网站定制
1. 为什么 Statsmodels 的一元线性回归值得单独拿出来讲很多人第一次接触线性回归都是从 scikit-learn 的LinearRegression开始的。几行代码拟合完.coef_和.intercept_一取预测一跑感觉事情就结束了。但真正做过数据分析项目的人都知道业务方或者审稿人从来不会只问“斜率是多少”他们更关心的是这个斜率显著吗置信区间多宽残差是否满足假设R² 调整后还剩多少解释力这些问题scikit-learn 默认是不回答的。它把回归当成一个纯粹的预测工具而不是一个统计推断工具。Statsmodels 则完全不同它的设计哲学更接近计量经济学和经典统计学OLS结果对象里塞满了各种检验统计量、p 值、置信区间、诊断指标。对于一元线性回归这种看似最简单的模型Statsmodels 反而能让你把“简单”背后的东西看得最清楚。这篇文章就围绕 Statsmodels 做一元线性回归展开重点不是教你调包而是把结果表里每一列的含义、每个诊断量的用途、以及实际项目中容易踩的坑讲透。适合已经会用 Python 做基本数据处理、想从“跑通模型”进阶到“读懂模型”的读者。哪怕你之前只用过 sklearn看完也能无缝切换过来。2. Statsmodels 做一元线性回归的整体思路与选型考量2.1 为什么一元线性回归还要用 Statsmodels 而不是 sklearn一元线性回归的形式很简单y β₀ β₁x ε。sklearn 的LinearRegression通过最小二乘法求出 β₀ 和 β₁目标是最小化残差平方和。它不假设误差分布也不输出推断结果。Statsmodels 的OLS同样用最小二乘法但它建立在经典线性回归模型假设之上误差项独立、均值为零、同方差、正态分布。基于这些假设它才能给出系数标准误、t 统计量、p 值和置信区间。换句话说如果你只想要一条拟合直线去做预测sklearn 足够如果你想知道这条直线的斜率在统计上是否显著不为零、这个模型的解释力有多强、有没有违反假设的地方Statsmodels 才是正确工具。一元线性回归是理解这些推断概念的绝佳载体因为变量少、公式简单所有注意力都能放在统计含义上。2.2 Statsmodels 两种 API 风格的选择Statsmodels 提供两套接口sm.OLS和smf.ols。前者接收数组后者接收公式字符串。对于一元线性回归我强烈建议用公式接口smf.ols(y ~ x, datadf)原因有三点。第一公式接口自动处理截距项。sm.OLS默认不包含截距你必须手动add_constant新手极容易漏掉导致结果完全错误。第二公式接口直接引用 DataFrame 列名结果表里显示的就是变量名不用再对照位置猜哪个系数对应哪个变量。第三公式接口支持C()分类变量语法、I()表达式运算后续扩展到多元回归或加入交互项时几乎不用改代码结构。当然如果你在做循环批量拟合、变量名动态生成数组接口sm.OLS更灵活。两种方式的结果对象完全一致选哪个取决于你的使用场景。2.3 一元线性回归在 Statsmodels 中的完整流程一个规范的 Statsmodels 一元线性回归流程应该包含以下环节数据准备与缺失值检查、散点图目视检查线性关系、拟合 OLS 模型、读取结果摘要、残差诊断、异常点识别、以及必要时的变量变换。很多人只做第三步就结束了但真正决定分析质量的是后面几步。下面我会按这个流程逐步展开把每一步的操作细节和判断标准都讲清楚。3. 核心细节解析与实操要点3.1 数据准备阶段的三个关键检查在拟合之前有三件事必须做。第一是缺失值检查。Statsmodels 的OLS默认使用列表删除法处理缺失值也就是说只要某一行在 y 或 x 上有缺失整行都会被丢弃。如果缺失比例较高样本量会大幅缩水结果代表性下降。用df[[y,x]].isnull().sum()先看一眼缺失多的话要考虑插补或换变量。第二是数据类型检查。确保 y 和 x 都是数值型。如果 x 是字符串形式的数字Statsmodels 会报错或者把它当分类变量处理。用df.dtypes确认必要时用astype(float)转换。第三是异常值初筛。一元线性回归对异常值非常敏感一个极端的点就能把斜率拉偏。用箱线图或者简单的描述统计df[[y,x]].describe()看最大最小值是否远离四分位范围。注意这里只是初筛不要急着删后面还有基于残差的正式判断。3.2 散点图拟合之前必须做的目视检查在跑任何回归之前先画散点图。这一步不能省。线性回归假设 y 和 x 之间是线性关系如果散点图显示明显的曲线、U 型或者聚集直接套线性模型就是错的。用 matplotlib 或 seaborn 都行import matplotlib.pyplot as plt import seaborn as sns sns.scatterplot(datadf, xx, yy) plt.xlabel(自变量 x) plt.ylabel(因变量 y) plt.title(x 与 y 散点图) plt.show()看什么看整体趋势是否大致呈直线、有没有明显的离群点、方差是否随 x 增大而扩大异方差迹象。如果散点图显示非线性可以考虑对 x 或 y 做对数变换、平方变换或者直接换模型。这一步花两分钟能省掉后面大量返工。3.3 拟合 OLS 模型的标准写法用公式接口拟合一元线性回归的代码非常简洁import statsmodels.formula.api as smf model smf.ols(y ~ x, datadf) results model.fit() print(results.summary())这里有几个细节值得注意。smf.ols的第一个参数是公式字符串~左边是因变量右边是自变量。data参数传入 DataFrame。fit()执行实际拟合返回RegressionResults对象。summary()打印完整结果表。如果你用数组接口写法是import statsmodels.api as sm X sm.add_constant(df[x]) model sm.OLS(df[y], X) results model.fit()再次强调数组接口必须手动add_constant否则模型没有截距结果会严重偏差。公式接口则自动包含截距除非你显式写y ~ x - 1。3.4 结果摘要表逐项解读summary()输出的表格信息量很大我按区块拆解。第一部分是模型概览Dep. Variable 是因变量名Model 是 OLSMethod 是最小二乘No. Observations 是有效样本量Df Residuals 是残差自由度n-2因为估计了两个参数Df Model 是自变量个数一元回归为1。第二部分是拟合优度R-squared 是决定系数表示 y 的方差中被 x 解释的比例。Adj. R-squared 是调整后 R²考虑了自变量个数一元回归中两者差别不大。F-statistic 是整体显著性检验对应 Prob (F-statistic) 是 p 值。一元回归中 F 检验和斜率的 t 检验等价p 值应该一致。第三部分是系数表coef 是系数估计值std err 是标准误t 是 t 统计量coef/std errP|t| 是双侧 p 值[0.025, 0.975] 是 95% 置信区间。截距项 const 是 β₀x 行是 β₁。判断斜率是否显著就看 x 行的 P|t| 是否小于 0.05。第四部分是残差诊断Omnibus、Prob(Omnibus)、Jarque-Bera、Skew、Kurtosis 检验残差正态性。Durbin-Watson 检验残差自相关取值 0-4接近 2 表示无自相关。Cond. No. 是条件数检测多重共线性一元回归中通常不用太担心。3.5 提取关键结果的编程方式实际项目中不会每次都打印摘要而是要把关键指标提取出来做后续处理。常用属性results.params # 系数Series索引为变量名 results.bse # 标准误 results.tvalues # t 统计量 results.pvalues # p 值 results.conf_int() # 置信区间DataFrame results.rsquared # R² results.rsquared_adj # 调整 R² results.fvalue # F 统计量 results.f_pvalue # F 检验 p 值 results.resid # 残差 results.fittedvalues # 拟合值比如要判断斜率显著性可以写results.pvalues[x] 0.05。要拿斜率置信区间results.conf_int().loc[x]。这些属性在批量分析时非常有用。4. 实操过程与核心环节实现4.1 完整可复现的一元线性回归示例下面用一个模拟数据集走完整流程。假设我们研究某产品广告投入x万元与销售额y万元的关系。import numpy as np import pandas as pd import statsmodels.formula.api as smf import matplotlib.pyplot as plt import seaborn as sns np.random.seed(42) n 100 x np.random.uniform(1, 20, n) y 3 2.5 * x np.random.normal(0, 5, n) df pd.DataFrame({x: x, y: y}) # 散点图 sns.scatterplot(datadf, xx, yy) plt.title(广告投入与销售额散点图) plt.show() # 拟合 model smf.ols(y ~ x, datadf) results model.fit() print(results.summary())运行后你会看到斜率接近 2.5截距接近 3R² 应该很高。这个例子故意造得干净是为了先跑通流程。真实数据往往没这么理想。4.2 残差诊断的四个必查项拟合完不能直接下结论残差诊断是必须的。第一残差 vs 拟合值图看是否随机散布在零线附近有没有漏斗形异方差或曲线非线性。第二残差 QQ 图看残差是否近似正态分布点是否大致落在对角线上。第三残差 vs 自变量图看残差是否与 x 有关联。第四Durbin-Watson 值看残差是否自相关。import scipy.stats as stats resid results.resid fitted results.fittedvalues fig, axes plt.subplots(1, 3, figsize(15, 4)) axes[0].scatter(fitted, resid) axes[0].axhline(0, colorred, linestyle--) axes[0].set_xlabel(拟合值) axes[0].set_ylabel(残差) axes[0].set_title(残差 vs 拟合值) stats.probplot(resid, plotaxes[1]) axes[1].set_title(残差 QQ 图) axes[2].scatter(df[x], resid) axes[2].axhline(0, colorred, linestyle--) axes[2].set_xlabel(x) axes[2].set_ylabel(残差) axes[2].set_title(残差 vs x) plt.tight_layout() plt.show() from statsmodels.stats.stattools import durbin_watson print(Durbin-Watson:, durbin_watson(resid))如果残差图显示漏斗形说明存在异方差可以考虑对 y 取对数或者使用稳健标准误results model.fit(cov_typeHC3)。如果 QQ 图严重偏离说明正态性假设不满足小样本下会影响 p 值可信度大样本下中心极限定理会缓解这个问题。4.3 异常点与强影响点的识别异常点分两种一种是 y 方向偏离大的离群点一种是 x 方向极端的高杠杆点。Statsmodels 提供了影响诊断工具influence results.get_influence() summary_frame influence.summary_frame() # 学生化残差绝对值大于 3 视为离群点 outliers summary_frame[abs(summary_frame[student_resid]) 3] print(离群点索引:, outliers.index.tolist()) # Cook 距离大于 4/n 视为强影响点 cooks_d summary_frame[cooks_d] influential summary_frame[cooks_d 4/len(df)] print(强影响点索引:, influential.index.tolist())识别出来后不要急着删。先检查是不是数据录入错误如果是错误就修正如果是真实极端值要分析它为什么极端是否代表特殊业务场景。删点必须在报告中说明不能偷偷删。4.4 稳健标准误的使用场景当残差诊断发现异方差时普通标准误会被低估或高估导致 p 值不可靠。这时用稳健标准误results_robust model.fit(cov_typeHC3) print(results_robust.summary())HC3 是常用的异方差稳健标准误对小样本表现较好。对比普通结果和稳健结果如果系数显著性结论一致说明异方差影响不大如果结论翻转就要谨慎下结论。注意稳健标准误只修正标准误和 p 值不改变系数估计值。4.5 预测与置信区间Statsmodels 做预测需要传入 DataFrame且列名要和公式中一致new_data pd.DataFrame({x: [5, 10, 15]}) predictions results.get_prediction(new_data) pred_summary predictions.summary_frame(alpha0.05) print(pred_summary)summary_frame返回 mean、mean_se、mean_ci_lower、mean_ci_upper、obs_ci_lower、obs_ci_upper。mean 是预测均值mean_ci 是均值的置信区间obs_ci 是单个观测值的预测区间。后者比前者宽因为它包含了误差项的不确定性。报告预测结果时要说清楚用的是哪个区间两者含义不同。5. 常见问题与排查技巧实录5.1 结果表里出现 nan 或报错怎么办最常见的原因是数据里有缺失值或无穷值。Statsmodels 遇到缺失值会丢弃整行如果丢弃后样本量太小或者某变量全空结果就会出现 nan。用df[[y,x]].isnull().sum()和np.isinf(df[[y,x]]).sum()检查。另一个原因是 x 是常量方差为零无法估计斜率这时会报错或给出 nan。检查df[x].std()是否为零。5.2 R² 很高但斜率不显著是怎么回事这种情况通常说明样本量太小或者 x 的变异范围太窄。R² 高只说明拟合线离点近但如果 x 本身变化不大斜率的估计不确定性就大标准误大t 值小p 值就大。解决办法是扩大样本量或扩大 x 的观测范围。还有一种可能是异常点主导了拟合删掉后关系消失这需要结合影响诊断判断。5.3 截距项没有业务意义要不要去掉截距项在 x0 时有意义。如果 x0 在业务上不可能比如身高、价格截距只是数学上的定位参数不用强行解释。但不要因为“没意义”就删掉截距。去掉截距会强制回归线过原点除非理论上有充分理由认为 x0 时 y 必须为 0否则会导致斜率估计偏差。公式接口写y ~ x - 1可以去掉截距但要慎用。5.4 残差正态性检验不通过怎么办先看样本量。大样本下n100中心极限定理保证系数估计近似正态p 值仍然可用不必过度担心。小样本下正态性重要可以考虑对 y 做 Box-Cox 变换或对数变换。另外正态性检验本身对异常值敏感先处理异常点再看检验结果。如果只是轻微偏离通常不影响主要结论。5.5 常见问题速查表问题现象可能原因排查方法解决方向结果出现 nan缺失值、无穷值、常量 xisnull/isinf/std 检查清洗数据或换变量斜率 p 值大样本小、x 变异窄、异常点看样本量、x 范围、影响诊断扩样本、扩范围、处理异常点残差漏斗形异方差残差 vs 拟合值图对数变换或稳健标准误QQ 图弯曲残差非正态QQ 图、Jarque-Bera变换或增大样本DW 值远离 2残差自相关Durbin-Watson 值检查数据顺序、加滞后项R² 异常高过拟合、数据泄漏检查变量来源重新审视数据流程5.6 几个容易忽略的实操心得第一公式接口中变量名如果包含特殊字符空格、横杠要用Q()包裹比如Q(变量 名)。第二summary()的输出宽度可能不够可以设置pd.set_option(display.width, 200)。第三拟合结果对象可以保存为 pickle方便后续加载不用每次重新拟合。第四批量做多个一元回归时用循环加字典收集结果比一个个手动跑高效得多。第五报告结果时不要只给 R² 和 p 值置信区间和样本量同样重要缺一个都不完整。6. 从一元到多元的平滑过渡建议一元线性回归是起点不是终点。掌握了 Statsmodels 的公式接口和结果解读后扩展到多元回归只需要在公式右边加变量y ~ x1 x2 x3。结果表的解读逻辑完全一致只是多了几个系数行。但要注意多重共线性问题这时 Cond. No. 和 VIF 就派上用场了。另外多元回归中调整 R² 比 R² 更重要因为 R² 会随变量增加而虚高。我个人的习惯是任何多元回归之前先把每个自变量和因变量单独做一元回归看看各自的关系方向和强度。这一步能帮你发现变量变换的需求、异常值的影响、以及哪些变量可能交互。一元回归跑起来快结果直观是探索性分析的利器不要因为它简单就跳过。最后分享一个小技巧Statsmodels 的结果对象有save()和load()方法可以把拟合结果序列化到文件。做报告或者需要反复查看结果时存一份省得重跑。另外results.summary2()返回的是 DataFrame 格式的摘要方便导出到 Excel 或做进一步处理比summary()的文本格式更适合程序化使用。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑