今天在准备SVM的一个答辩。于是重新深入理解了SVM的原理,从去工作的学长那里了解到现在的面试都已经开始询问SVM的数学原理,而SVM 的学习难点可能在于算法的理解和理论推导,而几个月前由于数学水平的不足而一知半解,现重新回顾,也是有了不一样的体验。并运用C#和Python分别对SVM完成了一定场景情况下的实现预测。
现在机器学习的缺口已经接近饱和,深度学习也只剩于百分之八到九左右,相对于近些年的深度学习,SVM作为传统的机器学习现在仍然具有很深远的指导意义。
下面是对于SVM的简单介绍:
# 读取外部数据
forestfires = pd.read_csv(r'C:\Users\Administrator\Desktop\forestfires.csv')
# 数据前 5 行
forestfires.head()
# 删除 day 变量
forestfires.drop('day',axis = 1, inplace = True)
# 将月份做数值化处理
forestfires.month = pd.factorize(forestfires.month)[0]
# 预览数据前 5 行
forestfires.head()
# 导入第三方模块
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.stats import norm
# 绘制森林烧毁面积的直方图
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':'Nomal', 'linestyle':'--'})
# 显示图例
plt.legend()
# 显示图形
plt.show()
这里呢大家如果对Pandas和Matplotlib不熟悉可以去了解一些它们的基本操作 。
对于直方图,从分布来看,数据呈现严重的右偏。建模时不能够直接使用该变量,一般都会将数据做对数处理,代码如下:
# 导入第三方模块
from sklearn import preprocessing
import numpy as np
# 对 area 变量做对数变换
y = np.log1p(forestfires.area)
# 将 X 变量做标准化处理
predictors = forestfires.columns[:-1]
X = preprocessing.scale(forestfires[predictors])
# 将数据拆分为训练集和测试集
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.9258635953335212
# 使用网格搜索法,选择 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)
# 返回交叉验证后的最佳参数值
print(grid_svr.best_params_, grid_svr.best_score_)
out:
{'C': 300, 'gamma': 0.001, 'epsilon': 1.1000000000000003} -1.99405794977
# 模型在测试集上的预测
pred_grid_svr = grid_svr.predict(X_test)
# 计算模型在测试集上的 MSE 值
metrics.mean_squared_error(y_test, pred_grid_svr)
out:
1.7455012238826526
![](https://i-blog.csdnimg.cn/blog_migrate/b335a3250c0c6877182a562db6e945ef.png)
如图我们可能希望在左边的图中寻找到一个隔离带将蓝色与红色分隔开,或是对于右图尽管红色与蓝色已经有一部分重叠,但我们希望还是能寻找到一个尽可能的隔离带。亦是在寻找隔离带的过程中引入了非线性,使得更高维,此时的模型更为复杂,加入了一些核之后,SVM分类器可以做到更为复杂 ,每每看到这些我就会感叹编程之美与神奇。
如上图左图中的蓝色的球与红色的球不再是点,因为此时是存在噪声的,对于误差我们可以利用以中心点为圆表示。而为了使得测试误差最小化,我们让边界远远地躲开每一个数据点,此时这个球可以变得更大,分类界离得足够远因此分类仍然是正确的,即为几何距离足够大。上图课展示为追求黄色的隔离带以此减小结构风险。而对于右图我们希望将绿色与橙色分开寻找一个最好的分类线。对此有无数种方法,但是我们通过先验信息,希望能够足够远,那此时问题就变成了唯一性。而如何解决这样的问题在SVM上就是一套数学工具了。
下面进行数学原理的简单介绍,对于市面上的资料从复杂入手容易让人困惑,我现在从简单入手,希望能对读者有所启发:
首先我们需要计算间隔多大。在两边都有点的情况下使得点到间隔带距离越大越好,那么两边一定是在中垂线的位置上。
界限上的无疑是最为重要的,除去此之外的就显得没有那么举足轻重了。而对于其他的点符合上面的不等式。那么这就是对于不等式下的一个优化求值问题,而且是区间上的优化问题而不是全值下的优化问题。限制住的区域无疑会给我们带来麻烦,受限制的优化问题。那么如何解决非线性的不等式的优化问题呢:转化成无约束条件下的优化问题——拉格朗日。
Min与Max之间并没有矛盾,因为它们维度不同。错分类点会被非常严厉地惩罚,因此此时不能有错误点。
这个转化问题通过拉格朗日也是极为精彩。约束条件下求极值。在生活中也有很多地方有拉格朗日的影子。对于约束条件被破坏的条件下资源的购买的代价就是拉格朗日乘法子的意义,而在支持向量机中这个乘子就是正无穷(错误的点) ,付出无穷代价。
如果找不到间隔呢?
![](https://i-blog.csdnimg.cn/blog_migrate/b4af1560f93269ac36df23292b525197.png)
运用SVM思维,SVM本质是一种正则化而不是优化。Regulization,是实现一种规范。不是为了训练集而是为了测试集的误差最小,因为数据存在噪声。尽管正则是永恒的主题,但我们总是希望总是能够有一条分割线将两个点分开。而如果对于拉格朗日乘子有了更深入的理解,我们会发现从前我们对于错误会让它们付出无穷的代价之后我们才能不付出高昂的代价,而现在变了,需要容纳这些错误,但是还是对这些错误得进行惩罚,但不是无穷的代价了,而是一定的代价。 根据出错的大小来进行惩罚。这就是具有容错能力我们又称之为——软间隔。下面是数学公式的推导相对于其他资料很容易理解。
事实上SVM同样可以处理无穷维的问题。 下面引出Kernal trick。
核函数
![](https://i-blog.csdnimg.cn/blog_migrate/0f2b1edc24cf48d594a44480dc4abcbc.png)
升维打击与非线性分类。尽管SVM逐渐被深度学习所替代但它的思想永不过时。核函数带来的VC维特别容易过拟合,拟合能力强,但是 SVM本身的正则化又控制这种过拟合(对出错的点的惩罚力度、也可以在非线性项之前加入乘子控制线性到非线性的转变)这就是SVM的强大之处。
C#部分代码展示:
由于事情太多我会对于最近的两篇文章会进行再一次地完善和修改。接下来我打算写点最近在研究的基于改进的的EAST算法的文本识别和Vue尚硅谷的精华重点以及Flask框架,对于元学习的论文和算法也不会停,敬请各位对于文章中的错误进行斧正,对此表示感谢。