欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

程序员文章站 2022-07-18 11:50:04
支持向量机(SVM)是非常强大的机器学习算法,支持线性和非线性的分类任务、回归任务,甚至可以完成离群值检测任务。SVM是机器学习最受欢迎的算法之一,特别适合于比较复杂的中小型数据集上进行建模,如果数据集比较大SVM就显得比较吃力。SVM的核心思想是:生成一条决策边界,使得决策边界离最近点的距离越远越好。0. 导入所需的库import numpy as npimport matplotlib.pyplot as pltimport matplotlib as mpl%matplotlib...

支持向量机(SVM)是非常强大的机器学习算法,支持线性和非线性的分类任务、回归任务,甚至可以完成离群值检测任务。SVM是机器学习最受欢迎的算法之一,特别适合于比较复杂的中小型数据集上进行建模,如果数据集比较大SVM就显得比较吃力。

SVM的核心思想是:生成一条决策边界,使得决策边界离最近点的距离越远越好。

0. 导入所需的库

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
%matplotlib inline
import sklearn

for i in (np, mpl, sklearn):
    print(i.__name__,": ",i.__version__,sep="")

输出:

numpy: 1.17.4
matplotlib: 3.1.2
sklearn: 0.21.3

1. SVM线性分类任务

from sklearn.svm import SVC
from sklearn import datasets

iris = datasets.load_iris()
X = iris["data"][:, (2, 3)]  # 花瓣长度和宽度
y = iris["target"]

setosa_or_versicolor = (y == 0) | (y == 1)
X = X[setosa_or_versicolor]
y = y[setosa_or_versicolor]

# SVM Classifier model
svm_clf = SVC(kernel="linear", C=float("inf"))
svm_clf.fit(X, y)

输出:

SVC(C=inf, cache_size=200, class_weight=None, coef0=0.0,
    decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
    kernel='linear', max_iter=-1, probability=False, random_state=None,
    shrinking=True, tol=0.001, verbose=False)
x0 = np.linspace(0, 5.5, 200)
pred_1 = 5*x0 - 20
pred_2 = x0 - 1.8
pred_3 = 0.1 * x0 + 0.5

def plot_svc_decision_boundary(svm_clf, xmin, xmax):
    w = svm_clf.coef_[0]
    b = svm_clf.intercept_[0]

    # At the decision boundary, w0*x0 + w1*x1 + b = 0
    # => x1 = -w0/w1 * x0 - b/w1
    x0 = np.linspace(xmin, xmax, 200)
    decision_boundary = -w[0]/w[1] * x0 - b/w[1]

    margin = 1/w[1]
    gutter_up = decision_boundary + margin
    gutter_down = decision_boundary - margin

    svs = svm_clf.support_vectors_
    plt.scatter(svs[:, 0], svs[:, 1], s=180, facecolors='#FFAAAA')
    plt.plot(x0, decision_boundary, "k-", linewidth=2)
    plt.plot(x0, gutter_up, "k--", linewidth=2)
    plt.plot(x0, gutter_down, "k--", linewidth=2)

fig, axes = plt.subplots(ncols=2, figsize=(12,5), sharey=True)

plt.sca(axes[0])
plt.plot(x0, pred_1, "r--", linewidth=2)
plt.plot(x0, pred_2, "g-", linewidth=2)
plt.plot(x0, pred_3, "g-", linewidth=2)
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "bs", label="Iris versicolor")
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "yo", label="Iris setosa")
plt.xlabel("Petal length", fontsize=14)
plt.ylabel("Petal width", fontsize=14)
plt.legend(loc="upper left", fontsize=14)
plt.axis([0, 5.5, 0, 2])

plt.sca(axes[1])
plot_svc_decision_boundary(svm_clf, 0, 5.5)
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "bs")
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "yo")
plt.xlabel("Petal length", fontsize=14)
plt.axis([0, 5.5, 0, 2])

plt.tight_layout()
plt.show()

输出:

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

