写点什么

支持向量机 - 探索核函数的优势和缺陷

  • 2022-11-25
    山东
  • 本文字数:3253 字

    阅读完需:约 11 分钟

看起来,除了 Sigmoid 核函数,其他核函数效果都还不错。但其实 rbf 和 poly 都有自己的弊端,我们使用乳腺癌数据集作为例子来展示一下:


from sklearn.datasets import load_breast_cancerfrom sklearn.svm import SVCfrom sklearn.model_selection import train_test_splitimport matplotlib.pyplot as pltimport numpy as npfrom time import timeimport datetime # 将时间戳转化为真实地时间
data = load_breast_cancer()X = data.datay = data.target
X.shape---(569, 30)
np.unique(y)---array([0, 1])
复制代码


注意我们并不通过可视化数据集来选择核函数,而是直接尝试选择核函数(这里就很不合适,数据明明有 30 个维度,我们任意选择前两个维度,是没有道理的)

plt.scatter(X[:,0],X[:,1],c=y)
plt.show()

我们可以考虑降维,降维成二维

from sklearn.decomposition import PCA

X_dr = PCA(2).fit_transform(X)
plt.scatter(X_dr[:,0],X_dr[:,1],c=y,alpha=0.3)
plt.show()


Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=420)Kernel = ["linear","poly","rbf","sigmoid"]
# 注意以下这一段跑不出结果for kernel in Kernel: time0 = time() clf = SVC(kernel=kernel ,gamma="auto" # ,degree=1 # degree:核函数的次方数,默认是3 # 之前说过当degree为1的时候用于线性,高次用于非线性 # 但是之前使用默认值的时候跑了将近十分钟没有跑出poly的结果,放弃了 ,cache_size=5000 ).fit(Xtrain,Ytrain) # cache_size:表示允许使用多大的内存进行计算,单位MB。默认200 # 用的内存越多运行越快(蓝屏可能性越大) print("The accuracy under kernel %s is %f"%(kernel, clf.score(Xtest,Ytest))) print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))# 一般SVM不需要过长的时间,超过五六分钟不出结果基本就可以选择打断了---The accuracy under kernel linear is 0.92982500:00:396585
复制代码


关于 time()

now = time() # 返回一串浮点数,就是时间戳

datetime.datetime.fromtimestamp(now).strftime("%Y-%m-%d,%H:%M:%S:%f")
---
'2022-10-24,10:33:16:370524'


之前说到模型一直停留在线性核函数之后,就没有再打印结果了。这证明,多项式核函数此时此刻要消耗大量的时间,运算非常的缓慢。让我们在循环中去掉多项式核函数,再试试看能否跑出结果


Kernel = ["linear","rbf","sigmoid"] # 谁慢把谁删了for kernel in Kernel:    time0 = time()    clf = SVC(kernel=kernel             ,gamma="auto"            # ,degree=1              ,cache_size=5000             ).fit(Xtrain,Ytrain)    print("The accuracy under kernel %s is %f"%(kernel, clf.score(Xtest,Ytest)))    print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))    # 基本秒出,所以证明是多项式核函数阻碍了我们的运行---The accuracy under kernel linear is 0.92982500:00:405324The accuracy under kernel rbf is 0.59649100:00:038619The accuracy under kernel sigmoid is 0.59649100:00:006005
复制代码


我们可以有两个发现。首先,乳腺癌数据集是一个线性数据集,线性核函数跑出来的效果很好。rbf 和 sigmoid 两个擅长非线性的数据从效果上来看完全不可用。其次,线性核函数的运行速度远远不如非线性的两个核函数。


关于 rbf 不是应当适用于所有数据吗,这里别着急,接着往下看


如果数据是线性的,那如果我们把 degree 参数调整为 1,多项式核函数应该也可以得到不错的结果:


