You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多分类SVM中某类近乎全为支持向量是否正常?附鸢尾花实验

问题描述

使用scikit-learn的SVC结合One-vs-Rest策略进行鸢尾花数据集的多分类任务时,发现versicolor类的35个训练样本几乎全部是支持向量,且各分类器的训练误差均为0。根据SVM的理论认知,这一情况超出预期,特此问询该现象是否正常,或是参数设置、代码实现存在问题。

实验代码

import pandas as pd
import numpy as np
from sklearn.svm import SVC
from sklearn.multiclass import OneVsRestClassifier

# 读取Excel文件
df = pd.read_excel("Classification iris.xlsx", index_col="instance_id")

# 划分训练集和测试集
train_data = pd.concat([
    df.loc[1:35],
    df.loc[51:85],
    df.loc[101:135]
])

test_data = pd.concat([
    df.loc[36:50],
    df.loc[86:100],
    df.loc[136:150]
])

# 分离特征和目标变量
train_features = train_data.drop(columns=['class'])
train_target = train_data['class']
test_features = test_data.drop(columns=['class'])
test_target = test_data['class']

# 构建One-vs-Rest策略的支持向量机
svm = OneVsRestClassifier(SVC(kernel='linear', C=1e5))
svm.fit(train_features, train_target)

# 生成预测结果
targets_train_pred = svm.predict(train_features)
targets_test_pred = svm.predict(test_features)

# 计算总误差
total_training_error =  sum(targets_train_pred != train_target) / len(train_data)
total_testing_error = sum(targets_test_pred != test_target) / len(test_data)

# 打印总训练和测试误差
print(f"Q2.2.2 使用标准SVM模型计算:
总训练误差: {total_training_error:.10f}, 总测试误差: {total_testing_error:.10f}")

# 初始化结果存储列表
classes = ['setosa', 'versicolor', 'virginica']
linear_separable = []

for i, class_name in enumerate(classes):
    # 获取当前类的二分类器
    classifier = svm.estimators_[i]
    
    # 计算每个类的误差
    train_class_error = sum((targets_train_pred == class_name) != (train_target == class_name)) / len(train_data)
    test_class_error = sum((targets_test_pred == class_name) != (test_target == class_name)) / len(test_data)
    
    # 获取权重向量w和偏置b
    w = classifier.coef_[0]
    b = classifier.intercept_[0]
    support_vector_indices = classifier.support_

    # 按格式打印每个类的结果
    print(f"
{class_name}类:")
    print(f"训练误差: {train_class_error:.10f}, 测试误差: {test_class_error:.10f}")
    print(f"w: [{', '.join([f'{x:.10f}' for x in w])}]")
    print(f"b: {b:.10f}")
    print(f"支持向量索引: {support_vector_indices.tolist()}")
    
    # 检查类是否线性可分
    if train_class_error == 0:
        linear_separable.append(class_name)

print(f"
线性可分类别: {', '.join(linear_separable)}")

实验输出

Q2.2.2 使用标准SVM模型计算:
总训练误差: 0.0571428571, 总测试误差: 0.0888888889

setosa类:
训练误差: 0.0000000000, 测试误差: 0.0000000000
w: [0.0097327108, 0.5377790363, -0.8273513712, -0.3820427629]
b: 0.7734548984
支持向量索引: [42, 23, 24]

versicolor类:
训练误差: 0.0000000000, 测试误差: 0.0000000000
w: [1.8485997715, -4.5023738999, -1.1043393026, 0.3212849949]
b: 5.6773042297
支持向量索引: [1, 2, 8, 9, 13, 25, 27, 34, 71, 72, 73, 77, 78, 80, 81, 86, 88, 89, 90, 91, 92, 93, 96, 99, 100, 102, 103, 104, 35, 36, 37, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 52, 55, 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69]

virginica类:
训练误差: 0.0000000000, 测试误差: 0.0000000000
w: [-3.6465034341, -5.1763639697, 7.4285254512, 11.0024158268]
b: -17.5703922240
支持向量索引: [55, 57, 62, 68, 96, 97, 99, 103]

线性可分类别: setosa, versicolor, virginica
问题解答

现象是否正常?

这种现象是正常的,并非代码实现错误,核心原因在于参数设置和数据集特性的共同作用。

关键原因分析

1. 正则化参数C设置过大

你使用的C=1e5属于极高的惩罚系数:

  • 在SVM中,C控制模型对训练误分类的容忍度。C越大,模型越追求完全拟合所有训练样本,甚至不惜让决策边界过度复杂,将大量样本纳入支持向量。
  • 当C趋近于无穷大时,线性SVM退化为硬间隔SVM,必须找到一个能完全分离两类的超平面(若数据线性可分),此时所有位于间隔边界或误分类区域的样本都会成为支持向量。

2. Versicolor与Virginica类的特征重叠

鸢尾花数据集中,versicolor和virginica的特征重叠程度很高,而setosa与另外两类完全线性可分。在One-vs-Rest策略下,针对versicolor的二分类器需要区分versicolor和“非versicolor”(setosa+virginica):

  • 由于两类重叠多,硬间隔SVM(大C值)需要将几乎所有versicolor样本作为支持向量,才能构建出恰好分离两类的超平面,确保训练集无任何误分类。

3. 训练误差为0的合理性

三个二分类器训练误差均为0,是大C值强制模型完全拟合训练数据的结果:

  • Setosa本身与其他两类线性可分,轻松实现0训练误差;
  • Versicolor和Virginica在硬间隔约束下,模型通过调整超平面刚好实现训练集全对,代价就是大量支持向量。

代码优化建议

你的代码实现逻辑正确,但有可优化之处:

  • 样本划分:手动按instance_id划分易引入分布偏差,推荐使用sklearn.model_selection.train_test_split进行随机划分;
  • 参数调整:过大的C易导致过拟合,尝试减小C(如C=1、C=10),可观察到支持向量数量减少,测试误差可能降低;
  • 误差计算:当前的train_class_error基于多分类结果,更准确的二分类器训练误差应直接用该分类器的预测结果(classifier.predict(train_features))与train_target == class_name对比计算,但不影响现有结论。

验证方案

  • 调整C为较小值(如C=1)重新训练,versicolor类的支持向量数量会大幅减少;
  • 使用sklearn.inspection.DecisionBoundaryDisplay绘制决策边界,直观观察不同C值下超平面的变化。

内容的提问来源于stack exchange,提问作者paul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 08:24:50