从上图可以看出,两个类别的鸢尾花是线性可分的,即通过一条直线就可以将两种鸢尾花分开。

左图:两条绿色实线能将两个类别正确地分开,但是红色虚线分类是错误的,没有很好地把两类分开。

右图:黑色实线将两类很好地分开,这正是SVM模型所产生的决策边界。这条实现不仅将两个类别正确地分开了,而且这条实线尽可能离最近的点距离最远。

SVM模型中决策边界由间隔边界上的点决定,加入非间隔边界上的数样本不会对决策边界产生影响,而这些间隔边界上的点(样本)组成的向量叫支持向量。

注意:SVM对特征归一化特别敏感,因此使用SVM算法训练模型前一定要对数据进行归一化预处理。未进行归一化和归一化后SVM模型的差别如下图所示:

Xs = np.array([[1, 50], [5, 20], [3, 80], [5, 60]]).astype(np.float64)
ys = np.array([0, 0, 1, 1])
svm_clf = SVC(kernel="linear", C=100)  # 参数C:正则化系数
svm_clf.fit(Xs, ys)

plt.figure(figsize=(12,5))
plt.subplot(121)
plt.plot(Xs[:, 0][ys==1], Xs[:, 1][ys==1], "bo")
plt.plot(Xs[:, 0][ys==0], Xs[:, 1][ys==0], "ms")
plot_svc_decision_boundary(svm_clf, 0, 6)
plt.xlabel("$x_0$", fontsize=20)
plt.ylabel("$x_1$    ", fontsize=20, rotation=0)
plt.title("Unscaled", fontsize=16)
plt.axis([0, 6, 0, 90])

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(Xs)
svm_clf.fit(X_scaled, ys)

plt.subplot(122)
plt.plot(X_scaled[:, 0][ys==1], X_scaled[:, 1][ys==1], "bo")
plt.plot(X_scaled[:, 0][ys==0], X_scaled[:, 1][ys==0], "ms")
plot_svc_decision_boundary(svm_clf, -2, 2)
plt.xlabel("$x_0$", fontsize=20)
plt.ylabel("$x'_1$  ", fontsize=20, rotation=0)
plt.title("Scaled", fontsize=16)
plt.axis([-2, 2, -2, 2])

plt.tight_layout()
plt.show()

输出:

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

2. 软间隔分类(Soft Margin Classification)

硬间隔分类:严格要求所有样本都必须在间隔之外。这时就有两个问题:一是这种模型只能用于严格线性可分的数据,二是这种模型对离群值异常敏感。

软间隔分类:容忍一定数量的样本位于分类间隔中,这样可以增加模型的泛化能力和模型的应用场景。

X_outliers = np.array([[3.4, 1.3], [3.2, 0.8]])
y_outliers = np.array([0, 0])
Xo1 = np.concatenate([X, X_outliers[:1]], axis=0)
yo1 = np.concatenate([y, y_outliers[:1]], axis=0)
Xo2 = np.concatenate([X, X_outliers[1:]], axis=0)
yo2 = np.concatenate([y, y_outliers[1:]], axis=0)

svm_clf2 = SVC(kernel="linear", C=10**9)
svm_clf2.fit(Xo2, yo2)

fig, axes = plt.subplots(ncols=2, figsize=(12,5), sharey=True)

plt.sca(axes[0])
plt.plot(Xo1[:, 0][yo1==1], Xo1[:, 1][yo1==1], "bs")
plt.plot(Xo1[:, 0][yo1==0], Xo1[:, 1][yo1==0], "yo")
plt.text(0.3, 1.0, "Impossible!", fontsize=24, color="red")
plt.xlabel("Petal length", fontsize=14)
plt.ylabel("Petal width", fontsize=14)
plt.annotate("Outlier",
             xy=(X_outliers[0][0], X_outliers[0][1]),
             xytext=(2.5, 1.7),
             ha="center",
             arrowprops=dict(facecolor='black', shrink=0.1),
             fontsize=16,
            )
plt.axis([0, 5.5, 0, 2])

