机器学习回归实战:算法选型、评估与上线避坑
2026/9/17 19:11:54 网站建设 项目流程

机器学习里被问得最多的那类问题,说白了就是"帮我预测一个数"。明天这个商圈的外卖单量大概多少、这台电机还能转多少小时、下个月这条线路的用电负荷是多少——这些问题的共同点是,输出不是一个类别标签,而是一个连续的数值。这类任务在机器学习(Machine Learning)里统一归到回归(Regression)这个大类底下。我第一次听到"回归"这个词的时候还以为是"退回去"的意思,后来才搞明白,它源自高尔顿研究父代身高与子代身高关系时发现的"均值回归"现象,跟退回没有半点关系。

回归能做的事情比大多数人想的要多:它既可以是预测,也可以是解释。预测是"给我一个数",解释是"哪些因素在推动这个数变化、各自推动了多少"。前者适合做业务决策,后者适合做因果归因和策略制定。这篇文章适合三类人看:刚入门机器学习、被各种回归名词绕晕的新手;做过几个项目但对"为什么这么选、参数为什么这么定"说不清楚的进阶者;以及需要把模型推到线上、被精度波动折腾过的工程同学。下面我按"想清楚—选对路—做扎实—避坑—落地"的顺序,把回归这套东西重新捋一遍,中间会穿插我自己踩过的坑和实际项目里的取舍逻辑。

1. 回归到底在解决什么问题

1.1 分类和回归那条分界线在哪

很多人第一次分不清这两个概念。你给一堆猫和狗的图片打上标签,让模型判断新图片是哪一类,这是分类;你给一堆房子的面积、楼层、房龄,让模型吐出一个小区的成交价,这是回归。判断标准其实只有一条:目标变量是不是连续且有大小意义的。输出"是/否""猫/狗/晴天/雨天"的,是分类;输出"3.7 元""82.5 千瓦时""16.4 天"的,是回归。顺序类别比如"差/中/好"比较尴尬,既可以用有序分类处理,也可以编码成 1/2/3 后用回归做,后者的好处是保留了顺序信息,坏处是预测出来的 2.3 没有明确含义,得自己定切分阈值。

有个经典的迷惑点:逻辑回归(Logistic Regression)名字里带"回归",做的却是分类。这不是命名混乱,而是因为它建模的是对数几率 log(p/(1-p)),这个量是连续的,本质上是一个广义线性模型,只不过最后套了个 Sigmoid 把连续值压到 0 到 1 之间当概率用。理解了这一层,你就不会在面试或者复习的时候被"逻辑回归为什么叫回归"问住。

反过来,KNN这个算法既能分类也能回归,切换的只是最后一步的聚合方式。KNN 分类是取最近 k 个邻居里出现最多的标签,KNN 回归则是取这 k 个邻居目标值的平均(或者按距离倒数加权平均)。我之前给一个设备剩余寿命的课题做基线,用的就是 KNN 回归,取 k=5、距离加权,效果竟然比调了半天的神经网络还稳,原因就是数据量小、特征维度低、局部结构清晰,这种场景下简单方法的归纳偏置反而更贴合。

1.2 回归的数学骨架就三件事

不管算法名字多花哨,回归模型拆开看都是同一套骨架:假设空间、损失函数、优化方法。假设空间回答"我认为输入和输出之间长什么样",损失函数回答"怎么衡量我猜得有多偏",优化方法回答"怎么把参数调到最不偏"。

以最基础的线性回归为例,假设空间是 y = w·x + b,损失函数用均方误差 MSE,优化有两条路。一条是解析解,也就是最小二乘的正规方程:

import numpy as np # X: (n, d) 特征矩阵,y: (n,) 目标值 X_b = np.hstack([np.ones((X.shape[0], 1)), X]) # 补一列常数项 w = np.linalg.pinv(X_b.T @ X_b) @ X_b.T @ y # 用伪逆更稳

这里我没有直接写np.linalg.inv,因为 X^T X 在特征之间有共线性时可能是奇异的或者病态的,用伪逆(pinv)或者直接调np.linalg.lstsq是更稳妥的习惯。这个坑我踩过:早期做用户价值预测,两个特征一个是"近30天消费额"、一个是"近30天订单数",相关系数 0.98,直接用 inv 求出来的权重数值大得离谱,正负号还来回跳,换伪逆再加上后面要讲的岭回归才稳定下来。

