(六十六)支持向量机

SVM的原理

SVM模型是将实例表示为空间中的点,这样映射就使得单独类别的实例被尽可能宽地明显间隔分开,然后将新的实例映射到同一空间,并基于它们落在间隔的哪一侧来预测所属类别。除了进行线性分类之外,SVM还可以使用所谓的核技巧有效地进行非线性分类,将其输入隐式映射到高维特征空间中。

以线性SVM为例,假设下图中x1和x2为圆形类别,x34为三角形类别,超平面1和超平面2(直线可认为是二维空间内的超平面)都可以将三角和圆形数据分开。对于超平面1,训练数据的几何间隔等价于粗箭头长度;对于超平面2,训练数据的几何间隔等价于细箭头的长度。图中超平面1的几何间隔大于超平面2的,实际含义为若以超平面1为分离超平面,那么几何间隔较大,相应分类预测的可靠程度也就较高。所以可以将线性可分支持向量机的学习概括为找到几何间隔最大的超平面,使得训练数据能够被线性分离,这一过程被称为间隔最大化。
在这里插入图片描述
在SVM算法中,只有一部分训练集数据对于边界的确定是有帮助的,而这些数据点就是正好位于决定边界上的。这些数据被称为“支持向量”(support vectors),这也是“支持向量机”名字的由来。间隔最大超平面,就是指中间这条实线和所有支持向量之间的距离都是最大的。

SVM的核函数

SVM可以分为回归(SVR)和分类(SVC)。核函数的思想是构造原输入数据的高维映射,将输入空间的数据映射到高维空间。在实际操作中可以通过交叉验证确定核函数的最优参数。最常使用的核函数有:

  • 多项式内核(Polynomial kernel),通过把样本原始特征进行乘方来把数据投射到高维空间,比如特征1乘2次方、特征2乘3次方等。在polynomial内核的SVC中,起决定性作用的参数是degree(对特征进行k次方操作)和正则化参数C。C越大容易过拟合,C越小容易欠拟合,下同。
  • 径向基内核(Radial basis function kernel, RBF),也被称为高斯内核(Gaussian kernel),通俗一些理解,就是三维空间上的椭圆、高维空间上的椭球。起决定作用的是正则化参数C和参数gamma。gamma值越小,则RBF内核的直径越大,决定边界也就越平滑,模型越倾向于欠拟合,反之亦然。
  • 线性内核(Linear kernel)。实际上,linearSVM就是一种使用了线性内核的SVM算法。不过linearSVM不支持对核函数进行修改,linearSVC对L2范数进行最小化,而线性内核的SVC是对L1范数进行最小化。不论如何,linearSVC和线性内核的SVC生成的决定边界都是线性的,在更高维数据集中将会是相交的超平面。

高斯内核的gamma和C参数选择可参考颜丑文良777:图解SVM中gamma和c参数的作用。高斯核函数是应用最广的一个,无论大样本还是小样本都有比较好的性能,而且其相对于多项式核函数参数要少,因此大多数情况下在不知道用什么样的核函数的时候优先使用高斯核函数。

案例

SVR案例

在scikit-learn中,内置了一个非常适合做回归分析的数据集——波士顿房价数据集。数据集中共有506个样本,每个样本有13个特征变量,还有一个叫作中位数(业主自住房屋价格的中位数)的第14个变量是target。

import numpy as np
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.datasets import load_boston
boston = load_boston()
print(boston['DESCR'])#部分结果
.. _boston_dataset:
Boston house prices dataset
---------------------------
**Data Set Characteristics:**  

    :Number of Instances: 506 

    :Number of Attributes: 13 numeric/categorical predictive. Median Value (attribute 14) is usually the target.

    :Attribute Information (in order):
        - CRIM     per capita crime rate by town
        - ZN       proportion of residential land zoned for lots over 25,000 sq.ft.
        - INDUS    proportion of non-retail business acres per town
        - CHAS     Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
        - NOX      nitric oxides concentration (parts per 10 million)
        - RM       average number of rooms per dwelling
        - AGE      proportion of owner-occupied units built prior to 1940
        - DIS      weighted distances to five Boston employment centres
        - RAD      index of accessibility to radial highways
        - TAX      full-value property-tax rate per $10,000
        - PTRATIO  pupil-teacher ratio by town
        - B        1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
        - LSTAT    % lower status of the population
        - MEDV     Median value of owner-occupied homes in $1000's

X, y = boston.data, boston.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)

先看看各个特征的数量级情况,发现第1个特征最小值在10-2以下,最大值在102左右,而第10个特征的最大最小值就很接近。因此有必要对数据进行标准化处理(否则SVR模型的得分会很低),可使用StandardScaler函数:

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
plt.plot(X_train_scaled.min(axis=0),'v',label='train set min')
plt.plot(X_train_scaled.max(axis=0),'^',label='train set max')
plt.plot(X_test_scaled.min(axis=0),'v',label='test set min')
plt.plot(X_test_scaled.max(axis=0),'^',label='test set max')
plt.yscale('log')#设置纵坐标为对数形式
plt.legend(loc='best')
plt.xlabel('scaled features')
plt.ylabel('scaled feature magnitude')
plt.show()

