SVM模型的应用

SVM模型的应用

前言

  SVM是Support Vector Machine的简称,它的中文名为支持向量机,属于一种有监督的机器学习算法,可用于离散因变量的分类和连续因变量的预测。通常情况下,该算法相对于其他单一的分类算法(如Logistic回归、决策树、朴素贝叶斯、KNN等)会有更好的预测准确率,主要是因为它可以将低维线性不可分的空间转换为高维线性可分空间。由于该算法具有较高的预测准确率,所以其备受企业界的欢迎,如利用该算法实现医疗诊断、图像识别、文本分类、市场营销等。
  该算法的思想就是利用某些支持向量所构成的“超平面”,将不同类别的样本点进行划分。不管样本点是线性可分的、近似线性可分的还是非线性可分的,都可以利用“超平面”将样本点以较高的准确度切割开来。需要注意的是,如果样本点为非线性可分,就要借助于核函数技术,实现样本在核空间下完成线性可分的操作。关键是“超平面”如何构造,可查阅其它文献资料。
  运用SVM模型对因变量进行分类或预测时具有几个显著的优点:例如,由于SVM模型最终所形成的分类器仅依赖于一些支持向量,这就导致模型具有很好的鲁棒性(增加或删除非支持向量的样本点,并不会改变分类器的效果)以及避免“维度灾难”的发生(模型并不会随着数据维度的提升而提高计算的复杂度),模型具有很好的泛化能力,一定程度上可以避免模型的过拟合;也可以避免模型在运算过程中出现的局部最优。当然,该算法的缺点也是明显的,例如该模型不适合大样本的分类或预测,因为它会消耗大量的计算资源和时间;模型对缺失样本非常敏感,这就需要在建模前清洗好每一个样本;虽然可以通过核函数解决非线性可分问题,但是模型对核函数的选择也同样很敏感;SVM为黑盒模型(相比于回归或决策树算法),对计算得到的结果无法解释。

分类问题的解决

  本节所使用的数据集是关于手体字母的识别,当一个用户在设备中写入某个字母后,该设备就需要准确地识别并返回写入字母的实际值。很显然,这是一个分类问题,即根据写入字母的特征信息(如字母的宽度、高度、边际等)去判断其属于哪一种字母。该数据集一共包含20000个观测和17个变量,其中变量letter为因变量,具体的值就是26个英文字母。接下来利用SVM模型对该数据集的因变量做分类判断。
  首先使用线性可分SVM对手体字母数据集进行建模,由于该模型会受到惩罚系数C的影响,故采用交叉验证的方法,从给定的几种C值中筛选出一个相对合理的,代码如下:

# 导入第三方模块
from sklearn import svm
import pandas as pd
from sklearn import model_selection
from sklearn import metrics

# 读取外部数据
letters = pd.read_csv('datasource/letterdata.csv')
# 数据前5行,见图1
letters.head()

图1:数据的前5行预览
图1:数据的前5行预览
  图1反映了手体字母数据集的前5行预测,都是关于手写体的长、宽及坐标信息特征。通常在建模前都需要将原始数据集拆分为两个部分,分别用于模型的构建和测试,具体代码如下:

# 将数据拆分为训练集和测试集
predictors = letters.columns[1:]
X_train, X_test, y_train, y_test = model_selection.train_test_split(letters[predictors], letters.letter, test_size=0.25, random_state=1234)
# 使用网格搜索法,选择线性可分SVM“类”中的最佳C值
C = [0.05, 0.1, 0.5, 1, 2, 5]
parameters = {'C' : C}
grid_linear_svc = model_selection.GridSearchCV(estimator=svm.LinearSVC(), param_grid=parameters, scoring='accuracy', cv=5, verbose=1)
# 模型在训练数据集上的拟合
grid_linear_svc.fit(X_train, y_train)
# 返回交叉验证后的最佳参数值
grid_linear_svc.best_params_, grid_linear_svc.best_score_
out:
({'C': 0.1}, 0.6917333333333333)
# 模型在测试集上的预测
pred_linear_svc = grid_linear_svc.predict(X_test)
# 模型的预测准确率
metrics.accuracy_score(y_test, pred_linear_svc)
out:
0.7154

  如上结果所示,经过5重交叉验证后,发现最佳的惩罚系数C为0.1,模型在训练数据集上的平均准确率只有69.2%,同时,其在测试数据集的预测准确率也不足72%,说明线性可分SVM模型并不太适合该数据集的拟合和预测。接下来,使用非线性SVM模型对该数据集进行重新建模,代码如下:

# 使用网格搜索法,选择非线性可分SVM“类”中的最佳C值和核函数
kernel = ['rbf', 'linear', 'poly', 'sigmoid']
C = [0.1, 0.5, 1, 2, 5]
parameters = {'kernel' : kernel, 'C' : C}
grid_svc = model_selection.GridSearchCV(estimator=svm.SVC(), param_grid=parameters, scoring='accuracy', cv=5, verbose=1)
# 模型在训练数据集上的拟合
grid_svc.fit(X_train, y_train)
# 返回交叉验证后的最佳参数值
grid_svc.best_params_, grid_svc.best_score_
out:
({'C': 5, 'kernel': 'rbf'}, 0.9734)
# 模型在测试集上的预测
pred_svc = grid_svc.predict(X_test)
# 模型的预测准确率
metrics.accuracy_score(y_test, pred_svc)
out:
0.9786

  如上结果所示,经过5重交叉验证后,发现最佳的惩罚系数C为5,最佳的核函数为径向基核函数。相比于线性可分SVM模型来说,基于核技术的SVM表现了极佳的效果,模型在训练数据集上的平均准确率高达97.34%,而且其在测试数据集的预测准确率也接近98%,说明利用非线性可分SVM模型拟合及预测手体字母数据集是非常理想的。