另一条路是梯度下降。为什么要放弃闭式解?因为正规方程里有个矩阵求逆的操作,复杂度大概是特征维度的三次方。特征在几百维以内、样本几万条以内,闭式解又快又准;一旦特征上万(比如做了 One-Hot、或者文本哈希之后),求逆的时间和内存都会失控,这时候就得换梯度下降或者随机梯度下降。这个取舍标准很好记:看特征维度 d 和样本量 n,d 小于 10^4 且 d²n 内存扛得住,就闭式解;否则随机梯度下降(SGD)。

1.3 泛化误差界:为什么不能让模型背题

训练集上误差小,不代表线上误差小。泛化误差界给的就是"训练误差和真实误差之间能差多少"的一个理论上限。以最经典的 Hoeffding 型界为例,在样本独立同分布、损失有界的前提下,真实风险与经验风险的差距大致以 O(1/√n) 的速度收敛:

P( |R(f) - R_emp(f)| > ε ) ≤ 2·exp(-2nε²)

翻译成人话:样本量 n 越大,训练表现和真实表现的差距越小;这个差距的收敛速度跟样本量的平方根成反比,想把它减半,样本量得翻两番。这也是为什么"再标 5000 条数据"往往比"再调两天参"更值钱。

知道这个界的存在,最大的好处是让你在做决策时不迷信单次验证集分数。我现在的固定动作是:调参阶段看 5 折交叉验证的均值和标准差,而不是只看某一个折的分数;模型上线前留一个时间上更靠后的验证集,模拟"未来数据"的效果。很多项目翻车不是因为算法差,而是因为离线评估的方式和线上真实分布不一致,这个问题在时序类回归里尤其致命,后面第 4 章还会展开。

2. 回归算法的选型逻辑

2.1 线性家族:从最小二乘到三种正则

线性回归是最容易上手也最容易被低估的一类。它的可解释性强到离谱——系数直接就是"该特征每变化一个单位,目标值平均变化多少",做业务归因的时候,这种解释力比提升 0.5% 的精度更值钱。

但普通最小二乘(OLS)有两个硬伤:一是对共线性敏感,二是对异常值敏感。于是有了带正则的版本。岭回归(Ridge)在损失里加了权重的 L2 范数平方,等价于给 X^T X 的对角线加了一个正数,直接解决了矩阵奇异的问题:

w_ridge = (X^T X + λI)^{-1} X^T y

Lasso 加的是 L1 范数,好处是能把不重要的特征系数直接压成 0,天然做特征选择。代价是 L1 在 0 点不可导,没有闭式解,一般用坐标下降法迭代求解。ElasticNet 是两者的加权组合,兼顾稀疏性和稳定性,特征之间相关性很强的时候通常比纯 Lasso 表现好,我在做营销渠道归因时就是靠它把 200 多个高度相关的渠道特征压到了 30 来个。

提示:λ(有的库叫 alpha)的选法别靠感觉。sklearn 里的 RidgeCV、LassoCV 内置了高效的留一法路径,能直接给出一串候选值对应的交叉验证误差,比手写循环快很多。

2.2 树家族:从单棵树到梯度提升

决策树回归的分裂准则跟分类树不同,分类树看基尼指数或信息熵,回归树看的是分裂前后目标值的方差(或 MSE)下降了多少。每分裂一次,相当于在特征空间里切一刀,把样本分到两个"更纯"的盒子里。单棵树的问题众所周知:方差大、容易过拟合、对训练数据的小扰动极其敏感。

随机森林回归用 Bagging 的思路解决这个问题:有放回地抽 n 个子样本,每个子样本训一棵树,每次分裂只在随机的一部分特征里挑最优,最后把所有树的预测平均。平均这个动作直接砍掉了一部分方差,所以随机森林通常比单棵树稳得多,而且几乎不用调参就能出个不错的基线。代价是模型体积大、推理慢、解释性差(虽然有特征重要性,但那个重要性是有偏的,对高基数特征会高估)。

梯度提升(GBDT)走的是另一条路:串行地拟合前面所有树的残差。第一棵树预测完,算残差,第二棵树去学这个残差,第三棵树学前两棵的残差,一层层逼近。XGBoost 是这条路线上工程化做得最成熟的实现之一,它做了几件关键的事:用损失函数的二阶泰勒展开代替一阶梯度,让收敛更快;在目标函数里显式加了叶子节点数和叶子权重的正则项;支持列采样和行采样;内置缺失值自动分到增益更大的一侧。

