.. _svm: ======================= 支持向量机 ======================= .. TODO: 描述 tol 参数 .. TODO: 描述 max_iter 参数 .. currentmodule:: sklearn.svm **支持向量机(SVMs)** 是一组用于监督学习的算法,用于 :ref:`分类 ` 、 :ref:`回归 ` 和 :ref:`异常检测 ` 。 支持向量机的优点包括: - 在高维空间中有效。 - 在维数大于样本数的情况下仍然有效。 - 使用决策函数中的一小部分训练点(称为支持向量),因此内存效率高。 - 多功能性:可以为决策函数指定不同的 :ref:`svm_kernels` 。提供了常见的核函数,但也可以指定自定义核函数。 支持向量机的缺点包括: - 如果特征数量远大于样本数量,选择 :ref:`svm_kernels` 和正则化项以避免过拟合至关重要。 - SVMs 不直接提供概率估计,这些估计是通过昂贵的五折交叉验证计算的(参见 :ref:`Scores and probabilities ` ,下文)。 scikit-learn 中的支持向量机支持密集( ``numpy.ndarray`` 和可由 ``numpy.asarray`` 转换的类型)和稀疏(任何 ``scipy.sparse`` )样本向量作为输入。然而,要使用 SVM 对稀疏数据进行预测,必须对这种数据进行拟合。为了获得最佳性能,请使用 C 顺序的 ``numpy.ndarray`` (密集)或 ``scipy.sparse.csr_matrix`` (稀疏),类型为 ``dtype=float64`` 。 .. _svm_classification: 分类 ============== :class:`SVC` 、:class:`NuSVC` 和 :class:`LinearSVC` 是能够在数据集上执行二分类和多分类的类。 .. figure:: ../auto_examples/svm/images/sphx_glr_plot_iris_svc_001.png :target: ../auto_examples/svm/plot_iris_svc.html :align: center :class:`SVC` 和 :class:`NuSVC` 是相似的方法,但接受稍微不同的参数集并具有不同的数学公式(参见章节 :ref:`svm_mathematical_formulation` )。另一方面,:class:`LinearSVC` 是另一种(更快的)线性核情况下的支持向量分类实现。它也缺乏 :class:`SVC` 和 :class:`NuSVC` 的一些属性,如 `support_` 。:class:`LinearSVC` 使用 `squared_hinge` 损失,并且由于其在 `liblinear` 中的实现,它还会对截距进行正则化,如果考虑的话。然而,通过仔细调整其 `intercept_scaling` 参数,可以减少这种影响,该参数允许截距项与其他特征相比具有不同的正则化行为。因此,分类结果和得分可能与其他两个分类器不同。 与其他分类器一样, :class:`SVC` 、:class:`NuSVC` 和 :class:`LinearSVC` 接受两个数组作为输入:一个形状为 `(n_samples, n_features)` 的数组 `X` 保存训练样本,以及一个类标签(字符串或整数)的数组 `y` ,形状为 `(n_samples)` :: >>> from sklearn import svm >>> X = [[0, 0], [1, 1]] >>> y = [0, 1] >>> clf = svm.SVC() >>> clf.fit(X, y) SVC() 拟合后,该模型可用于预测新值:: >>> clf.predict([[2., 2.]]) array([1]) SVM 的决策函数(在 :ref:`svm_mathematical_formulation` 中详细说明)依赖于训练数据的一个子集,称为支持向量。这些支持向量的一些属性可以在 `support_vectors_` 、 `support_` 和 `n_support_` 属性中找到:: >>> # 获取支持向量 >>> clf.support_vectors_ array([[0., 0.], [1., 1.]]) >>> # 获取支持向量的索引 >>> clf.support_ array([0, 1]...) >>> # 获取每个类的支持向量数量 >>> clf.n_support_ array([1, 1]...) .. rubric:: 示例 * :ref:`sphx_glr_auto_examples_svm_plot_separating_hyperplane.py` * :ref:`sphx_glr_auto_examples_svm_plot_svm_anova.py` .. _svm_multi_class: 多类分类 -------------------------- :class:`SVC` 和 :class:`NuSVC` 实现了多类分类的“一对一”方法。总共构建了 ``n_classes * (n_classes - 1) / 2`` 个分类器,每个分类器训练来自两个类的数据。为了与其他分类器提供一致的接口, ``decision_function_shape`` 选项允许将“一对一”分类器的结果单调地转换为形状为 ``(n_samples, n_classes)`` 的“一对多”决策函数。 >>> X = [[0], [1], [2], [3]] >>> Y = [0, 1, 2, 3] >>> clf = svm.SVC(decision_function_shape='ovo') >>> clf.fit(X, Y) SVC(decision_function_shape='ovo') >>> dec = clf.decision_function([[1]]) >>> dec.shape[1] # 6 个类:4*3/2 = 6 6 >>> clf.decision_function_shape = "ovr" >>> dec = clf.decision_function([[1]]) >>> dec.shape[1] # 4 个类 4 另一方面,:class:`LinearSVC` 实现了“一对多”的多类策略,从而训练了 `n_classes` 个模型。 >>> lin_clf = svm.LinearSVC() >>> lin_clf.fit(X, Y) LinearSVC() >>> dec = lin_clf.decision_function([[1]]) >>> dec.shape[1] 4 有关决策函数的完整描述,请参见 :ref:`svm_mathematical_formulation` 。 .. dropdown:: 多类策略的详细信息 请注意,:class:`LinearSVC` 还实现了另一种多类策略,即由 Crammer 和 Singer [#8]_ 提出的多类 SVM,通过使用选项 ``multi_class='crammer_singer'`` 。在实践中,通常首选“一对多”分类,因为结果大多相似,但运行时间显著减少。 对于“一对多”的 :class:`LinearSVC` ,属性 ``coef_`` 和 ``intercept_`` 具有形状 ``(n_classes, n_features)`` 和 ``(n_classes,)`` 分别。 系数矩阵的每一行对应于 ``n_classes`` 个 "一对多" 分类器中的一个, 截距也是如此,按照 "一" 类的顺序排列。 在 "一对一" :class:`SVC` 和 :class:`NuSVC` 的情况下,属性的布局稍微复杂一些。 对于线性核,属性 ``coef_`` 和 ``intercept_`` 的形状分别为 ``(n_classes * (n_classes - 1) / 2, n_features)`` 和 ``(n_classes * (n_classes - 1) / 2)`` 。这与上述 :class:`LinearSVC` 的布局类似, 每行现在对应于一个二分类器。类的顺序从 0 到 n 是 "0 对 1","0 对 2",... "0 对 n", "1 对 2","1 对 3","1 对 n",... "n-1 对 n"。 ``dual_coef_`` 的形状是 ``(n_classes-1, n_SV)`` ,布局有点难以理解。 列对应于参与任何 ``n_classes * (n_classes - 1) / 2`` 个 "一对一" 分类器的支持向量。 每个支持向量 ``v`` 在比较 ``v`` 所属类与其他类的 ``n_classes - 1`` 个分类器中都有一个对偶系数。 注意,这些对偶系数中的一些(但不是全部)可能为零。 每列中的 ``n_classes - 1`` 个条目是这些对偶系数,按对立类的顺序排列。 这可能通过一个例子更清楚:考虑一个三类问题,类 0 有三个支持向量 :math:`v^{0}_0, v^{1}_0, v^{2}_0` ,类 1 和 2 各有两个支持向量 :math:`v^{0}_1, v^{1}_1` 和 :math:`v^{0}_2, v^{1}_2` 。对于每个支持向量 :math:`v^{j}_i` , 有两个对偶系数。我们将在类 :math:`i` 和 :math:`k` 之间的分类器中支持向量 :math:`v^{j}_i` 的系数称为 :math:`\alpha^{j}_{i,k}` 。 那么 ``dual_coef_`` 看起来像这样: +------------------------+------------------------+------------------------+------------------------+------------------------+------------------------+------------------------+ |:math:`\alpha^{0}_{0,1}` |:math:`\alpha^{1}_{0,1}` |:math:`\alpha^{2}_{0,1}` |:math:`\alpha^{0}_{1,0}` |:math:`\alpha^{1}_{1,0}` |:math:`\alpha^{0}_{2,0}` |:math:`\alpha^{1}_{2,0}` | +------------------------+------------------------+------------------------+------------------------+------------------------+------------------------+------------------------+ |:math:`\alpha^{0}_{0,2}` |:math:`\alpha^{1}_{0,2}` |:math:`\alpha^{2}_{0,2}` |:math:`\alpha^{0}_{1,2}` |:math:`\alpha^{1}_{1,2}` |:math:`\alpha^{0}_{2,1}` |:math:`\alpha^{1}_{2,1}` | +------------------------+------------------------+------------------------+------------------------+------------------------+------------------------+------------------------+ |类0支持向量的系数 |类1支持向量的系数 |类2支持向量的系数 | +--------------------------------------------------------------------------+-------------------------------------------------+-------------------------------------------------+ .. rubric:: 示例 * :ref:`sphx_glr_auto_examples_svm_plot_iris_svc.py` .. _scores_probabilities: 分数和概率 ------------------------ :class:`SVC` 和 :class:`NuSVC` 的 ``decision_function`` 方法为每个样本提供每个类的分数(或在二元情况下为每个样本提供单个分数)。当构造函数选项 ``probability`` 设置为 ``True`` 时,启用类成员概率估计(通过 ``predict_proba`` 和 ``predict_log_proba`` 方法)。在二元情况下,概率是 使用Platt缩放 [#1]_ 进行校准:在SVM的分数上进行逻辑回归,通过在训练数据上的额外交叉验证进行拟合。 在多类别情况下,此方法按照 [#2]_ 进行扩展。 .. note:: 相同的概率校准过程可通过 :class:`~sklearn.calibration.CalibratedClassifierCV` 适用于所有估计器(参见 :ref:`calibration` )。对于 :class:`SVC` 和 :class:`NuSVC` ,此过程内置于 `libsvm`_ 中,该库在底层使用,因此不依赖于 scikit-learn 的 :class:`~sklearn.calibration.CalibratedClassifierCV` 。 Platt缩放中涉及的交叉验证对于大型数据集来说是一项昂贵的操作。 此外,概率估计可能与分数不一致: - 分数的“最大值”可能不是概率的最大值 - 在二分类中,样本可能被 ``predict`` 标记为属于正类,即使 `predict_proba` 的输出小于0.5;同样地,它可能被标记为负类,即使 `predict_proba` 的输出大于0.5。 Platt的方法也存在理论上的问题。 如果需要置信度分数,但这些不必须是概率,则建议设置 ``probability=False`` 并使用 ``decision_function`` 而不是 ``predict_proba`` 。 请注意,当 ``decision_function_shape='ovr'`` 且 ``n_classes > 2`` 时,与 ``decision_function`` 不同, ``predict`` 方法默认不会尝试打破平局。您可以设置 ``break_ties=True`` ,使 ``predict`` 的输出与 ``np.argmax(clf.decision_function(...), axis=1)`` 相同,否则将始终返回平局类别中的第一个类别;但请注意,这会带来计算成本。参见 :ref:`sphx_glr_auto_examples_svm_plot_svm_tie_breaking.py` 以了解关于打破平局的示例。 不平衡问题 -------------------- 在希望对某些样本给予更多重要性的问题中, 对于类别不平衡的分类问题或某些个别样本,可以使用参数 ``class_weight`` 和 ``sample_weight`` 。 :class:`SVC` (但不包括 :class:`NuSVC` )在 ``fit`` 方法中实现了参数 ``class_weight`` 。它是一个形式为 ``{class_label : value}`` 的字典,其中 value 是一个大于 0 的浮点数,用于将类别 ``class_label`` 的参数 ``C`` 设置为 ``C * value`` 。下图展示了在不平衡问题中,有和没有权重校正的决策边界。 .. figure:: ../auto_examples/svm/images/sphx_glr_plot_separating_hyperplane_unbalanced_001.png :target: ../auto_examples/svm/plot_separating_hyperplane_unbalanced.html :align: center :scale: 75 :class:`SVC` 、:class:`NuSVC` 、:class:`SVR` 、:class:`NuSVR` 、:class:`LinearSVC` 、:class:`LinearSVR` 和 :class:`OneClassSVM` 还通过 ``fit`` 方法中的 ``sample_weight`` 参数实现了对个别样本的权重。类似于 ``class_weight`` ,这会将第 i 个样本的参数 ``C`` 设置为 ``C * sample_weight[i]`` ,从而鼓励分类器正确处理这些样本。下图展示了样本权重对决策边界的影响。圆圈的大小与样本权重成正比: .. figure:: ../auto_examples/svm/images/sphx_glr_plot_weighted_samples_001.png :target: ../auto_examples/svm/plot_weighted_samples.html :align: center :scale: 75 .. rubric:: 示例 * :ref:`sphx_glr_auto_examples_svm_plot_separating_hyperplane_unbalanced.py` * :ref:`sphx_glr_auto_examples_svm_plot_weighted_samples.py` .. _svm_regression: 回归 ==== 支持向量分类的方法可以扩展到解决回归问题。这种方法称为支持向量回归。 支持向量分类(如上所述)产生的模型仅依赖于训练数据的一个子集,因为构建模型的成本函数不关心训练点 那些超出边界的点。类似地,支持向量回归(Support Vector Regression)生成的模型仅依赖于训练数据的一个子集,因为其成本函数忽略了预测值接近目标值的样本。 支持向量回归有三种不同的实现方式::class:`SVR` 、:class:`NuSVR` 和 :class:`LinearSVR` 。:class:`LinearSVR` 提供了比 :class:`SVR` 更快的实现,但仅考虑线性核函数,而 :class:`NuSVR` 实现了与 :class:`SVR` 和 :class:`LinearSVR` 略有不同的公式。由于在 `liblinear` 中的实现,:class:`LinearSVR` 还会对截距进行正则化(如果考虑的话)。然而,通过仔细调整其 `intercept_scaling` 参数,可以减少这种影响,该参数允许截距项与其他特征具有不同的正则化行为。因此,分类结果和评分可能与其他两个分类器不同。更多细节请参见 :ref:`svm_implementation_details` 。 与分类类一样,fit 方法将接受向量 X 和 y 作为参数,只是在这种情况下,y 预期具有浮点数值而不是整数值:: >>> from sklearn import svm >>> X = [[0, 0], [2, 2]] >>> y = [0.5, 2.5] >>> regr = svm.SVR() >>> regr.fit(X, y) SVR() >>> regr.predict([[1, 1]]) array([1.5]) .. rubric:: 示例 * :ref:`sphx_glr_auto_examples_svm_plot_svm_regression.py` .. _svm_outlier_detection: 密度估计,新颖性检测 ======================================= 类 :class:`OneClassSVM` 实现了一个用于异常检测的一类支持向量机(One-Class SVM)。 有关 OneClassSVM 的描述和使用,请参见 :ref:`outlier_detection` 。 复杂度 ========== 支持向量机是强大的工具,但其计算和存储需求随着训练向量数量的增加而迅速增长。支持向量机的核心是一个二次规划问题(QP), 分离支持向量与训练数据的其余部分。 `libsvm`_ 基于的实现所使用的 QP 求解器在 :math:`O(n_{features} \times n_{samples}^2)` 和 :math:`O(n_{features} \times n_{samples}^3)` 之间缩放,具体取决于 `libsvm`_ 缓存在实践中使用的效率(数据集依赖)。如果数据非常稀疏,:math:`n_{features}` 应替换为样本向量中非零特征的平均数量。 对于线性情况, `liblinear`_ 实现的 :class:`LinearSVC` 所使用的算法比基于 `libsvm`_ 的 :class:`SVC` 对应算法效率高得多,并且几乎可以线性缩放到数百万个样本和/或特征。 实用使用技巧 ============ * **避免数据复制**:对于 :class:`SVC` 、:class:`SVR` 、:class:`NuSVC` 和 :class:`NuSVR` ,如果传递给某些方法的数据不是 C 顺序连续且为双精度,则在调用底层 C 实现之前会进行复制。您可以通过检查其 ``flags`` 属性来检查给定的 numpy 数组是否为 C 连续。 对于 :class:`LinearSVC` (以及 :class:`LogisticRegression ` ),任何作为 numpy 数组传递的输入都将被复制并转换为 `liblinear`_ 内部稀疏数据表示(双精度浮点数和非零组件的 int32 索引)。如果您想在不复制密集的 numpy C 连续双精度数组作为输入的情况下拟合大规模线性分类器,我们建议使用 :class:`SGDClassifier ` 类。目标函数可以配置为与 :class:`LinearSVC` 模型几乎相同。 * **核缓存大小**:对于 :class:`SVC` 、:class:`SVR` 、:class:`NuSVC` 和 :class:`NuSVR` ,核缓存的大小对较大问题的运行时间有强烈影响。如果您有足够的可用 RAM,建议设置较大的核缓存大小。 建议将 ``cache_size`` 设置为高于默认值 200(MB) 的值,例如 500(MB) 或 1000(MB)。 * **设置 C**: ``C`` 默认为 ``1`` ,这是一个合理的默认选择。如果你有很多噪声观测值,你应该减小它:减小 C 对应于更多的正则化。 :class:`LinearSVC` 和 :class:`LinearSVR` 在 ``C`` 变得很大时对 ``C`` 不太敏感,预测结果在某个阈值后停止改善。同时,较大的 ``C`` 值将花费更多时间进行训练,有时长达 10 倍,如 [#3]_ 所示。 * 支持向量机算法不是尺度不变的,因此**强烈建议对数据进行缩放**。例如,将输入向量 X 上的每个属性缩放到 [0,1] 或 [-1,+1],或标准化为均值 0 和方差 1。请注意,必须对测试向量应用*相同*的缩放以获得有意义的结果。这可以通过使用 :class:`~sklearn.pipeline.Pipeline` 轻松完成:: >>> from sklearn.pipeline import make_pipeline >>> from sklearn.preprocessing import StandardScaler >>> from sklearn.svm import SVC >>> clf = make_pipeline(StandardScaler(), SVC()) 有关缩放和标准化的更多详细信息,请参见 :ref:`preprocessing` 部分。 .. _shrinking_svm: * 关于 `shrinking` 参数,引用 [#4]_:*我们发现,如果迭代次数很大,那么收缩可以缩短训练时间。然而,如果我们宽松地解决优化问题(例如,通过使用较大的停止容差),不使用收缩的代码可能会快得多* * :class:`NuSVC` /:class:`OneClassSVM` /:class:`NuSVR` 中的参数 ``nu`` 近似于训练误差和支持向量的比例。 * 在 :class:`SVC` 中,如果数据不平衡(例如,很多正例和很少负例),设置 ``class_weight='balanced'`` 并/或尝试不同的惩罚参数 ``C`` 。 * **底层实现的随机性**: :class:`SVC` 和 :class:`NuSVC` 的底层实现使用随机数生成器仅在概率估计时对数据进行洗牌(当 ``probability`` 设置为 ``True`` 时)。这种随机性可以通过 ``random_state`` 参数进行控制。如果 ``probability`` 设置为 ``False`` ,这些估计器不是随机的, ``random_state`` 对结果没有影响。:class:`OneClassSVM` 的底层实现与 :class:`SVC` 和 :class:`NuSVC` 类似。由于 :class:`OneClassSVM` 不提供概率估计,因此它不是随机的。 :class:`LinearSVC` 的底层实现在使用对偶坐标下降法拟合模型时(即当 ``dual`` 设置为 ``True`` 时)使用随机数生成器选择特征。因此,对于相同输入数据得到稍微不同的结果并不罕见。如果发生这种情况,可以尝试使用较小的 `tol` 参数。这种随机性也可以通过 ``random_state`` 参数进行控制。当 ``dual`` 设置为 ``False`` 时,:class:`LinearSVC` 的底层实现不是随机的, ``random_state`` 对结果没有影响。 * 使用 ``LinearSVC(penalty='l1', dual=False)`` 提供的 L1 正则化会产生稀疏解,即只有一小部分特征权重不为零并贡献于决策函数。增加 ``C`` 会产生更复杂的模型(选择更多的特征)。产生“空”模型(所有权重等于零)的 ``C`` 值可以使用 :func:`l1_min_c` 计算。 .. _svm_kernels: 核函数 ====== *核函数* 可以是以下任意一种: * 线性::math:`\langle x, x'\rangle` 。 * 多项式::math:`(\gamma \langle x, x'\rangle + r)^d` ,其中 :math:`d` 由参数 ``degree`` 指定,:math:`r` 由 ``coef0`` 指定。 * rbf::math:`\exp(-\gamma \|x-x'\|^2)` ,其中 :math:`\gamma` 是 由参数 ``gamma`` 指定的值必须大于 0。 * sigmoid :math:`\tanh(\gamma \langle x,x'\rangle + r)` , 其中 :math:`r` 由 ``coef0`` 指定。 不同的核函数由 `kernel` 参数指定:: >>> linear_svc = svm.SVC(kernel='linear') >>> linear_svc.kernel 'linear' >>> rbf_svc = svm.SVC(kernel='rbf') >>> rbf_svc.kernel 'rbf' 另请参阅 :ref:`kernel_approximation` ,了解使用 RBF 核函数的更快且更具可扩展性的解决方案。 RBF 核函数的参数 ---------------- 在使用 *径向基函数* (RBF) 核训练 SVM 时,必须考虑两个参数: ``C`` 和 ``gamma`` 。参数 ``C`` 是所有 SVM 核共有的,它在训练样本的误分类与决策面的简单性之间进行权衡。较低的 ``C`` 使决策面平滑,而较高的 ``C`` 旨在正确分类所有训练样本。 ``gamma`` 定义了单个训练样本的影响力。 ``gamma`` 越大,其他样本必须越接近才能受到影响。 ``C`` 和 ``gamma`` 的适当选择对 SVM 的性能至关重要。建议使用 :class:`~sklearn.model_selection.GridSearchCV` ,并以指数间隔选择 ``C`` 和 ``gamma`` 的良好值。 .. rubric:: 示例 * :ref:`sphx_glr_auto_examples_svm_plot_rbf_parameters.py` * :ref:`sphx_glr_auto_examples_svm_plot_svm_scale_c.py` 自定义核函数 ------------ 你可以通过提供一个 Python 函数或预计算 Gram 矩阵来定义自己的核函数。 具有自定义核函数的分类器与其他分类器的行为相同,除了: * 字段 ``support_vectors_`` 现在是空的,仅在 ``support_`` 中存储支持向量的索引 * 在 ``fit()`` 方法中,第一个参数的引用(而不是副本)被存储以供将来参考。如果该数组在调用 ``fit()`` 方法之间发生变化,则会受到影响。 使用 ``fit()`` 和 ``predict()`` 方法可能会产生意外的结果。 .. dropdown:: 使用Python函数作为核函数 你可以通过将函数传递给 ``kernel`` 参数来使用自己定义的核函数。 你的核函数必须接受两个形状为 ``(n_samples_1, n_features)`` 和 ``(n_samples_2, n_features)`` 的矩阵作为参数,并返回一个形状为 ``(n_samples_1, n_samples_2)`` 的核矩阵。 以下代码定义了一个线性核函数,并创建了一个使用该核函数的分类器实例:: >>> import numpy as np >>> from sklearn import svm >>> def my_kernel(X, Y): ... return np.dot(X, Y.T) ... >>> clf = svm.SVC(kernel=my_kernel) .. dropdown:: 使用Gram矩阵 你可以通过使用 ``kernel='precomputed'`` 选项来传递预计算的核矩阵。然后,你应该将Gram矩阵而不是X传递给 `fit` 和 `predict` 方法。所有训练向量和测试向量之间的核值必须提供: >>> import numpy as np >>> from sklearn.datasets import make_classification >>> from sklearn.model_selection import train_test_split >>> from sklearn import svm >>> X, y = make_classification(n_samples=10, random_state=0) >>> X_train , X_test , y_train, y_test = train_test_split(X, y, random_state=0) >>> clf = svm.SVC(kernel='precomputed') >>> # 线性核计算 >>> gram_train = np.dot(X_train, X_train.T) >>> clf.fit(gram_train, y_train) SVC(kernel='precomputed') >>> # 对训练样本进行预测 >>> gram_test = np.dot(X_test, X_train.T) >>> clf.predict(gram_test) array([0, 1, 0]) .. rubric:: 示例 * :ref:`sphx_glr_auto_examples_svm_plot_custom_kernel.py` .. _svm_mathematical_formulation: 数学公式 ======== 支持向量机在高位或无限维空间中构建超平面或一组超平面,这些超平面可用于分类、回归或其他任务。 分类、回归或其他任务。直观上,一个好的分离是通过具有最大距离的超平面实现的,这个距离是指到任意类别的最近训练数据点的距离(所谓的功能边界),因为在一般情况下,边界越大,分类器的泛化误差越小。下图显示了一个线性可分问题的决策函数,边界上有三个样本,称为“支持向量”: .. figure:: ../auto_examples/svm/images/sphx_glr_plot_separating_hyperplane_001.png :align: center :scale: 75 一般来说,当问题不是线性可分时,支持向量是位于边界内的样本。 我们推荐 [#5]_ 和 [#6]_ 作为支持向量机的理论和实践的良好参考。 SVC --- 给定训练向量 :math:`x_i \in \mathbb{R}^p` ,i=1,..., n,分为两类,以及向量 :math:`y \in \{1, -1\}^n` ,我们的目标是找到 :math:`w \in \mathbb{R}^p` 和 :math:`b \in \mathbb{R}` ,使得由 :math:`\text{sign} (w^T\phi(x) + b)` 给出的预测对大多数样本是正确的。 SVC 解决了以下原始问题: .. math:: \min_ {w, b, \zeta} \frac{1}{2} w^T w + C \sum_{i=1}^{n} \zeta_i \textrm {subject to } & y_i (w^T \phi (x_i) + b) \geq 1 - \zeta_i,\\ & \zeta_i \geq 0, i=1, ..., n 直观上,我们试图最大化边界(通过最小化 :math:`||w||^2 = w^Tw` ),同时当样本被错误分类或在边界内时产生惩罚。理想情况下,所有样本的值 :math:`y_i (w^T \phi (x_i) + b)` 都应为 :math:`\geq 1` ,这表示完美预测。但问题通常不是总能用一个超平面完美分离,因此我们允许一些样本与其正确的边界边界距离为 :math:`\zeta_i` 。惩罚项 `C` 控制了这个惩罚的强度,因此作为正则化参数的倒数(见下文注释)。 原始问题的对偶问题是 .. math:: .. math:: \min_{\alpha} \frac{1}{2} \alpha^T Q \alpha - e^T \alpha \textrm {subject to } & y^T \alpha = 0\\ & 0 \leq \alpha_i \leq C, i=1, ..., n 其中 :math:`e` 是全一的向量, 而 :math:`Q` 是一个 :math:`n` 乘 :math:`n` 的半正定矩阵, :math:`Q_{ij} \equiv y_i y_j K(x_i, x_j)` ,其中 :math:`K(x_i, x_j) = \phi (x_i)^T \phi (x_j)` 是核函数。:math:`\alpha_i` 被称为对偶系数, 并且它们的上限为 :math:`C` 。 这个对偶表示突出了一个事实,即训练向量通过函数 :math:`\phi` 隐式地映射到一个更高(可能是无限) 维的空间:参见 `核技巧 `_ 。 一旦优化问题得到解决,给定样本 :math:`x` 的 :term:`decision_function` 输出变为: .. math:: \sum_{i\in SV} y_i \alpha_i K(x_i, x) + b, 预测的类别对应于其符号。我们只需要对支持向量(即位于边界内的样本)求和,因为其他样本的对偶系数 :math:`\alpha_i` 为零。 这些参数可以通过属性 ``dual_coef_`` 访问,该属性保存了 :math:`y_i \alpha_i` 的乘积, ``support_vectors_`` 保存了支持向量,以及 ``intercept_`` 保存了独立项 :math:`b` 。 .. note:: 虽然从 `libsvm`_ 和 `liblinear`_ 派生的 SVM 模型使用 ``C`` 作为正则化参数,但大多数其他估计器使用 ``alpha`` 。两个模型之间的正则化量的确切等价性取决于模型优化的确切目标函数。例如,当使用的估计器是 :class:`~sklearn.linear_model.Ridge` 回归时,它们之间的关系为 :math:`C = \frac{1}{alpha}` 。 .. dropdown:: LinearSVC 原始问题可以等价地表述为 .. math:: \min_ {w, b} \frac{1}{2} w^T w + C \sum_{i=1}^{n}\max(0, 1 - y_i (w^T \phi(x_i) + b)), 我们使用 `hinge loss `_ 。这是直接由 :class:`LinearSVC` 优化的形式,但与对偶形式不同,这种形式不涉及样本之间的内积,因此著名的核技巧无法应用。这就是为什么 :class:`LinearSVC` 仅支持线性核(:math:`\phi` 是恒等函数)。 .. _nu_svc: .. dropdown:: NuSVC :math:`\nu` -SVC 公式 [#7]_ 是 :math:`C` -SVC 的重新参数化,因此在数学上是等价的。 我们引入一个新参数 :math:`\nu` (而不是 :math:`C` ),它控制支持向量和*边界误差*的数量::math:`\nu \in (0, 1]` 是边界误差比例的上限,也是支持向量比例的下限。边界误差对应于位于其边界错误一侧的样本:它要么被错误分类,要么被正确分类但未超出边界。 SVR --- 给定训练向量 :math:`x_i \in \mathbb{R}^p` ,i=1,..., n,以及向量 :math:`y \in \mathbb{R}^n` ,:math:`\varepsilon` -SVR 解决以下原始问题: .. math:: \min_ {w, b, \zeta, \zeta^*} \frac{1}{2} w^T w + C \sum_{i=1}^{n} (\zeta_i + \zeta_i^*) \textrm {subject to } & y_i - w^T \phi (x_i) - b \leq \varepsilon + \zeta_i,\\ & w^T \phi (x_i) + b - y_i \leq \varepsilon + \zeta_i^*,\\ & \zeta_i, \zeta_i^* \geq 0, i=1, ..., n 在这里,我们惩罚预测值至少与真实目标相差 :math:`\varepsilon` 的样本。这些样本根据其预测值位于 :math:`\varepsilon` 管道的上方还是下方,分别通过 :math:`\zeta_i` 或 :math:`\zeta_i^*` 惩罚目标函数。 对偶问题是 .. math:: \min_{\alpha, \alpha^*} \frac{1}{2} (\alpha - \alpha^*)^T Q (\alpha - \alpha^*) + \varepsilon e^T (\alpha + \alpha^*) - y^T (\alpha - \alpha^*) \textrm {满足 } & e^T (\alpha - \alpha^*) = 0\\ & 0 \leq \alpha_i, \alpha_i^* \leq C, i=1, ..., n 其中 :math:`e` 是全一的向量, :math:`Q` 是一个 :math:`n` 乘以 :math:`n` 的半正定矩阵, :math:`Q_{ij} \equiv K(x_i, x_j) = \phi (x_i)^T \phi (x_j)` 是核函数。这里训练向量通过函数 :math:`\phi` 隐式映射到更高 (可能是无限)维的空间。 预测为: .. math:: \sum_{i \in SV}(\alpha_i - \alpha_i^*) K(x_i, x) + b 这些参数可以通过属性 ``dual_coef_`` 访问, 该属性保存了差值 :math:`\alpha_i - \alpha_i^*` , ``support_vectors_`` 保存了支持向量, 以及 ``intercept_`` 保存了独立项 :math:`b` .. dropdown:: LinearSVR 原始问题可以等价地表述为 .. math:: \min_ {w, b} \frac{1}{2} w^T w + C \sum_{i=1}^{n}\max(0, |y_i - (w^T \phi(x_i) + b)| - \varepsilon), 其中我们使用了 epsilon-insensitive 损失,即小于 :math:`\varepsilon` 的误差被忽略。这是 :class:`LinearSVR` 直接优化的形式。 .. _svm_implementation_details: 实现细节 ====================== 内部,我们使用 `libsvm`_ [#4]_ 和 `liblinear`_ [#3]_ 来处理所有 计算。这些库通过 C 和 Cython 进行封装。 有关实现的描述和所用算法的详细信息,请参阅它们各自的论文。 .. _ `libsvm` : https://www.csie.ntu.edu.tw/~cjlin/libsvm/ .. _ `liblinear` : https://www.csie.ntu.edu.tw/~cjlin/liblinear/ .. rubric:: 参考文献 .. [#1] Platt `"Probabilistic outputs for SVMs and comparisons to regularized likelihood methods" `_ . .. [#2] Wu, Lin and Weng, `"Probability estimates for multi-class classification by pairwise coupling" `_ , JMLR 5:975-1005, 2004. .. [#3] Fan, Rong-En, 等人, `"LIBLINEAR: 用于大规模线性分类的库." `_ , 机器学习研究杂志 9.Aug (2008): 1871-1874. .. [#4] Chang 和 Lin, `LIBSVM: 支持向量机库 `_ . .. [#5] Bishop, `模式识别与机器学习 `_ , 第7章 稀疏核机器 .. [#6] :doi:`"支持向量回归教程" <10.1023/B:STCO.0000035301.49549.88>` Alex J. Smola, Bernhard Schölkopf - 统计与计算档案 第14卷第3期, 2004年8月, p. 199-222. .. [#7] Schölkopf 等人 `新的支持向量算法 `_ .. [#8] Crammer 和 Singer `关于多类核基向量机的算法实现 `_ , JMLR 2001.