凌云时刻 · 技术
导读:我们在 机器学习笔记十六之多项式回归、拟合程度、模型泛化 中讲过线性回归通过多项式回归方法处理非线性问题,同样SVM也可以使用多项式方法处理非线性问题。
作者 | 计缘
来源 | 凌云时刻(微信号:linuxpk)
SVM处理非线性问题
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
# 使用datasets提供的方法构建非线性数据
X, y = datasets.make_moons()
我们可以使用datasets
提供的make_moons()
函数生成非线性数据,默认为100行2列的矩阵,既100个样本数据,每个样本数据2个特征。可以使用n_samples
参数指定样本数据数量。我们将其绘制出来看看:
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()
可以看到make_moons()
默认生成的数据绘制出的图像是两个规整的半月牙曲线。但是作为样本数据有点太规整了,所以我们可以使用noise
参数给生成的数据增加一点噪音:
X, y = datasets.make_moons(noise=0.15)
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()
可以看到,增加了噪音后虽然数据点较之前的分布分散随机了许多,但整体仍然是两个半月牙形状。下面我们就在SVM的基础上使用多项式来看看对这个样本数据决策边界的计算:
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
首先我们需要引入我们用到的几个类:
多项式自然要用到之前讲过的
PolynomialFeatures
类。数据归一化需要用到
StandardScaler
类。同样需要用到Pipeline将多个过程封装在一个函数里,所以要用到
Pipeline
类。
# 定义多项式SVM函数
def PolynomialSVC(degree, C=1.0):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
("std_scaler", StandardScaler()),
("linearSVC", LinearSVC(C=C))
])
# 使用多项式SVM训练样本数据
ploy_svc = PolynomialSVC(degree=3)
ploy_svc.fit(X, y)
def plot_decision_boundary(model, axis):
# meshgrid函数用两个坐标轴上的点在平面上画格,返回坐标矩阵
X0, X1 = np.meshgrid(
# 随机两组数,起始值和密度由坐标轴的起始值决定
np.linspace(axis[0], axis[1], int((axis[1] - axis[0]) * 100)).reshape(-1, 1),
np.linspace(axis[2], axis[3], int((axis[3] - axis[2]) * 100)).reshape(-1, 1),
)
# ravel()方法将高维数组降为一维数组,c_[]将两个数组以列的形式拼接起来,形成矩阵
X_grid_matrix = np.c_[X0.ravel(), X1.ravel()]
# 通过训练好的逻辑回归模型,预测平面上这些点的分类
y_predict = model.predict(X_grid_matrix)
y_predict_matrix = y_predict.reshape(X0.shape)
# 设置色彩表
from matplotlib.colors import ListedColormap
my_colormap = ListedColormap(['#0000CD', '#40E0D0', '#FFFF00'])
# 绘制等高线,并且填充等高区域的颜色
plt.contourf(X0, X1, y_predict_matrix, linewidth=5, cmap=my_colormap)
plot_decision_boundary(ploy_svc, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()
从上图可以看到决策边界的情况,很明显已经不是线性决策边界了,并且能较好的将两类点区分开。
核函数(Kernel Function)
核函数是机器学习算法中一个重要的概念。简单来讲,核函数就是样本数据点的转换函数。之所以在SVM这篇笔记中介绍核函数,是因为在SVM处理非线性的问题中除了上一节介绍的方法外,还有使用核函数的方式。而介绍核函数的切入点也是通过多项式这个知识点来讲的。
首先我们回顾一下多项式方法。对样本数据进行多项式转换并不是真正的增加了样本数据的特征数量,而且对原有的特征数据进行转换,构造出其他特征,这些新构造出的特征和原始特征都有强关联。
比如如果将原本只有 、 两个特征的样本数据通过多项式转换为有10个特征的数据,那么转换后的这10个特征分别为 , , , , , , , , ,
假设某个机器学习算法的原始公式中含有 ( 和 为特征向量),如果是使用多项式的方法,那么首先需要将 和 转换为 和 ,然后转换后的,具有10个元素的两个新特征向量再相乘。如果转换后的特征数量比较多的时候,新特征向量的计算复杂度就会变的很高,并且还需要占用大量内存在存储庞大的特征向量。
那么核函数就是要解决上面的问题。所以多项式核函数就是有这样一个函数,将 和 作为参数传入,再指定要构造的特征数,然后该函数直接返回 的值。该函数既可以模拟多项式构造特征的原理,又能将新特征向量的点乘计算出来,同时计算复杂度相对比较小,而且也不用存储庞大的新特征向量。
下面就来看看多项式核函数:
我们将上面的公式展开来看看:
应用任意次项和的展开式公式,上面的公式继续展开后得:
上面的公式我们就可以看做是若干项相乘再相加,对于 来说:
从 可以分析出共有 这么多项。
从 可以分析出共有 这么多项。
从 可以分析出共有
将上面的三个向量合起来其实就相当于将原始xx特征向量根据多项式原理转换后的新的特征向量 :
根据同样的道理,也可以得出新的 。所以将 展开后的公式就相当于 。
综上多项式核函数的公式为:
代表多项式中的degree, 代表Soft Margin SVM中的 ,是两个超参数。
以上是通过多项式核函数解释核函数的概念和数学原理,那么不同的机器学习算法里有很多不同的核函数,对应对原始样本数据不同的转换。
我们再回过头来看看SVM解决非线性的问题,之前我们使用常规的多项式方法,这节我们来看看如何使用核函数:
from sklearn.svm import SVC
def PolynomailKernelSVC(degree, C=1):
return Pipeline([
("std_scaler", StandardScaler()),
("kernelSVC", SVC(kernel="poly", degree=degree, C=C))
])
poly_kernel_svc = PolynomailKernelSVC(degree=3)
poly_kernel_svc.fit(X, y)
plot_decision_boundary(poly_kernel_svc, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()
Scikit Learn中使用了多项式核函数的SVM的类是SVC
,它的kernel
参数就表示要使用哪种核函数,上面示例中传入的poly
就表示多项式核函数。
END
往期精彩文章回顾
机器学习笔记(二十六):支撑向量机(SVM)(2)
机器学习笔记(二十五):支撑向量机(SVM)
机器学习笔记(二十四):召回率、混淆矩阵
机器学习笔记(二十三):算法精准率、召回率
机器学习笔记(二十二):逻辑回归中使用模型正则化
机器学习笔记(二十一):决策边界
机器学习笔记(二十):逻辑回归(2)
机器学习笔记(十九):逻辑回归
机器学习笔记(十八):模型正则化
机器学习笔记(十七):交叉验证
长按扫描二维码关注凌云时刻
每日收获前沿技术与科技洞见