Kernel = ["linear","poly","rbf","sigmoid"]for kernel in Kernel:    time0 = time()    clf = SVC(kernel=kernel             ,gamma="auto"             ,degree=1              # 上面我们已经能看出,对于这个数据集,线性核比非线性核效果要好              # 因此我们可以考虑degree等于1,让多项式核函数运行线性结果              # 同时,加快多项式核函数的速度             ,cache_size=5000             ).fit(Xtrain,Ytrain)    print("The accuracy under kernel %s is %f"%(kernel, clf.score(Xtest,Ytest)))    print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))---The accuracy under kernel linear is 0.92982500:00:396625The accuracy under kernel poly is 0.92397700:00:075855The accuracy under kernel rbf is 0.59649100:00:039003The accuracy under kernel sigmoid is 0.59649100:00:005001
复制代码


多项式核函数的运行速度立刻加快了,并且精度也提升到了接近线性核函数的水平。但是,我们之前的实验中,我们了解说,rbf 在线性数据上也可以表现得非常好,那在这里,为什么跑出来的结果如此糟糕呢?其实,这里真正的问题是数据的量纲问题。回忆一下我们如何求解决策边界,如何判断点是否在决策边界的一边?是靠计算”距离“,虽然我们不能说 SVM 是完全的距离类模型,但是它严重受到数据量纲的影响。让我们来探索一下乳腺癌数据集的量纲:


import pandas as pd
data = pd.DataFrame(X)data.describe([0.01,0.05,0.1,0.25,0.5,0.75,0.9,0.99]).T# describe:对数据进行描述性分析# 接收数组,表示分位数# 看不同维度的均值和方差,看数据有量纲不统一# 观察1%和min,99%和max,看数据是否有偏态的问题---# 这里简述以下,打印出来太多了# 部分行均值在0.几,部分行甚至到达了几百将近一千,且这些均值大的数据方差也大,因此一定有量纲不统一的问题# 观察1%和min,99%和max。有一行99%还是177,到了max就是542,因此数据有偏态问题(偏态也就是非正态)
复制代码


对于量纲不统一我们可以考虑标准化


from sklearn.preprocessing import StandardScaler
X = StandardScaler().fit_transform(X)# 标准化,即均值为0,方差为1data = pd.DataFrame(X)data.describe([0.01,0.05,0.1,0.25,0.5,0.75,0.9,0.99]).T---# 此时数据均值基本接近0,方差接近1
复制代码


标准化完毕后,再次让 SVC 在核函数中遍历,此时我们把 degree 的数值设定为 1,观察各个核函数在去量纲后的数据上的表现:


Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=420)# 由于random_state=420没变,所以训练集测试集划分不变Kernel = ["linear","poly","rbf","sigmoid"]for kernel in Kernel:    time0 = time()    clf = SVC(kernel=kernel             ,gamma="auto"             ,degree=1             ,cache_size=5000             ).fit(Xtrain,Ytrain)    print("The accuracy under kernel %s is %f"%(kernel, clf.score(Xtest,Ytest)))    print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))    # 虽然这里看rbf表现没有linear好,但实际上linear没有参数可调,rbf可以调参,因此我们继续对rbf探索---The accuracy under kernel linear is 0.97660800:00:007997The accuracy under kernel poly is 0.96491200:00:006007The accuracy under kernel rbf is 0.97076000:00:006997The accuracy under kernel sigmoid is 0.95321600:00:004000
复制代码


量纲统一之后,可以观察到,所有核函数的运算时间都大大地减少了。其次,rbf 表现出了非常优秀的结果。经过我们的探索,我们可以得到的结论是:


  1. 线性核,尤其是多项式核函数在高次项时计算非常缓慢

  2. rbf 和多项式核函数都不擅长处理量纲不统一的数据集


这两个缺点都可以由数据无量纲化来解决。因此,SVM 执行之前,非常推荐先进行数据的无量纲化!虽然线性核函数的效果是最好的,但它是没有核函数相关参数可以调整的,rbf 和多项式却还有着可以调整的相关参数,接下来我们就来看看这些参数。


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


发布于: 刚刚阅读数: 3
用户头像

跃入人海 2022-09-14 加入

还未添加个人简介

评论

发布
暂无评论
支持向量机-探索核函数的优势和缺陷_Python_烧灯续昼2002_InfoQ写作社区