详解支持向量机-选取与核函数相关的参数:degree & gamma & coef0【菜菜的sklearn课堂笔记】

时间:2022-11-25 11:03:46

视频作者:[菜菜TsaiTsai] 链接:[【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili]

之前的表格

输入 含义 解决问题 核函数表达式 参数gamma 参数degree 参数coef0
linear 线性核 线性 $K(x,y)=x^{T}y=x \cdot y$
poly 多项式核 偏线性 $K(x,y)=(\gamma(x \cdot y)+r)^{d}$
sigmoid 双曲正切核 非线性 $K(x,y)=\tanh(\gamma (x \cdot y)+r)$
rbf 高斯径向基 偏非线性 $K(x,y)=e^{-\gamma|x-y|^{2}},\gamma>0$

对于线性核函数,"kernel"是唯一能够影响它的参数,但是对于其他三种非线性核函数,他们还受到参数gamma,degree以及coef0的影响。 参数gamma就是表达式中的$\gamma$,degree就是多项式核函数的次数$d$,参数coef0就是常数项$r$。其中,高斯径向量核函数受到gamma的影响,而多项式核函数受到三个参数的影响

参数 含义
degree 整数,可不填,默认3<br>多项式核函数的次数,如果核函数没有该参数将被忽略
gamma 浮点数,可不填,默认auto<br>核函数的系数,仅在参数Kernel的选项为rbf,poly,sigmoid的时候有效<br>输入auto,自动使用$\begin{aligned} \frac{1}{n_features}\end{aligned}$作为gamma的取值<br>输入scale,则使用$\begin{aligned} \frac{1}{n_{feature}\times X.std()}\end{aligned}$作为gamma的取值<br>输入auto_deprecated,则表示没有传递明确的gamma值(不推荐使用)
coef0 浮点数,可不填,默认=0.0<br>核函数中的常数项,它只在参数Kernel为poly和sigmoid的时候有效

但从核函数的公式来看,我们其实很难去界定具体每个参数如何影响了SVM的表现。当gamma的符号变化,或者degree的大小变化时,核函数本身甚至都不是永远单调的。所以如果我们想要彻底地理解这三个参数,我们要先推导出它们如何影响核函数地变化,再找出核函数的变化如何影响了我们的预测函数(可能改变我们的核变化所在的维度),再判断出决策边界随着预测函数的改变发生了怎样的变化。无论是从数学的角度来说还是从实践的角度来说,这个过程太复杂也太低效。所以,我们往往避免去真正探究这些参数如何影响了我们的核函数,而直接使用学习曲线或者网格搜索来帮助我们查找最佳的参数组合。 对于高斯径向基核函数,调整gamma的方式其实比较容易,那就是画学习曲线。我们来试试看高斯径向基核函数rbf的参数gamma在乳腺癌数据集上的表现:

score = []
gamma_range = np.logspace(-10,1,50)
for i in gamma_range:
    clf = SVC(kernel="rbf",gamma=i,cache_size=5000).fit(Xtrain,Ytrain)
    score.append(clf.score(Xtest,Ytest))
print(max(score),gamma_range[score.index(max(score))])
---
0.9766081871345029 0.012067926406393264

plt.plot(gamma_range,score)
plt.show()

详解支持向量机-选取与核函数相关的参数:degree & gamma & coef0【菜菜的sklearn课堂笔记】

np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
# 生成对数等比数列
# 大概步骤,先将[start,stop]等分num份,得到每个值i,然后计算10^i的值
# 注意是分割[start,stop]的时候等差,因为需要计算10^i,输出等比

np.logspace(-10,1,50)
---
array([1.00000000e-10, 1.67683294e-10, 2.81176870e-10, 4.71486636e-10,……, 1.00000000e+01])

(10**1,1.00000000e+01),(10**-10,1.00000000e-10)
# 1e+01可以理解为1*10^+1,负数同理
---
((10, 10.0), (1e-10, 1e-10))

通过学习曲线,很容就找出了rbf的最佳gamma值。但我们观察到,这其实与线性核函数的准确率一模一样之前的准确率。我们可以多次调整gamma_range来观察结果,可以发现97.6608应该是rbf核函数的极限了。 但对于多项式核函数来说,因为三个参数共同作用在一个数学公式上影响它的效果,因此我们往往使用网格搜索来共同调整三个对多项式核函数有影响的参数。依然使用乳腺癌数据集。

from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.model_selection import GridSearchCV

time0 = time()