它的分裂增益公式值得记一下,因为它解释了"什么时候才值得再分一刀":

Gain = 0.5 * [ G_L²/(H_L+λ) + G_R²/(H_R+λ) - (G_L+G_R)²/(H_L+H_R+λ) ] - γ

G 是一阶梯度和,H 是二阶梯度和,λ 控制叶子权重的惩罚,γ 是每分裂一次要付出的代价。只有当增益减去 γ 之后仍然为正,才值得分裂。γ 调大,树就更保守、更浅;λ 调大,叶子权重被压得更小,抗过拟合更强。理解这两个参数在公式里的位置,比死记"γ 是分裂阈值"要管用得多。

2.3 近邻与核方法:小样本场景的另一种选择

KNN 回归属于"懒惰学习",训练阶段什么都不做,所有计算都堆在预测时。它的核心假设是"相似的输入有相似的输出"。这个假设在低维稠密数据上通常成立,在高维稀疏数据上会被维度灾难击穿——维度一高,所有点之间的距离都趋于相等,邻居就不再"近"了。

用 KNN 回归有三个必须做的动作:标准化特征(否则量纲大的特征会主导距离计算)、选 k 值(k 小则方差大、k 大则偏差大,通常用交叉验证选)、决定加权方式(等权平均还是距离倒数加权)。距离加权在样本局部密度不均时更有优势,我给一个客户做门店销量预估时,用 k=7 的距离加权 KNN,比等权版本的 MAE 低了约 8%。

高斯过程回归(GPR)是另一类很有特色的方法。它不给你一个点预测,而是给你一个完整的预测分布——均值加上方差。这在需要"预测区间"的场景里非常有用,比如你不仅想知道明天负荷是多少,还想知道"有 95% 的把握落在什么范围"。它通过核函数(RBF、Matern 等)来刻画样本之间的相似性,预测均值的形式是:

μ* = k*^T (K + σ²I)^{-1} y

代价是它需要存整个训练集、算 n×n 矩阵的逆,复杂度 O(n³),样本量超过几万条就基本跑不动了。所以它的定位很清楚:小样本、需要不确定性量化、特征维度不高的场景。我做材料性能预测那种一次实验成本很高、样本只有几十到几百条的项目时,高斯过程是首选;样本上万就换 XGBoost 或者神经网络了。

2.4 一张表把选型说清楚

算法样本量适配需要标准化可解释性抗过拟合手段典型场景
OLS 线性回归小到中影响小极强无(易过拟合)变量少、需归因
Ridge 岭回归建议L2 正则特征共线性强
Lasso建议强(自带选择)L1 正则高维稀疏特征
决策树回归小到中不需要限深、剪枝规则提取
随机森林回归中到大不需要较弱平均+采样通用基线
XGBoost/LightGBM中到大不需要较弱正则+早停+采样竞赛与工业主力
KNN 回归必须增大 k低维局部结构
高斯过程回归建议核函数+噪声项需预测区间

我自己的默认路径是这样的:先跑一个 Ridge 拿到可解释的基线和基准误差,再跑一个 LightGBM 看能提升多少,如果提升明显就用树模型,如果提升在 3% 以内,我倾向于保留线性模型,因为它好维护、好解释、上线后的异常更容易定位。这个判断标准很多教程不讲,但实际项目里非常重要。

3. 一次完整的回归项目怎么做

3.1 数据准备与特征工程决定了八成的结果

我做过的大多数回归项目里,特征工程带来的提升远大于模型调参。这里按顺序说几个必做的动作。

缺失值处理要先分清是随机缺失还是有信息缺失。如果缺失本身携带信息(比如"没有填写收入"这件事跟违约率相关),那就别急着填,先加一个"是否缺失"的指示列,再对原列做填充。数值列填充我一般用中位数而不是均值,因为均值会被极端值带偏。树模型对缺失值天然友好,XGBoost 和 LightGBM 都能自己处理,线性模型则必须先填。

异常值处理要先判断是不是错误数据。传感器故障导致的 -999、手工录入多打一个 0,这些是错误,直接修或者删;如果是真实的极端情况(比如大促当天的订单量),删掉反而有害,正确的做法是变换或者用对异常值不敏感的损失函数。偏态分布的目标变量很常见,比如房价、销售额、用户生命周期价值,这时候对目标取 log1p 变换往往能显著改善线性模型的拟合效果,因为线性模型假设误差是正态的,而原始尺度的长尾会严重违反这个假设。别忘了预测完之后要反变换回原始尺度,并且注意反变换后的预测值是有偏的,严谨一点可以用 smearing 修正。

