sklearn之支持向量机(SVM)算法类库介绍

转载自:http://blog.sina.com.cn/s/articlelist_1654066213_0_1.html
上面3篇文章详细介绍了支持向量机(SVM)的算法。本文介绍一下scikit-learn中的SVM算法类库。

1. scikit-learn SVM算法类库概述
scikit-learn中的SVM算法库分为两类,一类是分类的算法库,包括SVC, NuSVC和LinearSVC 3个类;另一类是回归算法库,包括SVR, NuSVR和LinearSVR 3个类。相关的类都包含在sklearn.svm模块之中。
对于SVC, NuSVC和LinearSVC 这3个用于分类的类,SVC和NuSVC差不多,区别仅仅在于对损失的度量方式不同,而LinearSVC从名字就可以看出,它是线性分类,也就是不支持各种低维到高维的核函数,仅仅支持线性核函数,对线性不可分的数据不能使用。
同样地,对于SVR, NuSVR和LinearSVR 这3个用于回归的类, SVR和NuSVR差不多,区别也仅仅在于对损失的度量方式不同。LinearSVR是线性回归,只能使用线性核函数。
我们使用这些类的时候,如果有经验知道数据是可以线性拟合的,那么使用LinearSVC去分类或者LinearSVR去回归,它们不需要我们去慢慢的调参去选择各种核函数以及对应参数, 速度也快。如果我们对数据分布没有什么经验,一般使用SVC去分类或者SVR去回归,这就需要我们选择核函数以及对核函数进行调参了。
什么特殊场景需要使用NuSVC分类和NuSVR回归呢?如果我们对训练集训练的错误率或者说支持向量的百分比有要求的时候,可以选择NuSVC分类和NuSVR回归。它们有一个参数来控制这个百分比。

2. 回顾SVM分类算法和回归算法
我们先简要回顾一下SVM分类算法和回归算法,因为这里面有些参数对应于算法库中的参数,如果不先复习,下面对参数的讲解可能会有些难以理解。
对于SVM分类算法,其原始形式是:
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
其中m为样本个数,我们的样本为scikit-learn(sklearn)支持向量机(SVM)算法类库介绍。w、b是分离超平面scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
的系数, scikit-learn(sklearn)支持向量机(SVM)算法类库介绍为第i个样本的松弛系数, C为惩罚系数。scikit-learn(sklearn)支持向量机(SVM)算法类库介绍为低维到高维的映射函数。
通过拉格朗日函数以及对偶化后的形式为:
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
其中和原始形式不同的是α为拉格朗日系数向量。scikit-learn(sklearn)支持向量机(SVM)算法类库介绍为我们要使用的核函数。
对于SVM回归算法,其原始形式是:
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
其中m为样本个数,我们的样本为scikit-learn(sklearn)支持向量机(SVM)算法类库介绍。w、b是回归超平面scikit-learn(sklearn)支持向量机(SVM)算法类库介绍的系数。scikit-learn(sklearn)支持向量机(SVM)算法类库介绍为第i个样本的松弛系数, C为惩罚系数,scikit-learn(sklearn)支持向量机(SVM)算法类库介绍为损失边界,到超平面距离小于scikit-learn(sklearn)支持向量机(SVM)算法类库介绍的训练集样本点没有损失。scikit-learn(sklearn)支持向量机(SVM)算法类库介绍为低维到高维的映射函数。
通过拉格朗日函数以及对偶化后的形式为:
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
scikit-learn(sklearn)支持向量机(SVM)算法类库介绍
其中和原始形式不同的,scikit-learn(sklearn)支持向量机(SVM)算法类库介绍为拉格朗日系数向量。scikit-learn(sklearn)支持向量机(SVM)算法类库介绍为我们要使用的核函数。