plt.sca(axes[1])
plt.plot(Xo2[:, 0][yo2==1], Xo2[:, 1][yo2==1], "bs")
plt.plot(Xo2[:, 0][yo2==0], Xo2[:, 1][yo2==0], "yo")
plot_svc_decision_boundary(svm_clf2, 0, 5.5)
plt.xlabel("Petal length", fontsize=14)
plt.annotate("Outlier",
             xy=(X_outliers[1][0], X_outliers[1][1]),
             xytext=(3.2, 0.08),
             ha="center",
             arrowprops=dict(facecolor='black', shrink=0.1),
             fontsize=16,
            )
plt.axis([0, 5.5, 0, 2])
plt.tight_layout()
plt.show()

输出:

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

如上所示,左图中有一个黄色离群点,此时就无法用硬间隔SVM进行分类。而右图中也存在一个黄色离群点,但幸好可以用硬间隔SVM分类,但是与之前的图进行对比发现,决策间隔变小了很多很多,也就是说模型的泛化能力下降很多。

以上这种存在离群值的数据是日常实际应用是更常见的情况,而解决这种问题软间隔SVM分类就比较拿手。

from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC

iris = datasets.load_iris()
X = iris["data"][:,(2,3)] # 选择花瓣长度和宽度属性
y = (iris["target"]==2).astype(np.float64)

svm_clf = Pipeline([
    ("scaler",StandardScaler()),
    ("linear_svc",LinearSVC(C=1,loss="hinge",random_state=42))
])

svm_clf.fit(X,y)

输出:

Pipeline(memory=None,
         steps=[('scaler',
                 StandardScaler(copy=True, with_mean=True, with_std=True)),
                ('linear_svc',
                 LinearSVC(C=1, class_weight=None, dual=True,
                           fit_intercept=True, intercept_scaling=1,
                           loss='hinge', max_iter=1000, multi_class='ovr',
                           penalty='l2', random_state=42, tol=0.0001,
                           verbose=0))],
         verbose=False)
svm_clf.predict([[5.5,1.7]])

输出:

array([1.])

与逻辑回归分类器不一样,SVM只输出最终的类别,不会输出属于每个类别的概率。

注意:LinearSVC同样会对偏置项进行正则化,因此需要对训练集先做减平均值的操作,这种操作由StandardScaler自动完成。同时需要注意需要将超参数loss的值设置为hinge。最后为了达到更好的性能和效果,需要将超参数dual设置为False,除非训练集中特征数目大于训练样本数。

scaler = StandardScaler()
svm_clf1 = LinearSVC(C=1, loss="hinge", random_state=42)
svm_clf2 = LinearSVC(C=100, loss="hinge", random_state=42)

scaled_svm_clf1 = Pipeline([
        ("scaler", scaler),
        ("linear_svc", svm_clf1),
    ])
scaled_svm_clf2 = Pipeline([
        ("scaler", scaler),
        ("linear_svc", svm_clf2),
    ])

scaled_svm_clf1.fit(X, y)
scaled_svm_clf2.fit(X, y)

输出:

Pipeline(memory=None,
         steps=[('scaler',
                 StandardScaler(copy=True, with_mean=True, with_std=True)),
                ('linear_svc',
                 LinearSVC(C=100, class_weight=None, dual=True,
                           fit_intercept=True, intercept_scaling=1,
                           loss='hinge', max_iter=1000, multi_class='ovr',
                           penalty='l2', random_state=42, tol=0.0001,
                           verbose=0))],
         verbose=False)
# Convert to unscaled parameters
b1 = svm_clf1.decision_function([-scaler.mean_ / scaler.scale_])
b2 = svm_clf2.decision_function([-scaler.mean_ / scaler.scale_])
w1 = svm_clf1.coef_[0] / scaler.scale_
w2 = svm_clf2.coef_[0] / scaler.scale_
svm_clf1.intercept_ = np.array([b1])
svm_clf2.intercept_ = np.array([b2])
svm_clf1.coef_ = np.array([w1])
svm_clf2.coef_ = np.array([w2])