类别特征编码要看基数。低基数字段用 One-Hot 没问题,高基数字段(比如城市、门店 ID)One-Hot 会让维度爆炸,这时候用目标编码(Target Encoding)更合适,但必须配合交叉验证式的计算方式,否则会严重泄漏。目标编码泄漏这个坑非常隐蔽:你用全量数据算每个类别的目标均值,这个均值里已经包含了当前样本自己的目标值,模型在训练集上看起来神准,线上直接崩盘。

3.2 训练流程与核心代码

下面这段是我常用的模板,把预处理和模型串成 Pipeline,避免手动分步导致的训练/推理不一致:

from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.impute import SimpleImputer from sklearn.linear_model import RidgeCV from sklearn.ensemble import HistGradientBoostingRegressor from sklearn.model_selection import KFold, cross_val_score num_cols = ["area", "age", "floor"] cat_cols = ["district", "building_type"] num_pipe = Pipeline([ ("imp", SimpleImputer(strategy="median")), ("sc", StandardScaler()), ]) cat_pipe = Pipeline([ ("imp", SimpleImputer(strategy="most_frequent")), ("oh", OneHotEncoder(handle_unknown="ignore")), ]) pre = ColumnTransformer([ ("num", num_pipe, num_cols), ("cat", cat_pipe, cat_cols), ]) model = Pipeline([ ("pre", pre), ("reg", RidgeCV(alphas=[0.01, 0.1, 1.0, 10.0, 100.0])), ]) cv = KFold(n_splits=5, shuffle=True, random_state=42) scores = cross_val_score(model, X, y, cv=cv, scoring="neg_root_mean_squared_error") print("RMSE:", -scores.mean(), "±", scores.std())

为什么一定要用 Pipeline?因为标准化、填充、编码这些步骤都依赖训练数据统计出来的参数(均值、中位数、类别表)。如果先在全量数据上 fit 再切分,测试集的统计量就泄漏进了训练过程,你得到的分数是虚高的。用 Pipeline 之后,交叉验证会自动在每个折内重新 fit 预处理器,这个细节看起来小,但它决定了你的离线评估到底有没有参考价值。

3.3 评估指标别只会看 R²

回归的评估指标有好几个,各自适合的场景不一样,选错了会得出完全相反的结论。

指标公式要点量纲对异常值敏感度适用场景
MSE残差平方均值目标平方极高优化目标
RMSEMSE 开方同目标通用汇报
MAE残差绝对值均值同目标关注典型误差
1 - SS_res/SS_tot无量纲跨数据集对比
MAPE相对误差绝对值均值百分比低但会爆炸目标值远离 0
SMAPE对称相对误差百分比目标接近 0

几个必须知道的坑:R² 可以是负数,表示模型比"直接预测均值"还差,这时候别说"R² 有 80%",得先检查是不是数据泄漏或者切分有问题。MAPE 在真实值接近 0 时会爆炸,销售额预测里有些天是 0 单,一除就直接无穷大,所以要么过滤掉这些样本,要么改用 SMAPE 或者 WAPE(加权绝对百分比误差)。RMSE 和 MAE 的差距本身就是一个信息量:如果 RMSE 远大于 MAE,说明存在少数误差极大的样本,值得单独捞出来看,往往是数据质量问题或者某个子群体的模型失效。

我现在汇报结果的习惯是同时给三个数:MAE(业务方能理解的"平均差多少")、RMSE(用来比较模型)、以及分位数误差(P50 和 P90,看尾部表现)。只看一个数很容易被平均掩盖问题。

3.4 交叉验证与超参数搜索的正确姿势

交叉验证这块,最大的坑是时序数据不能随机切分。如果数据带时间属性,随机 K 折会让模型用"未来"的数据去预测"过去",分数虚高得离谱。正确做法是用 TimeSeriesSplit 做前向滚动验证:每次用前一段训、后一段验,逐步向前推进。我用随机 K 折和时序切分在同一个负荷预测任务上对比过,前者给出的 RMSE 比后者低了将近 30%,但线上真实表现反而是后者更准——这个差距就是泄漏出来的幻觉。

