实测跑过几轮对照实验之后我才发现很多人问支持向量机SVM和支持向量回归机SVR的区别本质上是在问一个更基础的问题同一个优化框架把损失函数换掉之后模型的行为到底会变成什么样。这两个算法名字只差一个字母在 sklearn 里也是同一个模块下的兄弟类但它们的输出空间、损失函数、支持向量的物理含义、超参数的调法几乎全都不一样。更麻烦的是网上大量教程把它们混着讲导致不少人拿着 SVC 的调参经验去调 SVR最后得到一条几乎贴着均值的直线还以为是自己数据的问题。这篇内容我打算把两者的分岔点、数学骨架、超参数语义和实操链路全部拆开讲一遍代码全部用 sklearn 可直接复现适合已经会用 sklearn 但一直没搞清这两个模型边界的人也适合需要选型决策的工程同学。1. 同一个优化框架两个完全不同的输出先把SVM和SVR的分岔点说清楚1.1 从找一条最宽的路到造一条最合适的带SVM 的经典图景非常直观在一堆两类样本中间画一条分界线并且要求这条线尽可能远离最近的样本点。这个远离的距离就是间隔marginSVM 的目标是让间隔最大化。贴在间隔边界上的那几个点就是支持向量——整个决策面只由这几个点决定你把其他样本删掉分界线可能纹丝不动这也是支持向量这个名字的由来。SVR 的图景则完全不同它不画分界线而是造一条有宽度的管状带tube管子以回归曲线为中心总宽度是 2ε。凡是落在管子里的样本一律认为预测得已经足够准了不计入任何损失只有掉在管子外面的点才会产生惩罚。所以 SVR 的支持向量是那些压在管子边界上或者掉在管子外面的样本管子内部的点全部被忽略。这个差别带来一个非常关键的直觉分类任务关心的是边界回归任务关心的是带宽。前者的核心问题是分界线该往哪边偏一点后者的核心问题是这条带子该多宽、往哪弯。理解了这个画面后面所有的公式推导、对偶形式、参数语义你都能自己推出来七八成不用死记。1.2 输出空间决定了损失函数必须整个换掉分类的输出是离散标签Hinge 损失天然贴合这个场景只要样本被正确分类并且离边界足够远损失就是零一旦被分错或者离边界太近就线性地惩罚。这个零损失区域的存在让 SVM 对噪声有一定的容忍度。但回归的输出是连续数值如果你继续用这种对错二元的惩罚方式问题就大了——预测值和真实值差 0.001 和差 1000会被同等对待这显然不合理。所以 SVR 换成了 ε 不敏感损失形式是 max(0, |y - f(x)| - ε)。这个损失有两个我很看重的特性第一ε 范围内损失为零意味着模型对小幅噪声完全不敏感传感器采集时那点抖动根本影响不到拟合结果第二超过 ε 之后惩罚只是线性增长而不是像最小二乘那样平方增长所以单个极端离群点没办法把整条曲线拽偏。我在含噪的传感器时序数据上做过对照最小二乘回归被一个尖峰带偏了很远而 SVR 基本稳在原地。这也是为什么在噪声大、离群点多的小样本回归任务里SVR 常常比线性回归更好用的直接原因。1.3 一张表看清两者的对照关系先把最容易混淆的维度列成表后面每一行我都会展开。对比维度SVM分类SVR回归任务输出离散类别标签连续数值几何直觉最大化间隔的分界超平面宽度为 2ε 的容错管道损失函数Hinge 损失ε 不敏感损失支持向量位置间隔边界上或越界管道边界上或管道外独有超参数class_weight类别权重epsilon管道半宽常用评估指标准确率、F1、AUCMAE、RMSE、R²典型副作用概率输出需要额外校准预测值向均值收缩大样本替代方案LinearSVC / SGDClassifierLinearSVR / SGDRegressor这张表里最值得盯住的是支持向量位置和典型副作用两行。前者决定了你用n_support_观察模型复杂度时两个模型的解读方式完全不同后者是新手最容易踩的雷我后面会用专门一节讲。2. 把两类问题的数学骨架拆到能看懂的程度2.1 硬间隔、软间隔与松弛变量SVM 的分类骨架硬间隔 SVM 的原始问题写出来是这样的最小化 (1/2)||w||²约束条件是每个样本都满足 y_i(w·x_i b) ≥ 1。这个约束的物理含义就是所有样本都在间隔之外。问题在于现实数据几乎不可能线性完全可分硬间隔会直接无解。于是引入松弛变量 ξ_i把约束放宽成 y_i(w·x_i b) ≥ 1 - ξ_i同时目标函数变成最小化 (1/2)||w||² C·Σξ_i。这个式子里的 C 就是惩罚系数C 越大对违反间隔的容忍度越低模型越倾向于把所有训练样本都分对泛化风险随之升高C 越小允许更多样本落在间隔内甚至分错模型更宽容。注意这里有个容易被忽略的点目标函数是间隔宽度和违规总量的一个加权和它本质上是一个结构风险最小化的实现——前半部分控制模型复杂度后半部分控制训练误差。理解了这一点你就明白为什么 C 的两端分别对应欠拟合和过拟合而不是越大越好或者越小越好。2.2 ε 不敏感管道是怎么写进目标函数的SVR 的原始问题形式上和 SVM 很像但多了一组变量最小化 (1/2)||w||² C·Σ(ξ_i ξ_i*)约束是y_i - (w·x_i b) ≤ ε ξ_i(w·x_i b) - y_i ≤ ε ξ_i*ξ_i, ξ_i* ≥ 0前面两条约束分别管预测偏低和预测偏高两个方向所以需要两组松弛变量。把两条约束合起来看就是|y_i - (w·x_i b)| ≤ ε ξ_i也就是说残差在 ε 以内时 ξ 取零完全没有惩罚超出 ε 的部分才由 ξ 承接并且被 C 线性惩罚。这里的 ε 是 SVM 里根本不存在的东西。它不是正则项也不是容错上限而是多准才算准的定义。你在心里设定一个可接受的误差范围SVR 就只对这个范围之外的偏差负责。这个设计对业务场景其实非常友好——预测销量差几十件无所谓那我直接把 ε 设成几十模型就不会为了拟合这些无关紧要的偏差而扭曲整体形状。2.3 对偶形式里的支持向量到底是谁SVM 的对偶问题是通过拉格朗日乘子 α_i 得到的最后预测函数写成 f(x) Σ α_i y_i K(x_i, x) b其中 K 是核函数。KKT 条件给出了 α_i 的三种状态α_i 0 的样本对决策面毫无影响0 α_i C 的样本恰好压在间隔边界上α_i C 的样本则是越过了边界的那批。后两类就是支持向量这也是为什么删掉 α_i 0 的点模型不变。SVR 的对偶形式更绕一点因为每个样本有两个乘子 α_i 和 α_i*它们的差 α_i - α_i* 才是这个样本的系数。预测函数变成 f(x) Σ (α_i - α_i*) K(x_i, x) b而且只有当 |α_i - α_i*| 0 时才有贡献。这个条件对应的正是样本落在管道外或压在管道边界上。换句话说管子里的样本 α_i α_i* 0系数直接归零被彻底忽略。这就解释了一个很多人疑惑的现象为什么 SVR 的支持向量数量有时候会明显少于样本数因为如果你的 ε 设得比较宽大部分样本都乖乖待在管子里了。反过来支持向量占比很高比如超过 80%通常意味着 ε 太小或者 C 太大模型在过度较真每一个点这是我会立刻回去调参的信号。3. C、gamma、epsilon 在两类任务里的角色完全不同3.1 C 的两副面孔同样是 C在 SVM 和 SVR 里的作用机制其实有细微但重要的差别。SVM 里 C 直接决定了间隔违规的惩罚力度它的对偶约束是 0 ≤ α_i ≤ CC 是 α 的上界也就是单个样本最多能有多大话语权。C 越大单个越界样本的影响力越大决策面越容易被少数难分样本带着走。SVR 里 C 同样是 α 的上界但它的对偶约束变成了 0 ≤ α_i, α_i* ≤ C也就是单个样本在管道外的偏差最多被计入 C 的权重。由于 SVR 的系数是 α_i - α_i*当 C 很小时两个乘子都被压得很低模型的预测几乎不动输出会趋向于一个接近常数的曲线当 C 很大时模型拼命去拟合每一个超出 ε 的点容易在噪声上过拟合。我自己的经验值是这样小样本几千条以内、特征经过标准化之后SVM 的 C 从 1 开始试SVR 的 C 从 10 开始试通常更省时间。原因是 SVR 的目标值量纲会放大残差需要更大的 C 才能让模型动起来。当然这只是起点真正靠谱的做法还是网格搜索只是它能把搜索范围缩窄。3.2 gamma 与核函数RBF 核下的影响半径RBF 核的形式是 K(x, x) exp(-gamma · ||x - x||²)其中 gamma 和传统的 σ 是倒数关系gamma 1/(2σ²)。物理含义是gamma 越大单个样本的影响半径越小模型的决策面/拟合曲线越能贴合局部细节gamma 越小影响半径越大模型越平滑。这个规律在两个任务里方向一致但后果不太一样。分类任务里 gamma 过大会出现一个个孤立的小岛式决策区域训练集准确率飙到 99% 但测试集一塌糊涂回归任务里 gamma 过大曲线会变成锯齿状的折线把每个噪声点都串起来看起来拟合得很好实际预测能力极差。sklearn 里 gamma 的默认值是scale等于 1/(n_features × X.var())这个默认值在特征标准化之后通常是个不错的起点。我一般只在这个基础上试三档scale、它的 0.1 倍、它的 10 倍。相比很多人习惯的 0.01/0.1/1/10 固定网格按数据方差缩放的做法在两个任务之间迁移性更好不容易出现某一档完全无效的浪费。3.3 epsilon 是 SVR 独有的旋钮也是最容易被忽略的如果只让我强调一个 SVM 与 SVR 调参上的核心差异那就是SVR 多了一个决定模型松紧的 epsilon而且它比 C 更能改变模型形态。epsilon 的语义是可接受的误差带半宽。设得太小几乎所有样本都掉到管道外模型退化成试图拟合每个点接近最小二乘还丢掉了鲁棒性优势设得太大管道宽到什么都装得下模型直接输出一条接近常数的直线也就是常见的预测全等于均值。怎么定 epsilon 有个很实用的办法先看目标变量的量纲和业务可接受的误差。比如预测房价业务上差 5 万以内都算可接受那 ε 就按 5 万来设注意目标变量需要标准化的话要换算过去。想要更数据驱动一点可以先用一个快速的基线模型比如随机森林回归或线性回归算一遍残差的标准差取它的 0.1 到 0.2 倍作为 epsilon 的搜索中心再在 [0.5倍, 2倍] 区间里网格搜索。这套流程比盲搜 0.01/0.1/0.5 要靠谱得多我实测至少能省一半以上的调参时间。补充一个很多人不知道的变体NuSVR用参数 nu ∈ (0, 1] 同时接管 C 和 epsilon 的部分职责nu 可以粗略理解为允许掉在管道外的样本比例上限。当你对异常点比例有业务先验时比如已知数据里有 5% 的坏点用 NuSVR 直接设 nu0.05 比调 C 和 epsilon 两个参数要直观得多。分类侧也有一一对应的NuSVC。4. 从 sklearn 跑通分类与回归的对照实验4.1 数据生成与标准化这一步决定了模型能不能用这两个模型都是基于距离的核方法特征尺度不统一会直接毁掉结果。一个取值范围 0 到 1 的特征和一个取值范围 0 到 10000 的特征放在一起RBF 核算出来的距离几乎完全由后者主导。所以标准化不是最好做一下而是必须做。更重要的是StandardScaler必须只在训练集上 fit然后 transform 测试集。这个细节看起来像废话但我在代码审查里见过太多次先对全量数据 fit_transform 的写法——这等于把测试集的均值和方差信息泄漏进了训练过程评估出来的分数会虚高上线之后直接掉。import numpy as np from sklearn.datasets import make_classification, make_regression from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # 分类数据 Xc, yc make_classification(n_samples2000, n_features20, n_informative8, n_redundant4, class_sep1.2, flip_y0.05, random_state42) Xc_tr, Xc_te, yc_tr, yc_te train_test_split(Xc, yc, test_size0.3, stratifyyc, random_state42) scaler_c StandardScaler().fit(Xc_tr) Xc_tr, Xc_te scaler_c.transform(Xc_tr), scaler_c.transform(Xc_te) # 回归数据故意加一点离群点用来看鲁棒性 Xr, yr make_regression(n_samples2000, n_features20, n_informative8, noise20.0, random_state42) rng np.random.default_rng(0) outlier_idx rng.choice(len(yr), size30, replaceFalse) yr[outlier_idx] 300 # 人工污染 Xr_tr, Xr_te, yr_tr, yr_te train_test_split(Xr, yr, test_size0.3, random_state42) scaler_r StandardScaler().fit(Xr_tr) Xr_tr, Xr_te scaler_r.transform(Xr_tr), scaler_r.transform(Xr_te)注意回归侧我做了两件事一是给目标值加了离群点用来观察 SVR 和线性回归的差异二是 X 的标准化器和 y 分开处理。y 要不要标准化取决于你怎么设 epsilon——如果 y 的量纲是几万epsilon 也得跟着是几百几千网格搜索的尺度会很难看。我通常会把 y 也标准化让 epsilon 回到 0.1 这个量级最后预测时再逆变换回去。4.2 SVM 分类的完整链路分类侧直接用SVCRBF 核起步同时打开probabilityTrue以便画 ROC 曲线。from sklearn.svm import SVC from sklearn.metrics import (classification_report, confusion_matrix, roc_auc_score, f1_score) import time t0 time.time() clf SVC(kernelrbf, C1.0, gammascale, probabilityTrue, class_weightbalanced, random_state42) clf.fit(Xc_tr, yc_tr) print(f训练耗时: {time.time()-t0:.2f}s) pred clf.predict(Xc_te) proba clf.predict_proba(Xc_te)[:, 1] print(confusion_matrix(yc_te, pred)) print(classification_report(yc_te, pred, digits4)) print(AUC , round(roc_auc_score(yc_te, proba), 4)) print(支持向量数:, clf.n_support_, 总计:, clf.n_support_.sum())这里有两个细节值得说。第一class_weightbalanced在处理不平衡数据时比盲目加大 C 有效得多它按类别频率自动给少数类更高的样本权重是在损失层面做的修正而加大 C 只是把所有样本的惩罚一起拉高往往会让少数类被更多噪声点淹没。第二probabilityTrue打开之后 sklearn 会额外跑一次 Platt 标定或者说内部交叉验证训练时间通常会翻倍甚至更多所以只有在你确实需要概率输出时才打开只做类别判定的话关掉能省大量时间。另一个观察指标是n_support_。如果支持向量占训练样本的比例超过 70%基本可以判断模型在硬扛噪声该降 C 或者升 gamma。这个比值是我判断模型紧不紧最快的体检指标比看训练准确率直观得多。4.3 SVR 回归的完整链路与目标变换回归这边我把 y 标准化后再喂给 SVRepsilon 按标准化尺度设。from sklearn.svm import SVR, LinearSVR from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score scaler_y StandardScaler().fit(yr_tr.reshape(-1, 1)) yr_tr_s scaler_y.transform(yr_tr.reshape(-1, 1)).ravel() yr_te_s scaler_y.transform(yr_te.reshape(-1, 1)).ravel() def evaluate(name, model, Xtr, ytr, Xte, yte, scaler_yNone): model.fit(Xtr, ytr) p model.predict(Xte) if scaler_y is not None: p scaler_y.inverse_transform(p.reshape(-1, 1)).ravel() mae mean_absolute_error(yte, p) rmse mean_squared_error(yte, p) ** 0.5 print(f{name:14s} MAE{mae:8.2f} RMSE{rmse:8.2f} R2{r2_score(yte, p):.4f}) return p p_lr evaluate(LinearRegression, LinearRegression(), Xr_tr, yr_tr, Xr_te, yr_te) p_svr evaluate(SVR(rbf,eps0.1), SVR(kernelrbf, C10.0, gammascale, epsilon0.1), Xr_tr, yr_tr_s, Xr_te, yr_te_s, scaler_y) p_lsv evaluate(LinearSVR, LinearSVR(C1.0, epsilon0.1, max_iter20000, random_state42), Xr_tr, yr_tr_s, Xr_te, yr_te_s, scaler_y)在我构造的这份带污染数据上线性回归的 RMSE 会被那 30 个离群点明显拉高而 SVR 因为只线性惩罚、且超出部分被 C 截断表现会稳定得多。这就是前面讲的鲁棒性优势落到数字上的样子。但我要特别提醒一句SVR 的鲁棒性是有代价的。它对管道内的样本完全不敏感意味着如果数据里有一段区域的样本全部落在管道内模型在那里就没有任何约束力曲线的形状完全靠核函数和正则项决定。回归任务如果你需要精确拟合每个区间SVR 未必是最优选择。4.4 网格搜索该搜哪些参数两个模型的搜索空间不一样不要共用一套参数网格。SVM 的搜索空间C和gamma评价指标用f1不平衡数据或roc_auc不要用 accuracy因为准确率在不平衡数据上有很强的欺骗性。SVR 的搜索空间C、gamma、epsilon三个比分类多一维计算量自然更大。评价指标用neg_mean_absolute_error或neg_root_mean_squared_error。用 RMSE 做指标时更看重拟合精度用 MAE 更看重整体偏差的中位数表现选哪个取决于你的业务是怕偶尔的大偏差还是怕整体系统性偏差。from sklearn.model_selection import GridSearchCV, KFold # 分类两个参数 cv_cls GridSearchCV( SVC(kernelrbf, probabilityFalse, class_weightbalanced), {C: [0.1, 1, 10, 100], gamma: [scale, 0.01, 0.05, 0.2]}, scoringf1, cvKFold(5, shuffleTrue, random_state42), n_jobs-1) # 回归三个参数网格要收窄否则组合爆炸 cv_reg GridSearchCV( SVR(kernelrbf), {C: [1, 10, 100], gamma: [scale, 0.01, 0.05], epsilon: [0.05, 0.1, 0.3]}, scoringneg_mean_absolute_error, cvKFold(5, shuffleTrue, random_state42), n_jobs-1) cv_cls.fit(Xc_tr, yc_tr) cv_reg.fit(Xr_tr, yr_tr_s) print(分类最优:, cv_cls.best_params_, cv_cls.best_score_) print(回归最优:, cv_reg.best_params_, cv_reg.best_score_)回归侧 3×3×3 27 组每组 5 折就是 135 次训练。样本量上万时这会很慢所以我的习惯是先用粗网格定位大致区域再在最优值附近做一轮细网格。这比一次性铺大网格的效率高很多。5. 踩过的坑真实数据上的典型翻车现场5.1 SVR 的向均值收缩一条几乎是直线的预测这是我见过最频繁的 SVR 翻车现场训练完看 R²居然只有 0.1 甚至负数画图一看预测值几乎是一条水平线紧贴着 y 的均值。新手第一反应是数据没规律实际上十有八九是三个原因之一。第一个原因是 epsilon 设得太大。如果你忘了标准化 y而 y 的量纲是几万你随手写的 epsilon0.1 反而没问题但如果 y 已经标准化到均值 0 方差 1而 epsilon 还是设成 1.0那等于允许误差达到一个标准差模型自然什么都不用做就能把损失压到零。第二个原因是 C 太小模型没有动力去拟合管道外的点。第三个原因是 gamma 太小RBF 核的宽度太大整个空间被平滑成一个常数。排查顺序我建议固定成先确认 y 的尺度与 epsilon 是否匹配再检查 best_params_ 里 C 是不是撞到了搜索区间的下界。如果 C 恰好是网格里的最小值说明搜索区间设错了应该往下再扩一档。这个检查动作只需要一行代码但能省掉半天瞎调参。5.2 类别不平衡时暴力调 C 的无效循环分类侧有个经典误区少数类召回率低就不断加大 C。结果往往是整体准确率上去了少数类的 F1 反而更差因为 C 变大让模型更倾向于把边界附近的样本都判给多数类以减少总体的违规数。真正的解法有两步先用class_weightbalanced在损失层面修正再用 F1 或 AUC 而不是准确率来做模型选择。如果数据极度不平衡比如 1:100SVM 的整体收益会明显下降这时候换成树模型会更省心。还有一个容易被忽略的点SVC 默认用的是 one-vs-one 多分类策略类别多的时候需要训练 n(n-1)/2 个二分类器。10 个类别就是 45 个模型训练时间和内存都会明显膨胀。类别数超过 10 的情况下我一般直接换LinearSVC或者别的模型而不是硬扛。5.3 数据量一大训练时间就不是线性的SVC 和 SVR 底层都是 libsvm 那套实现训练复杂度大致在 O(n²) 到 O(n³) 之间n 是样本数。这个增长曲线在小样本时看不出来一旦跨过某个临界点就突然变得无法忍受。我自己的体感经验是n 在几千以内随便调网格都很快n 到两三万一次训练就要几十秒五折网格搜索直接变成整个下午n 到十万以上基本就不用考虑核方法了。替代方案是明确的分类换LinearSVC或SGDClassifier回归换LinearSVR或SGDRegressor它们用的是线性核和坐标下降或随机梯度复杂度接近线性。代价是丢掉 RBF 核的非线性表达能力但如果你的特征是稠密的高维数据比如文本的 TF-IDF线性核往往本来就够用甚至效果更好。另外LinearSVR的 epsilon 语义和 SVR 一致但它的默认max_iter比较小数据稍大就会报收敛警告。我在上面的代码里显式设成了 20000这是从多次报错里总结出来的一个比较通用的值。收到收敛警告时不要直接忽略先看系数有没有收敛否则结果可能完全不可信。5.4 概率输出和预测区间被误用最后一个坑更隐蔽把 SVC 的predict_proba当成真实概率用。SVM 本身输出的是到超平面的距离不是概率sklearn 里的概率是通过 Platt 缩放或者内部交叉验证拟合出来的在小样本上偏差可能很大。如果你的业务需要可靠的概率比如风控打分要么做后续的校准要么换用天然输出概率的模型。SVR 这边对应的坑是把预测值当成有置信区间的估计。SVR 只给你一个点预测它不提供预测方差。想要区间得用分位数回归、集成模型的方差估计或者干脆训练多个模型看输出的离散程度。我见过有人拿 SVR 的输出直接乘以 0.9 和 1.1 当上下界这在业务上是非常危险的。6. 选型清单什么时候用 SVM什么时候用 SVR什么时候都别用6.1 按数据规模和特征维度分数据规模是第一道筛子。样本量在一万以内、特征维度几十到几千这两个模型都在舒适区样本量超过五万优先考虑线性变体超过十万直接换梯度提升树或线性模型。特征维度方面SVM 和 SVR 在样本数少于特征数的场景下有天然优势因为它们的是通过支持向量而非全部样本定义决策面泛化能力不容易被维度拖垮。文本分类就是典型例子TF-IDF 特征动辄几万维样本只有几千条线性 SVM 在这个场景里长期是强基线。但要注意高维稀疏特征下 RBF 核通常不如线性核。原因很实际稀疏向量之间的欧氏距离区分度很差RBF 核算出来的相似度都挤在一起模型学不到东西。所以文本场景我基本不试 RBF直接用 LinearSVC。6.2 按业务需求的容错性分如果你的业务能明确说出误差多少以内无所谓那 SVR 值得优先尝试因为 epsilon 就是这个容忍度的直接映射模型会主动忽略这个范围内的偏差把注意力放在大的偏差上。这类场景包括需求预测、库存预估、能耗预测——这些领域里预测偏几十件、几度电本来就不影响决策。反过来如果业务要求每个样本都尽量拟合准比如做物理仿真替代模型、做精密标定那 SVR 的容错带反而变成缺点最小二乘或者高斯过程回归更合适。分类侧类似如果类别边界模糊、噪声大SVM 的最大间隔特性会带来不错的泛化如果类别界限清晰且数据量很大用 SVM 就是杀鸡用牛刀还会拖慢整个流水线。6.3 我自己的取舍习惯总结成我实际工作中的几条判断习惯不一定对所有人适用但至少可复现小样本、非线性、噪声大、且我关心的是排序或分类边界先上 SVM用 RBF 核加class_weightbalanced。小样本、连续目标、有明确误差容忍区间先上 SVRy 做标准化epsilon 按容忍度折算。样本量过万先把线性变体跑一遍当基线确认核方法带来的提升值不值得那份训练时间。只要开始出现预测值贴着均值或者支持向量占比超过 70%立刻回头检查 epsilon、C、gamma 三者的量纲和尺度不要在评估指标上纠结。网格搜索的评价指标永远和业务对齐分类用 F1 或 AUC回归用 MAE 或 RMSE不用默认的 accuracy 和 R²。最后分享一个我在调 SVR 时常用的低成本技巧先固定 gammascale只对 C 和 epsilon 做二维网格找到大致区域之后再放开 gamma 做一轮细化。因为 gamma 主要影响曲线的弯曲能力而 C 和 epsilon 影响的是紧不紧这两类问题的可分离性比三个参数一起搜要好得多实测能少走很多弯路。