# Find support vectors (LinearSVC does not do this automatically)
t = y * 2 - 1
support_vectors_idx1 = (t * (X.dot(w1) + b1) < 1).ravel()
support_vectors_idx2 = (t * (X.dot(w2) + b2) < 1).ravel()
svm_clf1.support_vectors_ = X[support_vectors_idx1]
svm_clf2.support_vectors_ = X[support_vectors_idx2]
fig, axes = plt.subplots(ncols=2, figsize=(12,5), sharey=True)

plt.sca(axes[0])
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^", label="Iris virginica")
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "bs", label="Iris versicolor")
plot_svc_decision_boundary(svm_clf1, 4, 5.9)
plt.xlabel("Petal length", fontsize=14)
plt.ylabel("Petal width", fontsize=14)
plt.legend(loc="upper left", fontsize=14)
plt.title("$C = {}$".format(svm_clf1.C), fontsize=16)
plt.axis([4, 5.9, 0.8, 2.8])

plt.sca(axes[1])
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^")
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "bs")
plot_svc_decision_boundary(svm_clf2, 4, 5.99)
plt.xlabel("Petal length", fontsize=14)
plt.title("$C = {}$".format(svm_clf2.C), fontsize=16)
plt.axis([4, 5.9, 0.8, 2.8])

plt.tight_layout()
plt.show()

输出:

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

sklearn超参数C指定了这种容忍的程度,C值越小,容忍度越大,反之越小。注意:如果SVM过拟合,可以通过减小C值调整模型。

3. SVM非线性分类任务

虽然SVM线性分类器效果很好,但是实际应用中有些数据往往是线性不可分的。解决线性不可分问题的办法之一是添加更多的特征,例如添加多项式特征。

3.1 SVM解决非线性可分问题

X1D = np.linspace(-4, 4, 9).reshape(-1, 1)
X2D = np.c_[X1D, X1D**2]
y = np.array([0, 0, 1, 1, 1, 1, 1, 0, 0])

plt.figure(figsize=(12, 5))

plt.subplot(121)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.plot(X1D[:, 0][y==0], np.zeros(4), "bs")
plt.plot(X1D[:, 0][y==1], np.zeros(5), "g^")
plt.gca().get_yaxis().set_ticks([])
plt.xlabel(r"$x_1$", fontsize=20)
plt.axis([-4.5, 4.5, -0.2, 0.2])

plt.subplot(122)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.plot(X2D[:, 0][y==0], X2D[:, 1][y==0], "bs")
plt.plot(X2D[:, 0][y==1], X2D[:, 1][y==1], "g^")
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"$x_2$  ", fontsize=20, rotation=0)
plt.gca().get_yaxis().set_ticks([0, 4, 8, 12, 16])
plt.plot([-4.5, 4.5], [6.5, 6.5], "r--", linewidth=3)
plt.axis([-4.5, 4.5, -1, 17])

plt.subplots_adjust(right=1)

plt.tight_layout()
plt.show()

输出:

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

观察上面左图,数据只有一个特征x1,分别有绿色和蓝色两类点,可以看出无法用一条直线将它们分开。

如果增加一个特征,即x1的平方,此时再观察右图就可以发现这两类点可以用一条直线分开。

感觉增加多项式特征在解决线性不可分问题还是很有用的,现在尝试将其运用在moon数据集上:

from sklearn.datasets import make_moons
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures

X,y = make_moons(n_samples=100, noise=0.15, random_state=42)

def plot_dataset(X,y,axes):
    #plt.figure(figsize=(8,5))
    plt.plot(X[:,0][y==0],X[:,1][y==0],"bs")
    plt.plot(X[:,0][y==1],X[:,1][y==1],"g^")
    plt.axis(axes)
    plt.grid(True,which="both")
    plt.xlabel("$x_1$",fontsize=20)
    plt.ylabel("$x_2$",fontsize=20,rotation=0)
    