3. SVM核函数概述
在scikit-learn中,内置的核函数一共有4种。
  1) 线性核函数(Linear Kernel)表达式为:scikit-learn(sklearn)支持向量机(SVM)算法类库介绍,就是普通的内积,LinearSVC和LinearSVR只能使用它。
  2) 多项式核函数(Polynomial Kernel)是线性不可分SVM常用的核函数之一,表达式为:scikit-learn(sklearn)支持向量机(SVM)算法类库介绍,其中,scikit-learn(sklearn)支持向量机(SVM)算法类库介绍都需要自己调参定义,比较麻烦。
  3) 高斯核函数(Gaussian Kernel),在SVM中也称为径向基核函数(Radial Basis Function, RBF),它是libsvm默认的核函数,当然也是scikit-learn默认的核函数。表达式为:scikit-learn(sklearn)支持向量机(SVM)算法类库介绍,其中,scikit-learn(sklearn)支持向量机(SVM)算法类库介绍大于0,需要自己调参定义。
  4) Sigmoid核函数(Sigmoid Kernel)也是线性不可分SVM常用的核函数之一,表达式为:scikit-learn(sklearn)支持向量机(SVM)算法类库介绍, 其中,scikit-learn(sklearn)支持向量机(SVM)算法类库介绍都需要自己调参定义。
一般情况下,对非线性数据使用默认的高斯核函数会有比较好的效果,如果你不是SVM调参高手,建议使用高斯核来做数据分析。

4. SVM分类算法类库参数小结
这里我们对SVM分类算法类库的重要参数做一个详细的解释,重点讲述调参的一些注意点。
参数 LinearSVC SVC NuSVC
惩罚系数C 即第2节中SVM分类模型原型形式和对偶形式中的惩罚系数C,默认为1,通常需要通过交叉验证来选择一个合适的C。一般来说,如果噪声点较多时,C需要小一些。 NuSVC没有这个参数, 它通过另一个参数nu来控制训练集训练的错误率,等价于选择了一个C,让训练集训练后满足一个确定的错误率。
nu LinearSVC和SVC没有这个参数,LinearSVC和SVC使用惩罚系数C来控制惩罚力度。 nu代表训练集训练的错误率上限,或者说支持向量的百分比下限,取值范围为(0,1],默认值是0.5.它和惩罚系数C类似,都可以控制惩罚的力度。
核函数 kernel LinearSVC没有这个参数,LinearSVC限制了只能使用线性核函数。 核函数有四种内置选择,第3节已经讲到:’linear’即线性核函数,’poly’即多项式核函数,’rbf’即高斯核函数,’sigmoid’即sigmoid核函数。如果选择了这些核函数,对应的核函数需要单独调参。默认是高斯核’rbf’。
还有一种选择为’precomputed’,即我们预先计算出所有的训练集和测试集的样本对应的Gram矩阵,这样K(x,z)直接在对应的Gram矩阵中找对应位置的值。
当然我们也可以自定义核函数。
正则化参数penalty 仅仅对线性拟合有意义,可以选择’l1’即L1正则化或者’l2’即L2正则化。默认是L2正则化,如果我们需要产生稀疏化的系数时,可以选L1正则化,这和线性回归里面的Lasso回归类似。 SVC和NuSVC没有这个参数。
是否用对偶形式优化dual 这是一个布尔变量,控制是否使用对偶形式来优化算法,默认值是True,即采用第2节的分类算法对偶形式来优化算法。如果我们的样本量比特征数多,此时采用对偶形式计算量较大,推荐dual设置为False,即采用原始形式优化。 SVC和NuSVC没有这个参数。
核函数参数degree LinearSVC没有这个参数,LinearSVC限制了只能使用线性核函数。 如果我们在kernel参数使用了多项式核函数’poly’,那么我们就需要对这个参数进行调参。这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的d。默认是3。一般需要通过交叉验证选择一组合适的值。
核函数参数gamma LinearSVC没有这个参数,LinearSVC限制了只能使用线性核函数。 如果我们在kernel参数使用了多项式核函数’poly’,高斯核函数’rbf’或者sigmoid核函数,那么我们就需要对这个参数进行调参。
多项式核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的γ。一般需要通过交叉验证选择一组合适的γ,r,d。
高斯核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的γ。一般需要通过交叉验证选择合适的γ。
sigmoid核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的γ。一般需要通过交叉验证选择一组合适的γ,r。
γ默认为’auto’,即1/特征维度。
核函数参数coef0 LinearSVC没有这个参数,LinearSVC限制了只能使用线性核函数。 如果我们在kernel参数使用了多项式核函数’poly’或者sigmoid核函数,那么我们就需要对这个参数进行调参。
多项式核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的r。一般需要通过交叉验证选择一组合适的γ,r,d。
sigmoid核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的r。一般需要通过交叉验证选择一组合适的γ,r。
coef0默认为0。
样本权重class_weight 指定样本各类别的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策过于偏向这些类别。这里可以自己指定各个样本的权重,或者用’balanced’,如果使用’balanced’,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认值’None’即可。
分类决策decision_function_shape LinearSVC没有这个参数,使用multi_class参数替代。 可以选择’ovo’或者’ovr’。目前0.18版本默认是’ovo’,0.19版本默认将变为’ovr’。
OvR(one-vs-rest)的思想很简单,无论你是多少元分类,我们都可以看做二元分类。具体做法是,对于第K类的分类决策,我们把所有第K类的样本作为正例,除了第K类样本以外的所有样本都作为负例,然后在上面做二元分类,得到第K类的分类模型。其它类的分类模型获得以此类推。
OvO(one-vs-one)则是每次在所有的T类样本里面选择两类样本出来,不妨记为T1类和T2类,把所有的输出为T1和T2的样本放在一起,把T1作为正例,T2作为负例,进行二元分类,得到模型参数。一共需要T(T-1)/2次分类。
从上面的描述可以看出OvR相对简单,但分类效果相对略差(这里指大多数样本分布的情况,某些样本分布下OvR可能更好)。而OvO分类相对精确,但是分类速度没有OvR快。一般建议使用OvO以达到较好的分类效果。
分类决策multi_class 可以选择’ovr’或者’crammer_singer’。
‘ovr’和SVC、nuSVC中的decision_function_shape对应的’ovr’类似。
‘crammer_singer’是一种改良版的’ovr’,说是改良,但是没有比’ovr’好,一般在应用中都不建议使用。
SVC和nuSVC中没有这个参数,使用decision_function_shape参数替代。
缓存大小cache_size LinearSVC计算量不大,因此不需要这个参数。 在大样本的时候,缓存大小会影响训练速度,因此如果机器内存大,推荐使用500MB甚至1000MB。默认是200,即200MB。