在这里插入图片描述
可以看到对数据标准化之后,所有特征的数量级都被限制在了0~10左右。下面我们直接使用网格搜索方法建立最优的SVR模型:

from sklearn.model_selection import ParameterGrid,GridSearchCV
kernel = ['linear','rbf']
gamma = np.linspace(0.1,10,10)
C = [1,10,100,1000]
grid = {'kernel':kernel,'gamma':gamma,'C':C}
svr_search = GridSearchCV(estimator=svm.SVR(),param_grid=grid,cv=3)
svr_search.fit(X_train_scaled, y_train)
svr_search.best_params_
Out[34]: {'C': 100, 'gamma': 0.1, 'kernel': 'rbf'}
print('在训练集得分:{:.3f}'.format(svr_search.score(X_train_scaled, y_train)))
print('在测试集得分:{:.3f}'.format(svr_search.score(X_test_scaled, y_test)))
在训练集得分:0.966
在测试集得分:0.894

以上述param_grid为例,可以看到当参数为 {‘C’: 100, ‘gamma’: 0.1, ‘kernel’: ‘rbf’} 时,模型的测试集得分达到了90%。

SVC案例

某男士希望知道他在某婚恋网站和喜欢的女性约会是否会成功,他收集了以往注册该网站的男士的基本信息(income、attractive、assets、educlass),以及约会是否成功(dated)的信息,由此预测在自己的条件下能否约会到喜欢的女生。

Data = pd.read_csv(r'C:\Users\Desktop\date_data2.csv')
Data.describe()
Out[20]: 
             income  attractive      assets    educlass       Dated
count    100.000000  100.000000  100.000000  100.000000  100.000000
mean    9010.000000   50.500000   96.006300    3.710000    0.500000
std     5832.675288   28.810948   91.082226    1.225116    0.502519
min     3000.000000    1.000000    3.728400    1.000000    0.000000
25%     5000.000000   28.000000   31.665269    3.000000    0.000000
50%     7500.000000   51.000000   70.746924    4.000000    0.500000
75%    11500.000000   68.875000  131.481061    4.000000    1.000000
max    34000.000000   99.500000  486.311758    6.000000    1.000000
#数据预处理
X = Data.iloc[:, :4]
Y = Data['Dated']
train_data, test_data, train_target, test_target = train_test_split(\
    X, Y, test_size=0.3, train_size=0.7, random_state=123) 
scaler2 = StandardScaler()
scaler2.fit(train_data)
train_scaled = scaler2.transform(train_data)
test_scaled = scaler2.transform(test_data)
#网格搜索建立SVC模型
kernel = ('linear', 'rbf')
gamma = np.arange(0.01, 1, 0.1)
C = np.arange(0.01, 1.0, 0.1)
grid = {'kernel':kernel, 'gamma': gamma, 'C': C}
svc_search = GridSearchCV(estimator=svm.SVC(), param_grid=grid, cv=5)
svc_search.fit(train_scaled, train_target)
#模型评估
print(svc_search.best_estimator_)#返回的是可fit的estimator
SVC(C=0.41000000000000003, gamma=0.01, kernel='linear')
test_est = svc_search.predict(test_scaled)
print(classification_report(test_target, test_est))
              precision    recall  f1-score   support

           0       1.00      1.00      1.00        14
           1       1.00      1.00      1.00        16

    accuracy                           1.00        30
   macro avg       1.00      1.00      1.00        30
weighted avg       1.00      1.00      1.00        30

可以看到模型的表现很好。假设该男士的4个特征值分别为[10000,90,150,3],预测该男士是否能约到喜欢的女生:

info=scaler2.transform(np.array([10000,90,150,3]).reshape(1,-1))
print(svc_search.predict(info))
[0]

很遗憾,约会失败。

总结

如果数据集中的样本数量在1万以内,SVM都能驾驭得了,10w+的话SVM就会非常耗费时间和内存。SVM还有一个短板,就是对于数据预处理和参数调节要求非常高。对于非专业人士来说,随机森林和梯度上升决策树不仅不需要对数据预处理,而且要比SVM更容易理解,毕竟SVM算法的建模过程是比较难以呈现的。

在SVM算法建模中,有3个重点:第一个是核函数的选择;第二个是核函数的参数,例如RBF的gamma值;第三个是正则化参数C。RBF内核的gamma值和C值一起控制模型的复杂度,数值越大模型越复杂。对数据进行标准化可以提升高斯核SVM的表现

参考文献

段小手《深入浅出Python机器学习》,清华大学出版社
常国珍等《Python数据科学:技术详解与商业实践》,机械工业出版社

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值