plot_dataset(X,y,[-1.5,2.5,-1,1.5])
plt.show()

输出:

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

polynomial_svm_clf = Pipeline([
    ("poly_features",PolynomialFeatures(degree=3)),
    ("scaler",StandardScaler()),
    ("svm_clf",LinearSVC(C=10,loss="hinge", random_state=42))
])
polynomial_svm_clf.fit(X,y)

输出:

Pipeline(memory=None,
         steps=[('poly_features',
                 PolynomialFeatures(degree=3, include_bias=True,
                                    interaction_only=False, order='C')),
                ('scaler',
                 StandardScaler(copy=True, with_mean=True, with_std=True)),
                ('svm_clf',
                 LinearSVC(C=10, class_weight=None, dual=True,
                           fit_intercept=True, intercept_scaling=1,
                           loss='hinge', max_iter=1000, multi_class='ovr',
                           penalty='l2', random_state=42, tol=0.0001,
                           verbose=0))],
         verbose=False)
def plot_predictions(clf, axes):
    x0s = np.linspace(axes[0],axes[1],100)
    x1s = np.linspace(axes[2],axes[3],100)
    x0, x1 = np.meshgrid(x0s, x1s)
    
    X = np.c_[x0.ravel(),x1.ravel()]
    y_pred = clf.predict(X).reshape(x0.shape)
    y_decision = clf.decision_function(X).reshape(x0.shape)
    plt.contourf(x0,x1,y_pred,cmap=plt.cm.brg, alpha=0.2)
    plt.contourf(x0,x1,y_decision, cmap=plt.cm.brg,alpha=0.1)
    
plot_predictions(polynomial_svm_clf, [-1.5,2.5,-1,1.5])
plot_dataset(X,y,[-1.5,2.5,-1,1.5])

plt.show()

输出:

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

从上述输出结果可以看出,线性不可分的二分类问题经过添加多项式特征后变得可分了。

3.2 多项式核

添加多项式特征的方法比较简单,而且在很多机器学习算法中都可以使用。但是如果多项式次数不够高,则无法处理比较复杂的数据,如果次数太高,则会产生大量的特征从而导致模型训练会很慢很慢。

然而为了解决如上的矛盾,SVM中存在kernel trick(核技巧)的方法,核技巧可以达到添加高次多项式的效果,但不会真正添加到数据中,所以也就不存在维数爆炸的现象。

from sklearn.svm import SVC

poly_kernel_svm_clf = Pipeline([
    ("scaler",StandardScaler()),
    ("svm_clf",SVC(kernel="poly",degree=3,coef0=1,C=5))
])

poly_kernel_svm_clf.fit(X,y)

输出:

Pipeline(memory=None,
         steps=[('scaler',
                 StandardScaler(copy=True, with_mean=True, with_std=True)),
                ('svm_clf',
                 SVC(C=5, cache_size=200, class_weight=None, coef0=1,
                     decision_function_shape='ovr', degree=3,
                     gamma='auto_deprecated', kernel='poly', max_iter=-1,
                     probability=False, random_state=None, shrinking=True,
                     tol=0.001, verbose=False))],
         verbose=False)
poly100_kernel_svm_clf = Pipeline([
    ("scaler",StandardScaler()),
    ("svm_clf",SVC(kernel="poly",degree=10,coef0=100,C=5))
])

poly100_kernel_svm_clf.fit(X,y)

输出:

Pipeline(memory=None,
         steps=[('scaler',
                 StandardScaler(copy=True, with_mean=True, with_std=True)),
                ('svm_clf',
                 SVC(C=5, cache_size=200, class_weight=None, coef0=100,
                     decision_function_shape='ovr', degree=10,
                     gamma='auto_deprecated', kernel='poly', max_iter=-1,
                     probability=False, random_state=None, shrinking=True,
                     tol=0.001, verbose=False))],
         verbose=False)
fig, axes = plt.subplots(ncols=2,figsize=(12,5),sharey=True)

