文章目录
前言
我在大三刚接触到机器学习课程的时候,回归问题很自然就能跨过这个坎。但在分类这个问题上,遇到的疑问一个接一个,本博客就是为了解答我本科学习期间的一个二分类器的疑问所作出的解答。
刚开始学习机器学习时,我们学习的最简单的例子就是二分类的案例。这也就导致了我们学习了很多的二分类器,例如逻辑回归二分类器、支持向量机二分类器等等。当时我就一个疑问,那不是二分类问题怎么办,那这些二分类器就显得很作用受限,后来随着知识量的增多。我了解到这个问题有两种解决方案:
(1)用softmax回归进行多分类(其实是逻辑回归的推广)
该方法本质上是将二分类器 ----> 推广为 多分类器
(2)一对多(One-vs-Rest, OvR)或一对全(One-vs-All, OvA)
这种本质上训练多个二分类器组合进行多分类的方法我一直不明白其中的具体原理是什么,下面本博客就主要是这种特殊的多分类技术的详细说明 ---- 顺便说一下,在我写这篇博客的时候,以前的疑问自然就已经解决了才会开始写;所以读者不必担心看不懂。其实我当成为了这个问题找了一些网上资料,但都不是很满意,都写的很模糊,今天在这里给这种技术做一个详细的说明。
【注】:本文会以鸢尾花的多分类数据集用SVM二分类器进行演示。
支持向量机(Support Vector Machine, SVM)本质上是一个二分类模型,但是在实际应用中,往往需要处理多分类问题。为了解决多分类问题,可以将多个二分类SVM组合在一起。常用的两种策略是一下两种:
一、一对多(One-vs-Rest, OvR)
1 理论
这种方法也称为“二分之一”法。基本思路是将一个多分类问题拆解成多个二分类问题。具体步骤如下:
- 假设有 K K K个类别。
- 对于每个类别 k k k,训练一个二分类SVM来区分类别 k k k 和其他 K − 1 K-1 K−1 个类别。即,每个SVM的目标是将该类别的数据点与所有其他类别的数据点分开。并规定 k k k类为正类,其他 K − 1 K-1 K−1 个类别为负类。
- 对于每个类别 k k k,标记为1,如果是该类别的数据点,否则标记为-1。
- 最终,训练 K K K个二分类SVM。
2 决策原则(这里给出的是SVM的,其他的二分类器也类似)
在预测时,将输入数据点输入到所有
K
K
K 个分类器中,选择得分最高的分类器对应的类别作为最终预测结果。
这句话怎么理解,这个得分究竟怎么计算的,我一直有一个疑惑,没关系,下面给出详细解释:
得分最高分类器的理解:
在“一对多”(One-vs-Rest, OvR)策略中,“得分最高的分类器”是指在预测过程中,将输入数据点送入每个分类器后,选择输出得分最高的那个分类器对应的类别作为最终的预测结果。为了更好地理解这一过程,我们可以深入探讨以下几个关键点:
(1) 一对多策略的分类器得分
在一对多策略中,对于一个
K
K
K类问题,我们会训练
K
K
K个二分类支持向量机(SVM)。每个SVM
k
k
k的任务是区分类别
k
k
k 和其他所有类别。训练过程中,类别
k
k
k的数据点被标记为正类(+1),而其他类别的数据点被标记为负类(-1)。
每个分类器在预测时会计算一个决策函数值或得分,表示该数据点属于正类的程度。这个得分可以理解为到分类平面的距离(考虑符号)。
(2) 决策函数值的含义
对于SVM,决策函数
f
(
x
)
f(x)
f(x) 的值可以表示输入数据点
x
x
x 到分类超平面的距离。通常,正的得分表示数据点更接近于正类,负的得分表示更接近于负类。决策函数的值越大,模型越自信该数据点属于正类。
例如,对于一个数据点
x
x
x,SVM的决策函数值
f
k
(
x
)
f_k(x)
fk(x)可以用来表示数据点
x
x
x属于类别
k
k
k 的程度。
【注】:sklearn里面的SVC中是有一个函数是计算这个决策函数值的,这个值为正的就说明分为正类,为负的就分为负类。
【注】:如果是逻辑回归二分类器那就更好办了,直接选择输出概率最大的那个作为得分。
(3)选择得分最高的分类器
在多分类预测中,我们将输入数据点
x
x
x输入到所有
K
K
K个二分类器中,每个分类器都会输出一个决策函数值
f
k
(
x
)
f_k(x)
fk(x)。
- 分类器1(类别1 vs 其他): f 1 ( x ) f_1(x) f1(x)
- 分类器2(类别2 vs 其他): f 2 ( x ) f_2(x) f2(x)
- …
- 分类器
K
K
K(类别
K
K
K vs 其他):
f
K
(
x
)
f_K(x)
fK(x)
我们选择得分最高的分类器 k k k,即决策函数值 f k ( x ) f_k(x) fk(x) 最大的那个分类器,作为最终的预测结果。选择得分最高的分类器意味着我们认为该数据点更接近这个分类器的正类(即该类别)。
(4)示例分析
假设我们有三个类别 A, B 和 C,以及一个输入数据点
x
x
x。在一对多策略下,我们有三个分类器:
- SVM1(A vs B and C):计算 f A ( x ) f_A(x) fA(x)
- SVM2(B vs A and C):计算 f B ( x ) f_B(x) fB(x)
- SVM3(C vs A and B):计算
f
C
(
x
)
f_C(x)
fC(x)
假设这些分类器的输出决策函数值分别为: - f A ( x ) = − 1.2 f_A(x) = -1.2 fA(x)=−1.2
- f B ( x ) = 2.3 f_B(x) = 2.3 fB(x)=2.3
- f C ( x ) = 0.7 f_C(x) = 0.7 fC(x)=0.7
根据决策函数值,我们可以看到:
- 分类器1的得分为 -1.2,表示输入数据点 ( x ) 不太可能属于类别A。
- 分类器2的得分为 2.3,表示输入数据点 ( x ) 很有可能属于类别B。
- 分类器3的得分为 0.7,表示输入数据点 ( x ) 可能属于类别C,但自信度不如类别B。
在这种情况下,我们选择得分最高的分类器,即分类器2(得分 2.3),对应的类别是B。因此,我们最终预测输入数据点 ( x ) 属于类别B。
优点:
- 实现简单。
- 适用于任意数量的类别。
缺点:
- 当类别数较多时,每个分类器的决策边界可能不准确,尤其是对于不平衡数据集。
- 可能需要较长的训练时间,因为要训练多个分类器。
2 简单代码演示
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
# 加载示例数据集
iris = datasets.load_iris()
X = iris.data
y = iris.target
print(X)
print(y) # 0, 1, 2 分别代表三种不同的鸢尾花,有3个类别,是多分类问题
输出:
# 数据集拆分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 使用一对多策略训练SVM
clf = SVC(decision_function_shape='ovr') # 'ovr' for One-vs-Rest 这个参数是svc中选择一对多还是一对一的策略;默认是ovr,其他二分类器也有类似参数可选
clf.fit(X_train, y_train)
# 预测
y_pred = clf.predict(X_test)
# 评估
print("Accuracy (OvR):", accuracy_score(y_test, y_pred))
输出:
二、 一对一(One-vs-One, OvO)
1 理论
这种方法也称为“二分二”法。基本思路是对每一对类别分别训练一个二分类SVM。具体步骤如下:
- 假设有 K K K个类别。
- 对于每一对类别 ( i , j ) (i, j) (i,j),训练一个二分类SVM来区分这两个类别。
- 每个SVM只使用类别 i i i 和类别 j j j 的数据。
- 最终,训练 K ( K − 1 ) 2 \frac{K(K-1)}{2} 2K(K−1) 个二分类SVM。
在预测时,将输入数据点输入到所有
K
(
K
−
1
)
2
\frac{K(K-1)}{2}
2K(K−1)个分类器中,采用投票机制来确定最终的类别,即选择得票最多的类别作为预测结果。
具体分为下面两个过程:
(1) 训练阶段:
- 对于一个 K K K类问题,训练 K ( K − 1 ) 2 \frac{K(K-1)}{2} 2K(K−1)个二分类器,每个分类器 ( i , j ) (i, j) (i,j)用来区分类别 i i i和类别 j j j。
- 每个分类器只使用类别 i i i和类别 j j j 的数据进行训练,忽略其他类别的数据。
(2) 预测阶段:
- 对于每一个输入数据点,将其输入到所有 K ( K − 1 ) 2 \frac{K(K-1)}{2} 2K(K−1)个分类器中。
- 每个分类器会预测输入数据点属于两个类别中的一个。
- 最后,使用投票机制来确定最终的类别,选票最多的类别即为最终的预测结果。
2 决策原则(投票)
在一对一策略中,投票机制的步骤如下:
(1)收集每个分类器的预测:
- 每个二分类器 ( i , j ) (i, j) (i,j) 都会对输入数据点进行预测,输出一个类别:要么是 i i i,要么是 j j j。
- 记录每个分类器的预测结果。
(2)统计每个类别的投票数:
- 初始化一个计数器(或数组)来记录每个类别得到的投票数。
- 对于每个分类器的预测结果,将票数增加到相应的类别上。例如,如果分类器 ( i , j ) (i, j) (i,j)预测输入数据点属于类别 i i i,那么类别 i i i 的投票数加1。
(3)确定最终的类别:
- 统计完所有的投票后,选择投票数最多的类别作为最终的预测结果。
- 如果出现平局(多个类别得到相同的最高票数),可以根据某些策略进行决策,例如选择其中一个类别(通常是先到的)或者基于决策函数的信心度来打破平局。
具体例子:
假设我们有一个三分类问题,类别为 A, B 和 C。我们会有三个二分类器:
- SVM1:区分类别 A 和类别 B。
- SVM2:区分类别 A 和类别 C。
- SVM3:区分类别 B 和类别 C。
假设对于一个输入数据点 x x x,这三个分类器的预测结果如下:
- SVM1 预测 x x x 属于类别 A。
- SVM2 预测 x x x属于类别 A。
- SVM3 预测 x x x 属于类别 C。
投票过程
(1)初始化投票计数:
- 创建一个字典或数组来记录投票数,例如
{A: 0, B: 0, C: 0}
。
(2)更新投票数:
- SVM1 预测 A: 更新投票数
{A: 1, B: 0, C: 0}
。 - SVM2 预测 A: 更新投票数
{A: 2, B: 0, C: 0}
。 - SVM3 预测 C: 更新投票数
{A: 2, B: 0, C: 1}
。
(3)确定最终的类别:
- 在投票数中,类别 A 得到的票数最多(2 票),因此最终的预测结果是类别 A。
优点:
- 相较于OvR,OvO在处理类别数较多时通常能产生更准确的决策边界。
- 每个分类器只处理两个类别,可能会更快。
缺点:
- 需要训练的分类器数量显著增加,尤其是类别较多时,这会增加计算复杂度。
- 最终的投票过程可能会受到少数分类器的极端决策的影响。
3 简单代码演示
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
# 加载示例数据集
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 数据集拆分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 使用一对一策略训练SVM
clf = SVC(decision_function_shape='ovo') # 'ovo' for One-vs-One 这里采用了一对一策略
clf.fit(X_train, y_train)
# 预测
y_pred = clf.predict(X_test)
# 评估
print("Accuracy (OvO):", accuracy_score(y_test, y_pred))
总结
如果你和我一样对这两种分类策略不是很了解的话,希望这篇文章能够帮助你!