预测问题的解决

  本节实战部分所使用的数据集来源于UCI网站,是一个关于森林火灾方面的预测,该数据集一共包含517条火灾记录和13个变量,其中变量area为因变量,表示火灾产生的森林毁坏面积,其余变量主要包含火灾发生的坐标位置、时间、各项火险天气指标、气温、湿度、风力等信息。接下来利用SVM模型对该数据集的因变量做预测分析:

# 读取外部数据
forestfires = pd.read_csv('datasource/forestfires.csv')
# 显示数据前5行,见图2
forestfires.head()

图2:数据的前5行预览
图2:数据的前5行预览
  如图2所示,火灾发生的时间(month和day)为字符型的变量,如果将这样的变量带入模型中,就必须对其做数值化转换。考虑到月份可能是火灾发生的一个因素,故将该变量做保留处理,而将day变量删除。数据清洗如下:

# 删除day变量
forestfires.drop(labels='day', axis=1, inplace=True)
# 将月份做标准化处理
forestfires['month'] = pd.factorize(forestfires.month)[0]
# 预览数据的前5行,见图3
forestfires.head()

图3:离散变量的数值化处理
图3:离散变量的数值化处理
  如图3所示,day变量已被删除,而且month变量也成为数值型变量。图中的因变量为area,是一个数值型变量,通常都需要对连续型的因变量做分布的探索性分析,如果数据呈现严重的偏态,而不做任何的修正时,直接带入到模型将会产生很差的效果。不妨这里使用直方图直观感受area变量的分布形态,操作代码如下:

# 导入第三方模块
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.stats import norm
# plt图像背景、字体、符号设置
plt.style.use('ggplot')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 绘制森林烧毁面积的直方图
sns.distplot(forestfires.area, bins=50, kde=True, fit=norm, hist_kws={'color':'steelblue'}, kde_kws={'color':'red','label':'Kernel Density'}, fit_kws={'color':'black','label':'Normal','linestyle':'--'})
# 显示图例
plt.legend()
# 显示图形
plt.show()

图4:受灾面积的直方图
图4:受灾面积的直方图
  如图4所示,从分布来看,数据呈现明显的右偏。建模时不能够直接使用该变量,一般都会将数据做对数处理,代码如下:

# 导入第三方模块
from sklearn import preprocessing
import numpy as np
# 对area变量做对数变换
y = np.log1p(forestfires.area)
# 将x变量做标准化处理
predictors = forestfires.columns[:-1]
X = preprocessing.scale(forestfires[predictors])

  接下来基于上面清洗后的数据将其拆分为两部分,分别用于模型的构建和测试。需要注意的是,在建模时必须要对参数C、 ϵ \epsilon ϵ、y做调优处理,因为默认的SVM模型并不一定是最好的。代码如下:

# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.25, random_state=1234)
# 构建默认参数的SVM回归模型
svr = svm.SVR()
# 模型在训练数据集上的拟合
svr.fit(X_train, y_train)
# 模型在测试数据集上的预测
pred_svr = svr.predict(X_test)
# 计算模型的MSE
metrics.mean_squared_error(y_test, pred_svr)
out:
1.925863595333521
# 使用网格搜索法,选择SVM回归中的最佳C值、epsilon值和gamma值
epsilon = np.arange(0.1, 1.5, 0.2)
C = np.arange(100, 1000, 200)
gamma = np.arange(0.001, 0.01, 0.002)
parameters = {'epsilon':epsilon, 'C':C, 'gamma':gamma}
grid_svr = model_selection.GridSearchCV(estimator=svm.SVR(), param_grid=parameters, scoring='neg_mean_squared_error', cv=5, verbose=1, n_jobs=2)
# 模型在训练数据集上的拟合
grid_svr.fit(X_train, y_train)
# 返回交叉验证后的最佳参数值
grid_svr.best_params_, grid_svr.best_score_
out:
({'C': 300, 'epsilon': 1.1000000000000003, 'gamma': 0.001}, -1.9940579497706303)
# 模型在测试集上的预测
pred_grid_svr = grid_svr.predict(X_test)
# 计算模型在测试数据集上的MSE值
metrics.mean_squared_error(y_test, pred_grid_svr)
out:
1.7455012238826595

  如上结果所示:经过5重交叉验证后,非线性SVM回归的最佳惩罚系数C为300、最佳的 ϵ \epsilon ϵ值为1.1,最佳的Y值为0.001,而且该模型在训练数据集上的负MSE值为-1.994。为了实现模型之间拟合效果的对比,构建了一个不做任何参数调整的SVM回归模型,并计算得到该模型在测试数据集上的MSE值为1.926,相比于经过调参之后的模型来说,这个值要高于1.746。进而可以说明,在利用SVM模型解决分类或预测问题时,需要对模型的参数做必要的优化。

小结

  相比于其它模型的分类或预测模型来说,SVM模型的表现通常是非常优异的,但其最大的缺点是运算成本非常高,尤其是当数据规模很大时,明显感觉速度跟不上。所以,在实际应用中,需要将时间成本和准确率做一个平衡,从中选择合理的模型解决工作中的需求。

源文件及完整代码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值