plt.sca(axes[0])
plot_predictions(poly_kernel_svm_clf,[-1.5,2.45,-1,1.5])
plot_dataset(X,y,[-1.5,2.4,-1,1.5])
plt.title(r"$d=3, r=1, C=5$",fontsize=18)

plt.sca(axes[1])
plot_predictions(poly100_kernel_svm_clf, [-1.5,2.45,-1,1.5])
plot_dataset(X,y,[-1.5,2.45,-1,1.5])
plt.title(r"$d=10, r=100, C=5$",fontsize=18)
plt.ylabel("")

plt.tight_layout()
plt.show()

输出:

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

如上图所示,左边是利用SVM三次多项式核训练的模型效果,右边是10次多项式核模型。观察发现,如果模型过拟合,就需要降低degree的值,反之如果欠拟合,就需要增大degree的值。

超参数coef0控制模型受高次多项式和低次多项式影响的程度。

3.3 相似特征

上面介绍了解决线性不可分问题的解决方法之一,即添加多项式特征。

解决线性不可分问题另一个方法是添加利用相似函数计算的特征。 相似函数计算样本与特定目标相似的程度。

def gaussian_rbf(x, landmark, gamma): # 高斯径向基函数
    return np.exp(-gamma * np.linalg.norm(x - landmark, axis=1)**2)

gamma = 0.3

x1s = np.linspace(-4.5, 4.5, 200).reshape(-1, 1)
x2s = gaussian_rbf(x1s, -2, gamma)
x3s = gaussian_rbf(x1s, 1, gamma)

XK = np.c_[gaussian_rbf(X1D, -2, gamma), gaussian_rbf(X1D, 1, gamma)]
yk = np.array([0, 0, 1, 1, 1, 1, 1, 0, 0])

plt.figure(figsize=(12, 5))

plt.subplot(121)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.scatter(x=[-2, 1], y=[0, 0], s=150, alpha=0.5, c="red")
plt.plot(X1D[:, 0][yk==0], np.zeros(4), "bs")
plt.plot(X1D[:, 0][yk==1], np.zeros(5), "g^")
plt.plot(x1s, x2s, "g--")
plt.plot(x1s, x3s, "b:")
plt.gca().get_yaxis().set_ticks([0, 0.25, 0.5, 0.75, 1])
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"Similarity", fontsize=14)
plt.annotate(r'$\mathbf{x}$',
             xy=(X1D[3, 0], 0),
             xytext=(-0.5, 0.20),
             ha="center",
             arrowprops=dict(facecolor='black', shrink=0.1),
             fontsize=18,
            )
plt.text(-2, 0.9, "$x_2$", ha="center", fontsize=20)
plt.text(1, 0.9, "$x_3$", ha="center", fontsize=20)
plt.axis([-4.5, 4.5, -0.1, 1.1])

plt.subplot(122)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.plot(XK[:, 0][yk==0], XK[:, 1][yk==0], "bs")
plt.plot(XK[:, 0][yk==1], XK[:, 1][yk==1], "g^")
plt.xlabel(r"$x_2$", fontsize=20)
plt.ylabel(r"$x_3$  ", fontsize=20, rotation=0)
plt.annotate(r'$\phi\left(\mathbf{x}\right)$',
             xy=(XK[3, 0], XK[3, 1]),
             xytext=(0.65, 0.50),
             ha="center",
             arrowprops=dict(facecolor='black', shrink=0.1),
             fontsize=18,
            )
plt.plot([-0.1, 1.1], [0.57, -0.1], "r--", linewidth=3)
plt.axis([-0.1, 1.1, -0.1, 1.1])
    
plt.subplots_adjust(right=1)
plt.tight_layout()
plt.show()

输出:

基于Scikit-Learn、Keras和TensorFlow2支持向量机(Support Vector Machine)

上图左图所示,我们分别在x=-2和x=1处添加两个landmarks。

此时,定义相似函数为高斯径向基函数(Gaussian Radial Basis Function,RBF),