超参数搜索上,GridSearchCV 适合参数空间小的场景,RandomizedSearchCV 在维度高的时候性价比更高,贝叶斯优化(Optuna、Hyperopt)在评估一次很贵的时候优势最大。不过我想强调的是另一件事:先调对模型影响大的参数,别在小参数上磨。对梯度提升类模型,影响从大到小大致是:学习率与树数量的组合、树的深度(或叶子数)、最小叶子样本数、行/列采样比例、L2 正则。我一般先用较大的学习率(0.1)快速确定树的大致数量,再把学习率降到 0.03 左右、树数量相应增大约 3 倍,最后微调正则参数。这个顺序比盲目网格搜索省一半以上的时间。

注意:交叉验证的分数不是越高越好地追求,而是要看它和线上表现的差距有多大。我见过模型在 CV 上是 0.92 的 R²、线上只有 0.6,问题出在训练数据的时间跨度和线上不同。离线分数永远只是一个相对参考,不是承诺。

4. 常见问题与排查技巧实录

4.1 损失不下降或者直接发散

线性模型加梯度下降时,如果学习率设得太大,损失会震荡甚至变成 NaN。第一个要检查的是特征有没有标准化,量纲差异大的特征会让损失曲面变成一个细长的椭圆,梯度下降在这个曲面上来回横跳。第二个检查学习率,从 1e-3 开始试,如果损失在头几个迭代就飙到无穷,直接降一个数量级。

树模型出现"损失不降"通常是另一回事:要么是学习率太小、树的数量不够(早停的轮数设置得太短),要么是数据里有大量缺失或者标签异常。有一次我遇到 XGBoost 训练到一半验证误差不再下降,排查了半天发现是标签里混进了一批被记为 0 的缺失值,模型花了大量精力去拟合这些假的 0,把这些样本剔除后曲线立刻正常了。

4.2 训练集很好、验证集很差

这是最经典的过拟合信号,处理手段按性价比排序:

  • 加数据:最有效但最贵。如果拿不到新数据,可以看看能不能扩充特征或做数据增强。
  • 降模型复杂度:减少树的深度、增加最小叶子样本数、提高正则强度、减少特征数量。
  • 加正则:岭回归的 alpha 调大,梯度提升的 lambda 和 gamma 调大。
  • 早停:用验证集监控,在验证误差开始上升的那个点停下。这是树模型最省事也最有效的手段。
  • 特征筛选:把重要性极低或者明显是噪声的特征去掉,尤其是那些在业务上解释不通的特征。

反过来,如果训练集和验证集都很差,那是欠拟合,方向完全相反:加特征、加模型复杂度、加训练轮数。判断方向比盲目试参数重要得多,我习惯先画学习曲线(横轴训练样本量,纵轴训练误差和验证误差),两条线离得远是过拟合,两条线都高且贴在一起是欠拟合。

4.3 特征层面的隐蔽陷阱

共线性:线性模型里会导致系数不稳定、符号反常,用 VIF(方差膨胀因子)能查出来,一般 VIF 超过 10 就该处理了,手段是删掉其中之一、做 PCA、或者上岭回归。树模型对共线性不敏感,但共线性会让特征重要性分散到几个相关特征上,看起来每个都不重要,做特征选择时容易被误删。

量纲与分布漂移:训练时的特征分布和线上不一致,是最容易被忽略的线上事故来源。我有个项目,模型训练时用的是某渠道的曝光数据,上线后渠道投放策略变了,曝光量整体上了一个量级,标准化后的特征直接跑到了训练分布的尾巴外面,预测值系统性偏高。解决办法是监控特征的分布(均值、分位数),一旦偏移超过阈值就触发告警。

数据泄漏:这是最致命也最难发现的问题。常见的泄漏形式包括:用了预测时点拿不到的特征(比如用"最终成交金额"预测"是否成交")、用了全量统计量做编码、把未来信息混进了特征。排查习惯是逐个特征问一句"这个值在预测那一刻真的能拿到吗",问不过去的就删。

4.4 问题速查表

现象可能原因优先排查动作
损失变 NaN学习率过大、特征未标准化降学习率、加标准化
训练好验证差过拟合、泄漏、切分方式错查泄漏、加正则、换切分
训练验证都差欠拟合、特征信息不足加特征、加复杂度
预测值系统性偏高/偏低分布漂移、反变换偏差查特征分布、加截距项
R² 为负模型不如均值、泄漏检查切分和数据质量
树模型特征重要性全都很低特征共线性聚类后合并特征
线上精度随时间下降概念漂移建监控、定期重训

5. 从离线到线上:部署环节的坑

5.1 量化之后精度掉了,数值还不动