5. SVM回归算法库参数小结
SVM回归算法类库的重要参数绝大部分和分类算法类库相似,因此这里重点讲述和分类算法类库不同的部分,对于相同的部分可以参考上一节对应的参数。
参数 LinearSVR SVR NuSVR
惩罚系数C 即为我们第2节中SVM分类模型原型形式和对偶形式中的惩罚系数C,默认为1,通常需要通过交叉验证来选择一个合适的C。一般来说,如果噪声点较多时,C需要小一些。大家可能注意到在分类模型里面,NuSVC使用了nu这个等价的参数控制错误率,就没有使用C,那么为什么NuSVR仍然有这个参数呢,不是重复了吗?这里的原因在于在回归模型里面,除了惩罚系数C还有一个距离误差ϵ来控制损失度量,因此仅仅一个nu不能等同于C,也就是说分类错误率是惩罚系数C和距离误差ϵ共同作用的结果。后面我们可以看到NuSVR中nu的作用。
nu LinearSVR和SVR没有这个参数,用ϵ控制错误率。 nu代表训练集训练的错误率的上限,或者说支持向量的百分比下限,取值范围为(0,1],默认值是0.5。通过选择不同的错误率可以得到不同的距离误差ϵ,也就是说这里nu的使用与LinearSVR和SVR的ϵ参数等价。
距离误差epsilon 即第2节回归模型中的ϵ,训练集中的样本需满足scikit-learn(sklearn)支持向量机(SVM)算法类库介绍 NuSVR没有这个参数,用nu控制错误率。
是否用对偶形式优化dual 这是一个布尔变量,控制是否使用对偶形式来优化算法,默认值是True,即采用第2节的分类算法对偶形式来优化算法。如果我们的样本量比特征数多,此时采用对偶形式计算量较大,推荐dual设置为False,即采用原始形式优化。 SVR和NuSVR没有这个参数。
正则化参数penalty 仅仅对线性拟合有意义,可以选择’l1’即L1正则化或者’l2’即L2正则化。默认是L2正则化,如果我们需要产生稀疏化的系数时,可以选L1正则化,这和线性回归里面的Lasso回归类似。 SVR和NuSVR没有这个参数。
核函数 kernel LinearSVR没有这个参数,LinearSVR限制了只能使用线性核函数。 核函数有四种内置选择,第3节已经讲到:’linear’即线性核函数,’poly’即多项式核函数,’rbf’即高斯核函数,’sigmoid’即sigmoid核函数。如果选择了这些核函数,对应的核函数需要单独调参。默认是高斯核’rbf’。
还有一种选择为’precomputed’,即我们预先计算出所有的训练集和测试集的样本对应的Gram矩阵,这样K(x,z)直接在对应的Gram矩阵中找对应位置的值。
当然我们也可以自定义核函数。
核函数参数degree LinearSVR没有这个参数,LinearSVR限制了只能使用线性核函数。 如果我们在kernel参数使用了多项式核函数’poly’,那么我们就需要对这个参数进行调参。这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的d。默认是3。一般需要通过交叉验证选择一组合适的值。
核函数参数gamma LinearSVR没有这个参数,LinearSVR限制了只能使用线性核函数。 如果我们在kernel参数使用了多项式核函数’poly’,高斯核函数’rbf’或者sigmoid核函数,那么我们就需要对这个参数进行调参。
多项式核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的γ。一般需要通过交叉验证选择一组合适的γ,r,d。
高斯核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的γ。一般需要通过交叉验证选择合适的γ。
sigmoid核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的γ。一般需要通过交叉验证选择一组合适的γ,r。
γ默认为’auto’,即1/特征维度。
核函数参数coef0 LinearSVR没有这个参数,LinearSVR限制了只能使用线性核函数。 如果我们在kernel参数使用了多项式核函数’poly’或者sigmoid核函数,那么我们就需要对这个参数进行调参。
多项式核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的r。一般需要通过交叉验证选择一组合适的γ,r,d。
sigmoid核函数中这个参数对应scikit-learn(sklearn)支持向量机(SVM)算法类库介绍中的r。一般需要通过交叉验证选择一组合适的γ,r。
coef0默认为0。
样本权重class_weight 指定样本各类别的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策过于偏向这些类别。这里可以自己指定各个样本的权重,或者用’balanced’,如果使用’balanced’,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认值’None’即可。
损失函数度量loss 可以选择’epsilon_insensitive’和’squared_epsilon_insensitive’,如果选择’epsilon_insensitive’,则损失度量满足scikit-learn(sklearn)支持向量机(SVM)算法类库介绍,即和第2节的损失度量一样。它是默认的SVM回归的损失度量标准形式。
如果选择为’squared_epsilon_insensitive’,则损失度量满足scikit-learn(sklearn)支持向量机(SVM)算法类库介绍,此时少了一个松弛系数。其目标函数优化过程和支持向量机(SVM)的回归模型》中所讲的过程是相似的。
一般用默认的’epsilon_insensitive’就足够了。
SVR和NuSVR没有这个参数。
缓存大小cache_size LinearSVR计算量不大,因此不需要这个参数。 在大样本的时候,缓存大小会影响训练速度,因此如果机器内存大,和SVC,NuSVC一样,推荐用500MB甚至1000MB。默认是200,即200MB。