gamma_range = np.logspace(-10,1,20)
coef0_range = np.linspace(0,5,10) # coef不接收负数
# 因为我们已经知道多项式核函数的degree为1,因此不需要进行网格搜索
param_grid = dict(gamma = gamma_range
                 ,coef0 = coef0_range)
cv = StratifiedShuffleSplit(n_splits=5,test_size=0.3,random_state=420)
# n_splits:将数据集分5次
# test_size:测试集大小
grid = GridSearchCV(SVC(kernel="poly",degree=1,cache_size=5000)
                   ,param_grid=param_grid
                   ,cv=cv
                   )
grid.fit(X,y)
print("The best parameters are %s with a score of %0.5f" % (grid.best_params_,grid.best_score_))
print(datetime.datetime.fromtimestamp(time() - time0).strftime("%M:%S:%f"))
---
The best parameters are {'coef0': 0.0, 'gamma': 0.18329807108324375} with a score of 0.96959
00:07:456977

可以发现,网格搜索为我们返回的整体分数是0.96959,虽然比调参前略有提高,但依然没有超过线性核函数核和rbf的结果。可见,如果最初选择核函数的时候,你就发现多项式的结果不如rbf和线性核函数,那就不要挣扎了,试试看调整rbf或者直接使用线性。

关于几种交叉验证

KFold K折交叉验证: 进行多次train_test_split划分。每次划分时,在不同的数据集上进行训练、测试评估,从而得出一个评价结果;如果是5折交叉验证,意思就是在原始数据集上,进行5次划分,每次划分进行一次训练、评估,最后得到5次划分后的评估结果,一般在这几次评估结果上取平均得到最后的评分。这也是cross_val_score默认的方法 详解支持向量机-选取与核函数相关的参数:degree & gamma & coef0【菜菜的sklearn课堂笔记】

StratifiedKFold 分层交叉验证: StratifiedKFold是为分类问题设计的 KFold 版本。 在分类问题中,即使将数据拆分为多个集合,也必须保留目标分布。 简单的说就是分类目标的比例在进行分折后应该与原始数据相同,例如原始数据种A类占比30%,B类占比35%,C类占比35%,在我们分折以后,这个比例是不应该变化的。而使用StratifiedKFold就可以保证样本集与测试集不同类别的数据成比例 详解支持向量机-选取与核函数相关的参数:degree & gamma & coef0【菜菜的sklearn课堂笔记】

观察上面两个方法,明显可以发现,交叉验证中所有的测试集加和应该正好是一个全集,那么如果我们交叉验证测试足够大,测试集就可能过小而产生干扰,因此就有

ShuffleSplit 随机打乱交叉验证先根据随机数进行指定次的train_test_split,然后不同次的训练集测试集分别进行验证得到score,并进行平均。 优点是可以完全控制每个折中训练集和测试集的大小。 集合的大小不必与拆分的数量成反比。但是与其他拆分器相反,不能保证在每次随机拆分中样本不同。 详解支持向量机-选取与核函数相关的参数:degree & gamma & coef0【菜菜的sklearn课堂笔记】

StratifiedShuffleSplit 随机打乱分层交叉验证: 也就是ShuffleSplit用于分类的版本

在方法的参数中也有体现

KFold(n_splits='warn', shuffle=False, random_state=None)
# n_splits:交叉验证的次数
# 其实这里也有shuffle,但这里的shuffle与StratifiedShuffleSplit里的意义不同。例如如果设置shuffle=Falsh也就是默认值,进行3次K折验证,测试集第一次取前1/3,第二次取中间1/3,最后一次取剩余1/3;如果设置为True,每次取出的测试集总和仍然是全集的1/3,只是位置发生变化而已

详解支持向量机-选取与核函数相关的参数:degree & gamma & coef0【菜菜的sklearn课堂笔记】

StratifiedKFold(n_splits='warn', shuffle=False, random_state=None)
# 参数同KFold

ShuffleSplit(
    ['n_splits=10', "test_size='default'", 'train_size=None', 'random_state=None'],
)
# 对比前两个方法,这里多了个test_size和train_size,也就是说我们可以指定测试集和训练集的大小,就类似于我们使用train_test_splite方法
StratifiedShuffleSplit(
    ['n_splits=10', "test_size='default'", 'train_size=None', 'random_state=None'],
)
# 参数同ShuffleSplit

部分来源 作者:deephub 链接:5个常见的交叉验证技术介绍和可视化_deephub的博客-CSDN博客_五重交叉验证