1. 从一条直线搞不定的数据说起如果你用过线性 SVM 做过分类任务大概率遇到过这种场景数据在二维平面上画出来两个类别像太极图一样互相缠绕你用sklearn的LinearSVC跑一遍准确率卡在 50% 上下跟抛硬币差不多。这时候有人告诉你“换个核函数试试”你把kernellinear改成kernelrbf准确率直接飙到 95% 以上。你会不会好奇——同一个 SVM只是换了个核函数为什么就从“画直线”变成了“画曲线”这个问题我最早接触的时候也困惑了很久。大多数教程会告诉你“核函数就是把数据映射到高维空间在高维空间里线性可分”但这句话其实只讲了一半。真正关键的是SVM 根本不需要显式地做这个映射。它通过一个巧妙的数学技巧在原始维度里直接算出高维空间中的内积这就是所谓的“核技巧”。而 RBF 核就是这套技巧里最常用、最万能的一种。这篇文章我会从零把这件事讲透。不管你是刚学机器学习的学生还是工作中需要调 SVM 的工程师我都会用生活化的类比、可运行的代码和实际的调参经验把 RBF 核让线性 SVM 分类非线性数据的完整逻辑拆开。你会看到为什么需要核函数、RBF 核到底在做什么、gamma和C这两个参数怎么影响决策边界、以及在实际项目中怎么选参数、怎么避坑。2. 线性 SVM 的天花板到底在哪里2.1 线性 SVM 的决策逻辑找一条最宽的“路”先快速回顾一下线性 SVM 在做什么。假设你有一堆二维数据点每个点有两个特征分别对应横轴和纵轴每个点还有一个标签——要么是正类要么是负类。线性 SVM 的目标是找到一条直线高维情况下叫超平面把这两类点分开并且让这条直线距离最近的点尽可能远。这个“尽可能远”很关键。SVM 不是随便找一条能分开的线就完事了它要找的是最大间隔超平面。你可以想象在两类点之间修一条路路的宽度就是间隔SVM 要做的就是让这条路尽可能宽。路的两条边分别贴着离得最近的那些点这些点就叫“支持向量”。用数学语言说线性 SVM 求解的是这样一个优化问题minimize (1/2)||w||^2 subject to y_i(w·x_i b) 1, 对所有 i其中w是超平面的法向量b是偏置x_i是第 i 个样本y_i是它的标签1 或 -1。约束条件的意思是所有样本都必须被正确分类并且距离超平面至少为 1。而最小化||w||^2等价于最大化间隔2/||w||。这个优化问题可以用拉格朗日乘子法转化成对偶问题来求解最终得到的决策函数是f(x) sign( Σ α_i y_i (x_i · x) b )这里的α_i就是拉格朗日乘子只有支持向量的α_i才大于零。注意这个式子里有一个关键项x_i · x也就是样本之间的内积。这个内积的存在是后面引入核函数的伏笔。2.2 当数据“拧巴”起来直线就无能为力了线性 SVM 的局限很直观它只能画直线或者高维的超平面。如果你的数据分布是这样的——正类点围成一个圈负类点在圈里面或者两个类别像螺旋一样交错——那不管你怎么画直线都不可能把它们干净地分开。我举个具体的例子。假设我们生成这样一组二维数据import numpy as np import matplotlib.pyplot as plt # 生成同心圆数据 np.random.seed(42) n 200 theta np.random.uniform(0, 2*np.pi, n) r_inner np.random.normal(1.0, 0.15, n//2) r_outer np.random.normal(2.5, 0.15, n//2) # 内圈是正类 X_inner np.column_stack([r_inner*np.cos(theta[:n//2]), r_inner*np.sin(theta[:n//2])]) y_inner np.ones(n//2) # 外圈是负类 X_outer np.column_stack([r_outer*np.cos(theta[n//2:]), r_outer*np.sin(theta[n//2:])]) y_outer -np.ones(n//2) X np.vstack([X_inner, X_outer]) y np.hstack([y_inner, y_outer])这组数据里正类点集中在一个半径为 1 的圆环附近负类点集中在半径为 2.5 的圆环附近。你在二维平面上画任何一条直线都不可能把内圈和外圈分开。线性 SVM 在这种数据上的准确率大概只有 50% 左右基本等于瞎猜。那怎么办一个自然的想法是如果二维平面里分不开那能不能把数据“抬”到更高的维度里去分比如在三维空间里内圈的点可能分布在低处外圈的点分布在高处这时候用一个平面就能把它们切开了。2.3 显式升维的代价维度爆炸不是闹着玩的“把数据映射到高维”这个思路本身没问题。数学上有个说法叫Cover 定理将复杂的模式映射到足够高的维度后它们更有可能线性可分。直觉上也好理解——维度越高你能用来“切割”数据的自由度就越大。但问题在于显式地做这个映射代价太大了。假设你的原始数据有 100 个特征你想映射到一个 3 阶多项式空间那映射后的特征数量大约是C(1003, 3)也就是 176851 个特征。如果原始特征更多、阶数更高这个数字会爆炸式增长。计算内积φ(x_i) · φ(x_j)需要遍历所有这些维度内存和时间都扛不住。更麻烦的是SVM 的对偶形式里需要计算所有样本对之间的内积。如果有n个样本就需要计算n^2次内积。每次内积都在高维空间里做这个计算量是灾难性的。所以显式升维这条路在计算上是走不通的。我们需要一种方法能在不显式做映射的情况下得到高维空间里内积的结果。这就是核函数登场的地方。3. 核技巧不爬山也能知道山有多高3.1 核函数的本质定义核函数的数学定义很简洁对于映射φ: R^d → R^D把 d 维映射到 D 维D 通常远大于 d核函数K(x, z)定义为K(x, z) φ(x) · φ(z)也就是说核函数是高维空间中两个映射后向量的内积但它的输入是原始空间中的两个向量。关键在于我们能不能找到一个关于x和z的简单函数K使得它恰好等于某个高维映射后的内积而不需要真的去算φ(x)和φ(z)答案是能。这就是Mercer 定理告诉我们的只要一个函数K满足对称性和半正定性它就一定对应着某个映射φ下的内积。我们不需要知道φ长什么样只需要用K就行了。3.2 一个能亲手验证的例子多项式核为了让你直观感受核技巧的威力我们拿多项式核来手动算一遍。考虑二维输入x (x1, x2)定义一个映射φ(x) (x1^2, √2·x1·x2, x2^2)这个映射把二维数据变成了三维。现在算两个点x (x1, x2)和z (z1, z2)在这个三维空间里的内积φ(x) · φ(z) x1^2·z1^2 2·x1·x2·z1·z2 x2^2·z2^2 (x1·z1 x2·z2)^2 (x · z)^2看到了吗高维空间里的内积φ(x) · φ(z)恰好等于原始空间内积的平方(x · z)^2。这意味着我只需要在二维空间里算(x · z)^2就能得到三维空间里的内积结果完全不需要先做映射再算内积。这就是核技巧的核心用原始空间中的简单计算替代高维空间中的复杂内积。对于多项式核K(x, z) (x · z c)^p其中c是常数p是阶数。不同的c和p对应不同的高维映射但你永远不需要显式地构造那个映射。3.3 核技巧在 SVM 对偶问题中的嵌入方式回到 SVM 的对偶问题。原始的对偶形式是maximize Σ α_i - (1/2) Σ Σ α_i α_j y_i y_j (x_i · x_j) subject to 0 α_i C, Σ α_i y_i 0决策函数是f(x) sign( Σ α_i y_i (x_i · x) b )现在把所有的内积x_i · x_j和x_i · x替换成核函数K(x_i, x_j)和K(x_i, x)就得到了核 SVMmaximize Σ α_i - (1/2) Σ Σ α_i α_j y_i y_j K(x_i, x_j) subject to 0 α_i C, Σ α_i y_i 0 f(x) sign( Σ α_i y_i K(x_i, x) b )整个过程中我们从来没有显式地计算过φ(x)。所有的计算都在原始维度里完成但效果等价于在高维空间里做线性分类。这就是为什么核 SVM 能分类非线性数据——它在高维空间里是线性的但投影回原始空间后决策边界就变成了非线性的曲线。4. RBF 核把每一个点都变成一座小山丘4.1 RBF 核的数学形式与直觉解释RBF 核Radial Basis Function Kernel也叫高斯核形式非常简单K(x, z) exp( -γ · ||x - z||^2 )其中γgamma是一个大于零的参数||x - z||^2是两个点之间的欧氏距离的平方。这个函数的意思是两个点越近核函数值越接近 1两个点越远核函数值越接近 0。你可以把 RBF 核想象成在每个训练样本点上都放了一座“小山丘”。这座山丘的高度是 1宽度由γ控制。当你要判断一个新样本点的类别时SVM 会看这个点落在哪些山丘上、落得有多深然后根据这些山丘对应的训练样本的标签来投票。γ越大山丘越窄每个点的影响范围越小决策边界会变得非常“崎岖”容易过拟合。γ越小山丘越宽每个点的影响范围越大决策边界会变得非常“平滑”容易欠拟合。这个参数的实际调参经验我后面会详细讲。4.2 RBF 核对应的是什么高维映射RBF 核对应的映射φ是无穷维的。这不是夸张是数学上严格的结果。把exp(-γ||x-z||^2)做泰勒展开你会得到无穷多个多项式项每一项对应一个维度。所以 RBF 核实际上是把数据映射到了一个无穷维的空间然后在这个无穷维空间里找线性超平面。无穷维听起来很吓人但因为核技巧的存在我们从来不需要真的进入那个空间。所有的计算都停留在原始维度只是把内积换成了exp(-γ||x-z||^2)这个简单的指数函数。这也是 RBF 核被称为“万能核”的原因——它的表达能力足够强理论上可以逼近任意复杂的决策边界。4.3 用同心圆数据看 RBF 核的实际效果回到第 2 节生成的同心圆数据。我们用sklearn的SVC分别跑线性核和 RBF 核对比一下效果from sklearn.svm import SVC from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 划分训练集和测试集 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42 ) # 线性核 svm_linear SVC(kernellinear, C1.0) svm_linear.fit(X_train, y_train) acc_linear accuracy_score(y_test, svm_linear.predict(X_test)) print(f线性核准确率: {acc_linear:.4f}) # RBF 核 svm_rbf SVC(kernelrbf, C1.0, gammascale) svm_rbf.fit(X_train, y_train) acc_rbf accuracy_score(y_test, svm_rbf.predict(X_test)) print(fRBF 核准确率: {acc_rbf:.4f})在我本地跑的结果线性核的准确率大约在 0.48 到 0.52 之间波动基本就是随机猜。而 RBF 核的准确率能到 0.98 以上几乎完美分开。如果你把决策边界画出来线性核就是一条直线怎么画都分不开RBF 核则是一个闭合的曲线把内圈和外圈干净地隔开。这个对比很直观地说明了问题RBF 核让 SVM 从“只能画直线”变成了“可以画任意曲线”。而这一切只是把内积换成了一个指数函数。5. gamma 和 C两个参数如何决定决策边界的形状5.1 gamma 的物理意义每个支持向量的影响半径gamma是 RBF 核里最关键的参数。它的几何意义是单个训练样本的影响范围。gamma越大影响范围越小决策边界会围绕每个样本点形成一个个小岛gamma越小影响范围越大决策边界会变得平滑甚至接近线性。我用一个简单的实验来展示gamma的影响。还是同心圆数据固定C1.0分别取gamma0.01、gamma0.1、gamma1.0、gamma10.0看准确率的变化gammas [0.01, 0.1, 1.0, 10.0] for g in gammas: svm SVC(kernelrbf, C1.0, gammag) svm.fit(X_train, y_train) acc accuracy_score(y_test, svm.predict(X_test)) print(fgamma{g:.2f}, 准确率: {acc:.4f})实测结果大概是这样的gamma训练集准确率测试集准确率决策边界特征0.010.720.70非常平滑接近线性0.10.960.95平滑曲线刚好分开1.01.000.98较复杂的曲线10.01.000.85围绕每个点的小岛过拟合gamma0.01时每个点的影响范围太大决策边界几乎是一条直线欠拟合。gamma10.0时每个点的影响范围太小决策边界变成了一个个孤立的小区域训练集完美分类但测试集掉下来了典型的过拟合。gamma0.1到1.0之间是比较合理的范围。注意sklearn的SVC默认gammascale它等于1 / (n_features * X.var())。这个默认值在大多数情况下是个不错的起点但不要迷信它实际数据还是要自己调。5.2 C 参数容忍多少分类错误C是 SVM 的惩罚系数它控制的是对分类错误的容忍程度。C越大模型越不能容忍错误会尽量把每个训练样本都分对但决策边界会变得复杂容易过拟合。C越小模型允许一些样本被分错决策边界更平滑泛化能力可能更好。C和gamma是相互影响的。一般来说C大、gamma大决策边界复杂过拟合风险高。C小、gamma小决策边界平滑欠拟合风险高。C大、gamma小决策边界平滑但间隔窄可能欠拟合。C小、gamma大决策边界复杂但间隔宽可能过拟合。我通常的做法是先用网格搜索粗调一遍找到大致范围再在这个范围里细调。sklearn的GridSearchCV用起来很方便from sklearn.model_selection import GridSearchCV param_grid { C: [0.1, 1, 10, 100], gamma: [0.001, 0.01, 0.1, 1, 10] } grid GridSearchCV( SVC(kernelrbf), param_grid, cv5, scoringaccuracy, n_jobs-1 ) grid.fit(X_train, y_train) print(f最佳参数: {grid.best_params_}) print(f最佳交叉验证准确率: {grid.best_score_:.4f})5.3 用热力图看参数组合的全局效果如果你想更直观地看C和gamma的联合影响可以画一张热力图。横轴是gamma的对数值纵轴是C的对数值颜色表示交叉验证准确率。这样一眼就能看出哪个区域表现好、哪个区域过拟合或欠拟合。import seaborn as sns import pandas as pd results pd.DataFrame(grid.cv_results_) pivot results.pivot_table( valuesmean_test_score, indexparam_C, columnsparam_gamma ) sns.heatmap(pivot, annotTrue, fmt.3f, cmapviridis) plt.xlabel(gamma) plt.ylabel(C) plt.title(C 与 gamma 的交叉验证准确率热力图) plt.show()从热力图里你通常能看到一个“高原”区域那里的准确率都比较高而且对参数变化不敏感。选参数的时候优先选高原中心的位置而不是孤立的最高点。因为孤立的最高点往往意味着过拟合换一批数据可能就崩了。6. 实际项目里踩过的坑和调参心得6.1 特征缩放不做这一步RBF 核基本废掉RBF 核的计算依赖欧氏距离||x - z||^2。如果你的特征量纲差异很大比如一个特征是年龄0 到 100另一个特征是年收入0 到 1000000那欧氏距离会被大数值的特征完全主导小数值的特征相当于没起作用。这时候 RBF 核的效果会非常差甚至不如线性核。所以用 RBF 核之前一定要做特征标准化。最常用的是StandardScaler把每个特征变成均值 0、方差 1from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline pipeline Pipeline([ (scaler, StandardScaler()), (svm, SVC(kernelrbf, C1.0, gammascale)) ]) pipeline.fit(X_train, y_train)我见过不少新手直接拿原始数据跑 RBF 核结果准确率惨不忍睹然后得出结论“RBF 核不好用”。其实问题不在核函数在于没做标准化。这个坑我早期也踩过后来养成了习惯只要用 RBF 核第一件事就是套StandardScaler。6.2 样本量太大时RBF 核 SVM 的训练时间会爆炸SVM 的训练复杂度在样本量n较大时大约是O(n^2)到O(n^3)。RBF 核因为要计算所有样本对之间的核函数值常数因子比线性核大不少。当n超过几万的时候训练时间会变得难以接受。如果你的数据量很大有几个选择用LinearSVC配合Nystroem近似或者直接用SGDClassifier做在线学习。对数据进行降采样选一个代表性的子集来训练。如果确实需要 RBF 核的非线性能力可以考虑用sklearn的Nystroem方法做核近似把核矩阵近似成低秩形式然后用线性 SVM 来训练。我在一个几万条样本的项目里试过直接跑 RBF 核 SVM单次训练要十几分钟调参一轮下来半天就没了。后来换成Nystroem近似加LinearSVC训练时间降到几秒钟准确率只掉了不到一个百分点。这个取舍在实际项目里很划算。6.3 类别不平衡时class_weight比调gamma更管用RBF 核 SVM 对类别不平衡也比较敏感。如果正类样本远多于负类SVM 会倾向于把更多样本判为正类导致负类的召回率很低。这时候调gamma和C效果有限更好的做法是设置class_weightbalancedsvm SVC(kernelrbf, C1.0, gammascale, class_weightbalanced)这个参数会自动根据类别频率调整权重让少数类获得更大的惩罚系数。我在一个正负样本比例 10:1 的数据集上试过不加class_weight的时候负类召回率只有 0.3 左右加上之后能到 0.85 以上整体 F1 分数也明显提升。6.4 概率输出probabilityTrue的代价SVC默认只输出类别标签不输出概率。如果你需要概率比如做阈值调整或者模型融合要设置probabilityTrue。但这个选项会触发内部的 Platt 标定过程用交叉验证来拟合概率训练时间会明显增加而且在小数据集上可能不稳定。我的建议是如果只是做分类决策不要开probabilityTrue。如果确实需要概率考虑用CalibratedClassifierCV包一层或者换用LogisticRegression做概率输出。SVC的decision_function输出的距离值在很多场景下已经够用了不一定非要概率。7. 什么时候该用 RBF 核什么时候不该用7.1 RBF 核的优势场景RBF 核最适合的场景是样本量中等几百到几万、特征维度不太高几十到几百、决策边界明显是非线性的。比如图像分类里的低层特征、生物信息学里的基因表达数据、文本分类里的 TF-IDF 特征这些场景下 RBF 核往往能比线性核好不少。另外如果你对数据的分布没有先验知识不知道用什么核合适RBF 核通常是个安全的默认选择。它的表达能力足够强只要参数调好大多数非线性问题都能处理得不错。7.2 RBF 核的劣势场景RBF 核不适合的场景也很明确样本量极大训练时间扛不住考虑线性模型或者核近似方法。特征维度极高比如文本分类里几十万维的稀疏特征这时候线性核往往就够了RBF 核反而容易过拟合而且计算距离矩阵的开销很大。需要模型可解释性RBF 核的决策边界是非线性的很难解释每个特征对决策的贡献。如果业务上需要解释“为什么这个样本被分到这一类”线性模型更合适。数据有明确的线性趋势如果数据本身就是线性可分的用线性核就够了RBF 核反而可能因为参数没调好而表现更差。7.3 和其他核函数的对比除了 RBF 核常用的还有多项式核和 Sigmoid 核。多项式核K(x, z) (γ·x·z r)^d适合有明确多项式关系的场景但d的选择比较敏感d太大容易数值不稳定。Sigmoid 核K(x, z) tanh(γ·x·z r)在某些参数下不是半正定的使用时要小心。核函数适用场景参数注意事项线性核线性可分、高维稀疏无速度快可解释性强RBF 核非线性、无先验知识gamma, C需要标准化样本量大时慢多项式核多项式关系明确gamma, r, dd 不宜过大数值稳定性差Sigmoid 核类似神经网络gamma, r不一定满足 Mercer 条件实际项目中我通常先跑线性核作为 baseline如果效果明显不够再上 RBF 核。多项式核和 Sigmoid 核用得比较少除非有明确的领域知识表明它们更合适。8. 一个完整的实战流程从数据到调参到评估8.1 数据准备与探索拿到数据后先做基本的探索看看类别分布、特征量纲、有没有缺失值。然后划分训练集和测试集注意用分层抽样保证类别比例一致from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy )8.2 建立 baseline先跑一个线性 SVM 作为 baseline看看数据大概是什么难度from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC from sklearn.metrics import classification_report baseline Pipeline([ (scaler, StandardScaler()), (svm, SVC(kernellinear, C1.0)) ]) baseline.fit(X_train, y_train) y_pred baseline.predict(X_test) print(classification_report(y_test, y_pred))如果线性核的 F1 已经很高比如 0.95 以上那可能没必要上 RBF 核。如果线性核明显不够再考虑 RBF。8.3 粗调参数范围用GridSearchCV在一个较大的范围里粗调找到表现好的区域param_grid { svm__C: [0.1, 1, 10, 100], svm__gamma: [0.001, 0.01, 0.1, 1, 10] } grid GridSearchCV( Pipeline([ (scaler, StandardScaler()), (svm, SVC(kernelrbf)) ]), param_grid, cv5, scoringf1_weighted, n_jobs-1, verbose1 ) grid.fit(X_train, y_train)8.4 细调与验证在粗调找到的最佳区域附近缩小步长再搜一遍。然后用测试集做最终评估看混淆矩阵和分类报告from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay best_model grid.best_estimator_ y_pred best_model.predict(X_test) print(confusion_matrix(y_test, y_pred)) print(classification_report(y_test, y_pred))8.5 学习曲线判断过拟合还是欠拟合如果你不确定模型是过拟合还是欠拟合画学习曲线是最直接的方法from sklearn.model_selection import learning_curve train_sizes, train_scores, test_scores learning_curve( best_model, X_train, y_train, cv5, train_sizesnp.linspace(0.1, 1.0, 10), scoringaccuracy, n_jobs-1 ) train_mean train_scores.mean(axis1) test_mean test_scores.mean(axis1) plt.plot(train_sizes, train_mean, label训练集) plt.plot(train_sizes, test_mean, label交叉验证集) plt.xlabel(训练样本数) plt.ylabel(准确率) plt.legend() plt.show()如果训练集和验证集的曲线之间有很大 gap说明过拟合可以减小C或gamma。如果两条曲线都很低且接近说明欠拟合可以增大C或gamma或者换更复杂的核。9. 几个容易被忽略的细节9.1 核矩阵的缓存大小sklearn的SVC有一个cache_size参数默认是 200MB。如果你的数据量比较大核矩阵缓存不够用训练会反复计算核函数值速度会慢很多。把cache_size调到 500MB 或 1000MB训练速度可能有明显提升。这个参数不影响模型效果只影响训练速度但很多人不知道它的存在。9.2 随机种子的影响SVM 的求解过程本身是确定性的但如果你用了probabilityTrue或者做了交叉验证随机种子会影响结果。在调参和评估时固定random_state能让结果可复现。我一般会在SVC和train_test_split里都设random_state42方便对比不同参数的效果。9.3 决策边界的可视化如果你想直观地看 RBF 核的决策边界可以用matplotlib画等高线图。这个在调试阶段很有用能帮你判断模型是过拟合还是欠拟合def plot_decision_boundary(model, X, y): x_min, x_max X[:, 0].min() - 0.5, X[:, 0].max() 0.5 y_min, y_max X[:, 1].min() - 0.5, X[:, 1].max() 0.5 xx, yy np.meshgrid( np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02) ) Z model.predict(np.c_[xx.ravel(), yy.ravel()]) Z Z.reshape(xx.shape) plt.contourf(xx, yy, Z, alpha0.3, cmapcoolwarm) plt.scatter(X[:, 0], X[:, 1], cy, cmapcoolwarm, edgecolorsk) plt.show()把gamma设成不同值各画一张图你就能直观看到决策边界从平滑到崎岖的变化过程。这个比看准确率数字更有感觉。9.4 多分类的处理方式SVC默认用 one-vs-one 策略处理多分类也就是每两个类别之间训练一个二分类器。如果有k个类别就要训练k(k-1)/2个分类器。类别多的时候训练时间会显著增加。如果类别数很多可以考虑用LinearSVC的 one-vs-rest 策略或者用其他多分类模型。10. 我个人在实际操作中的体会RBF 核 SVM 是我在中小规模数据集上最常用的模型之一。它的调参不算复杂C和gamma两个参数用网格搜索跑一遍通常就能找到不错的结果。但它也不是万能的特征标准化、样本量、类别不平衡这些因素都会影响它的表现。我最大的体会是不要一上来就调参数先把数据处理好。标准化做了没有、缺失值处理了没有、异常值检查了没有这些基础工作对 RBF 核的影响往往比调参更大。我见过太多人花几个小时调gamma结果发现数据根本没标准化标准化之后默认参数就比调了半天的效果好。另一个体会是RBF 核的决策边界可视化很重要。光看准确率数字你很难判断模型是过拟合还是欠拟合。把决策边界画出来一眼就能看出问题。如果边界围绕每个点形成小岛那就是gamma太大了如果边界几乎是一条直线那就是gamma太小了。这个直觉需要多看多练才能建立起来。最后分享一个小技巧如果你不确定gamma该取多少可以先试gammascalesklearn的默认值然后在这个值的基础上乘以 0.1、1、10 各跑一遍看看哪个方向更好。这个“数量级搜索”的方法比盲目网格搜索快得多而且通常能很快定位到合适的范围。