模型要上线到资源受限的环境,通常要做量化,把浮点权重压成 int8。我遇到过一个很典型的现象:模型量化之后,输出数值几乎不动,但精度掉了一大截。一开始以为是量化算法有问题,后来发现根因是特征侧的预处理没跟着量化对齐——训练时特征经过标准化,数值范围是围绕 0 的小数,量化后精度损失相对可控;但线上推理时预处理用了不同的实现,出来的特征尺度偏大,落到量化后的输入区间里被大量截断,模型的响应就"僵"住了,输出趋近于某个常数。

这类问题的排查顺序我总结成三步:第一步,比对线上和离线的预处理中间结果,逐列看均值和方差;第二步,用同一批样本分别跑浮点模型和量化模型,看预测值的差分布,如果差异集中在某个特征区间,就去查那个特征的预处理;第三步,确认量化是逐通道还是逐张量、激活值的动态范围是不是用校准集统计出来的。校准集的选择很关键,如果校准集和线上数据分布不一致,激活的量化范围就会偏,误差会被放大。

5.2 回归任务的上线监控该看什么

分类模型看准确率、召回率就够了,回归模型的监控要复杂一些,因为目标值往往有延迟(比如预测的是下个月的销量,得等下个月过完才能算误差)。所以我把监控分成两层。

输入端监控:每个特征的均值、标准差、缺失率、分位数,跟训练时的基准分布做对比,用 PSI(群体稳定性指数)或者 KS 统计量来量化偏移。这一层不依赖标签,可以实时算,是最早的预警。

输出端监控:预测值的分布本身是否异常,比如均值突然偏移、方差突然变小(往往是模型退化成常数输出的信号)。标签回传之后,再算 MAE、RMSE 的滚动窗口值,看趋势。

我的一般配置是:特征 PSI 超过 0.1 触发观察、超过 0.25 触发告警;误差指标相比基线恶化超过 20% 触发重训流程。阈值别照抄,得按业务容忍度定,有些场景误差涨 5% 就已经不能接受了。

5.3 电力负荷这类场景该怎么选回归方法

拿城市电力规划中的负荷预测举例,这是个很典型的回归应用。影响因素通常包括历史负荷、气温、湿度、节假日、星期几、产业结构变化等。这里的选型逻辑跟前面讲的一致:如果只需要一个可解释的基准模型,用多元线性回归,把气温、节假日等做成哑变量,系数直接告诉你气温每升高一度负荷变化多少;如果需要更高的预测精度,用梯度提升或者 LightGBM,把历史负荷的滞后项(前 1 天、前 7 天同一时刻)作为特征喂进去。

时序类回归有几个额外要注意的点。第一,切分必须按时间,不能用随机 K 折。第二,滞后特征要小心构造,预测明天 8 点的负荷时,只能用今天 8 点之前能拿到的数据,不能用明天全天的平均温度。第三,节假日这种周期性的特殊日子,要么单独建模,要么在特征里明确标出来,否则模型会把它当成普通工作日。第四,评估要看峰谷时段的误差,因为规划决策最关心的往往是峰值时刻的预测准不准,而不是全天平均误差——全天 MAE 很低但峰值低估 10%,对电网调度的意义完全不一样。

5.4 因果归因场景下的回归用法

如果你用回归的目的不是预测,而是"这个因素到底影响了多少",那要额外小心。普通线性回归的系数只有在满足"没有遗漏重要变量、没有反向因果、测量没有误差"这些条件时才有因果解释,现实中很少能全部满足。我的做法是:先跑一个预测导向的模型看整体拟合,再针对具体问题用双重差分、倾向得分匹配这类因果推断方法,回归只作为其中的一个组件,而不是唯一依据。这个界限一定要跟业务方说清楚,否则很容易出现"模型说这个因素影响最大,所以我们加大投入"这种被数据误导向的决策。

最后分享一个小技巧:回归模型的误差不是均匀分布的,永远要按子群体拆开看。整体 MAE 是 5,可能藏着一个群体的 MAE 是 2、另一个群体是 15 的情况。我在每个回归项目结束时都会按城市、品类、用户分层各跑一遍误差表,找出表现最差的那几个格子——改进那几个格子带来的收益,通常比继续在全量上调参大得多。踩过几次坑之后,我现在养成一个习惯:任何回归模型上线之前,先把误差最大的 20 个样本逐条看一遍,看完经常会发现一两个能立刻修掉的数据问题,比调参见效快。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询