6. SVM算法库其他调参要点
前面已经对scikit-learn中SVM类库的参数做了说明,这里对其它的调参要点做一个小结。
  1) 一般推荐在做训练之前对数据进行归一化,当然测试集中的数据也需要归一化。
  2) 在特征数非常多的情况下,或者样本数远小于特征数的时候,使用线性核,效果已经很好,并且只需要选择惩罚系数C即可。
  3) 在选择核函数时,如果线性拟合不好,一般推荐使用默认的高斯核’rbf’。这时我们主要需要对惩罚系数C和核函数参数γ进行艰苦的调参,通过多轮的交叉验证选择合适的惩罚系数C和核函数参数γ。
  4) 理论上高斯核不会比线性核差,但是这个理论却建立在要花费更多的时间来调参上。所以实际上能用线性核解决问题我们尽量使用线性核。

7. 使用Mnist数据集测试scikit-learn的SVM分类算法类库
代码如下所示:
—————————————————————————————————
from sklearn.svm import SVC, NuSVC, LinearSVC
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import accuracy_score
import numpy as np
import mnist

if __name__ == “__main__”:
    # 读取Mnist数据集, 测试SVM的分类模型
    mnistSet = mnist.loadLecunMnistSet()
    train_X, train_Y, test_X, test_Y = mnistSet[0], mnistSet[1], mnistSet[2], mnistSet[3]

    m, n = np.shape(train_X)
    idx = range(m)
    np.random.shuffle(idx)

    print “\n**********测试LinearSVC类**********”
    model = LinearSVC(C=0.0000001)
    # 拟合训练数据集
    model.fit(train_X, train_Y)
    # 预测训练集
    train_Y_hat = model.predict(train_X[idx])
    print “训练集精确度: “, accuracy_score(train_Y[idx], train_Y_hat)
    # 预测测试集
    test_Y_hat = model.predict(test_X)
    print “测试集精确度: “, accuracy_score(test_Y, test_Y_hat)

    print “\n**********测试SVC类**********”
    model = SVC(C=10, gamma=0.0000001, cache_size=1000)
    # 拟合训练数据集
    model.fit(train_X, train_Y)
    # 预测训练集
    train_Y_hat = model.predict(train_X[idx])
    print “训练集精确度: “, accuracy_score(train_Y[idx], train_Y_hat)
    # 预测测试集
    test_Y_hat = model.predict(test_X)
    print “测试集精确度: “, accuracy_score(test_Y, test_Y_hat)

    print “\n**********测试NuSVC类**********”
    model = NuSVC(gamma=0.0000001, cache_size=1000)
    # 拟合训练数据集
    model.fit(train_X, train_Y)
    # 预测训练集
    train_Y_hat = model.predict(train_X[idx])
    print “训练集精确度: “, accuracy_score(train_Y[idx], train_Y_hat)
    # 预测测试集
    test_Y_hat = model.predict(test_X)
    print “测试集精确度: “, accuracy_score(test_Y, test_Y_hat)
—————————————————————————————————

8. 使用CCPP数据集测试scikit-learn的SVM回归算法类库
代码如下所示:
—————————————————————————————————
from sklearn.svm import SVR, NuSVR, LinearSVR
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import numpy as np
import pandas as pd

if __name__ == “__main__”:
    # 读取CCPP数据集, 测试SVM的回归模型
    data = pd.read_excel(“data/CCPP/Folds5x2_pp.xlsx”)
    # AT:温度, V:压力, AP:湿度, RH:压强, PE:输出电力
    # 样本特征X
    X = data[[‘AT’, ‘V’, ‘AP’, ‘RH’]]
    # 数据归一化
    X = StandardScaler().fit_transform(X)
    # 样本输出Y
    Y = data[[‘PE’]]
    # 划分训练集和测试集,将数据集的70%划入训练集,30%划入测试集
    train_X, test_X, train_Y, test_Y = train_test_split(X, Y, test_size=0.3, random_state=1)

    m, n = np.shape(train_X)
    idx = range(m)
    np.random.shuffle(idx)

    print “\n**********测试LinearSVR类**********”
    model = LinearSVR(C=10.0)
    # 拟合训练集
    model.fit(train_X, train_Y.values.ravel())
    # 预测测试集
    test_Y_pred = model.predict(test_X)
    print “测试集MSE:”, mean_squared_error(test_Y, test_Y_pred)
    print “测试集RMSE:”, np.sqrt(mean_squared_error(test_Y, test_Y_pred))

    print “\n**********测试SVR类**********”
    model = SVR(C=100.0, gamma=0.1, cache_size=500)
    # 拟合训练集
    model.fit(train_X, train_Y.values.ravel())
    # 预测测试集
    test_Y_pred = model.predict(test_X)
    print “测试集MSE:”, mean_squared_error(test_Y, test_Y_pred)
    print “测试集RMSE:”, np.sqrt(mean_squared_error(test_Y, test_Y_pred))

    print “\n**********测试NuSVR类**********”
    model = NuSVR(C=100.0, nu=0.3, gamma=0.1, cache_size=500)
    # 拟合训练集
    model.fit(train_X, train_Y.values.ravel())
    # 预测测试集
    test_Y_pred = model.predict(test_X)
    print “测试集MSE:”, mean_squared_error(test_Y, test_Y_pred)
    print “测试集RMSE:”, np.sqrt(mean_squared_error(test_Y, test_Y_pred))
—————————————————————————————————

猜你喜欢

转载自blog.csdn.net/zztingfeng/article/details/80590244
今日推荐