多分类任务OVO、OVR及softmax回归

作者: pdnbplus | 发布时间: 2024/06/25 | 阅读量: 294

# 多分类任务OVO、OVR及softmax回归 -- 潘登同学的Machine Learning笔记 @

简单回顾Logistic回归

  • 总目标:分类

    逻辑回归就是在多元线性回归基础上把结果缩放到 0 到 1 之间。 $h_{\theta}(x)$ 越接近1 越是正例, $h_{\theta}(x)$ 越接近 0 越是负例,根据中间 0.5 分为二类;

  • 模型: $$ \hat{y} = h_{\theta}(x)= g(\theta^Tx) = \frac{1}{1+e^{-\theta^Tx}} $$

    $\hat{y}$值: 概率含义($\hat{y}$越大说明分成正例的概率越大)

  • 优化目标:分类的越精确越好, 分对的越多越好

  • Loss函数:

    $$ L(\theta) = -\sum_{i=1}^{m}(y_{i}\log h_{\theta}(x_{i}) + (1-y_{i})\log (1-h_{\theta}(x_{i}))$$

Logistic回归实现多分类问题

  • Logistic回归就是二分类器, 那应该怎么做多分类呢?

我们想到$\hat{y}$的值不是有概率含义嘛, 把多分类任务转换成很多个二分类任务, 然后根据概率的大小分类;

考察如下分类任务:

多分类问题

One-vs-all(one-vs-rest)

OVR的思想就是用一个类别去与其他类别进行二分类, 然后进行多次这样的分类, 选择概率值最大的那个类别;

OVR的一个核心是生成假数据集;

当对红色做二分类时, 就要将其他两个变成同一类别:

ovr1

ovr2

ovr3

  • 将其表示为数学形式

$$ h_{\theta}^{(1)}(x) = P(y=1|x;\theta) \ h_{\theta}^{(2)}(x) = P(y=2|x;\theta) \ h_{\theta}^{(3)}(x) = P(y=3|x;\theta) \ $$

  • 总的来说 $$ h_{\theta}^{(i)}(x) = P(y=i|x;\theta) \ $$
  • 根据概率最大选择类别 $$ \max_i h_{\theta}^{(i)}(x) $$

实战OVR对上次的鸢尾花数据进行多分类

上次我们对鸢尾花数据分类只是分为属于setosa和不属于setosa;

其实这不就是OVR的一部分嘛, 我们这次把3个类别setosa,versicolor,virginica都实现分类;

话不多说, 上代码!!!

#%%多分类任务
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
import seaborn as sns
path = 'iris.csv'
data = pd.read_csv(path)

np.random.seed(2)
x = data.iloc[:,2:4]
y = data.iloc[:,4]
y.replace(['setosa','versicolor','virginica'],[0,1,2],inplace = True)#把品种转化为0 1 2

sns.set()
sns.scatterplot(data['petal_length'],data['petal_width'],hue = data['species'])
#划分训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.3)

log_reg = LogisticRegression(solver='sag',max_iter=100000,multi_class='ovr')  #ovr表示one-vs-rest 
#公式中默认自带penalty L2正则项   和  L2 前面的系数1/C  C 默认是1
log_reg.fit(x_train,y_train)
log_reg.coef_

y_hat = log_reg.predict_proba(x_test)
#这个第一列表示是零这一类的的概率
#将概率转化为预测结果
idx = np.argmax(y_hat, axis=1)

#比较预测结果与实际值
print(idx == y_test) 
#发现结果中有一个错误

OVO(One vs One)

另外一个做多分类的思想就是把所有类别的数据, 每个分类器只挑两个类别做二分类, 得出属于哪一类; 最后把所有分类器的结果放在一起, 选择最多的那个类别;

graph TD;
    多分类任务(以三分类为例)-->A与B进行二分类-->分为A类;
    多分类任务(以三分类为例)-->A与C进行二分类-->分为A类;
    多分类任务(以三分类为例)-->B与C进行二分类-->分为C类;
    分为A类-->投票选出A类;
    分为C类-->投票选出A类;

这也属于机器学习的经典范式, 就是自下而上的决策, 根据所有分类器对结果进行投票, 票数高者就是最终结果;

实战OVO对鸢尾花数据进行多分类

在sklearn中, OVO的参数是'multinomial',

话不多说, 上代码!!!

#%%多分类任务OVO
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
import seaborn as sns
path = 'iris.csv'
data = pd.read_csv(path)

np.random.seed(2)
x = data.iloc[:,2:4]
y = data.iloc[:,4]
y.replace(['setosa','versicolor','virginica'],[0,1,2],inplace = True)#把品种转化为0 1 2

sns.set()
sns.scatterplot(data['petal_length'],data['petal_width'],hue = data['species'])
#划分训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.3)

log_reg = LogisticRegression(solver='sag',max_iter=100000,multi_class='multinomial')  #multinomial表示OVO 
#公式中默认自带penalty L2正则项   和  L2 前面的系数1/C  C 默认是1
log_reg.fit(x_train,y_train)
log_reg.coef_

y_hat = log_reg.predict_proba(x_test)
#这个第一列表示是零这一类的的概率
#将概率转化为预测结果
idx = np.argmax(y_hat, axis=1)

#比较预测结果与实际值
print(idx == y_test) 
#发现结果中有一个错误
  • 而不论是OVO还是OVR, 本质上都是二分类, 那么有没有直接多分类的算法呢?

那就是Softmax!!!

Softmax回归

  • 总目标:多分类

    Softmax也是在多元线性回归基础上把结果缩放到 0 到 1 之间。 然后依据属于哪一类的概率最高, 选择该类;

  • 模型: $$ \hat{y^i} = h_{\theta}(x^i) = {\begin{bmatrix} P(y^i=1|x^i;\theta) \ P(y^i=2|x^i;\theta) \ \vdots \ P(y^i=k|x^i;\theta) \ \end{bmatrix}} = \frac{1}{\sum_{j=1}^{k}e^{-\theta_j^Tx^i}} {\begin{bmatrix} e^{-\theta_1^Tx^i} \ e^{-\theta_2^Tx^i} \ \vdots \ e^{-\theta_k^Tx^i} \ \end{bmatrix}} $$

$\hat{y}$值: 概率含义($\hat{y}$越大说明分成该例的概率越大)

上面的角标解释: 头上顶着i表示第i条样本, 下标是j表示第j组参数;

模型参数比较复杂, 不像之前的多元线性回归的参数基本上是一个行向量$[\theta_1, \theta_2, \cdots, \theta_n]$

而softmax模型的参数为$\theta_{k \times n}$, 将其按行分块: $$\begin{bmatrix} \theta_1 \ \theta_2 \ \vdots \ \theta_k \ \end{bmatrix}_{k \times n}$$ 举个栗子: $$ \theta_1 \times x_1$$ 这个结果进行非线性变换后就表示第一个样本属于第一类的概率;

所以结果矩阵 $X_{m \times n} \cdot \theta_{k \times n}^T$

  • 优化目标:分类的越精确越好, 分对的越多越好 > 根据Logistic回归的Loss函数也可以想到loss函数大概就是: 分对的概率取个负数(loss越小越好) > $$ L(\theta) = -\sum_{i=1}^{m}\sum_{j=1}^{k}y_{j}^{i} \log p_{j}^{i}$$ > > 其中$y_{j}^{i}$表示第i样本是否属于第j个类别(如果属于是则为1, 不是则为0);$p_{j}^{i}$为预测值(表示第i样本是否属于第j个类别的预测概率) > 后面还会详细讲loss函数, 先有初步感知即可;

从广义线性回归推导出 softmax

像Logistic回归假设服从二项分布; 像多元线性回归假设服从高斯分布;

softmax回归假设服从多项分布的, 可以理解为二项分布的推广, 也契合了做多分类的特点;

推导说明多项分布是指数族分布

  • 多项式分布的目标值 $y\in {1,2,3,\ldots,k}$;(其中是类别种数)其概率分布为: $$ I{y=i}=\varphi_i , 且\sum_{i=1}^{k}\varphi_i = 1\ $$

  • 其联合分布的概率密度函数为:

$$ \begin{aligned} P(y;\varphi) &= \varphi_1^{I{y=1}}\varphi_2^{I{y=2}}\ldots\varphi_{k-1}^{I{y=k-1}}\varphi_k^{I{y=k}} \ &= \varphi_1^{I{y=1}}\varphi_2^{I{y=2}}\ldots\varphi_{k-1}^{I{y=k-1}}\varphi_k^{1-\sum_{i=1}^{k-1}I{y=i}} \ &= e^{\log (\varphi_1^{I{y=1}}\varphi_2^{I{y=2}}\ldots\varphi_{k-1}^{I{y=k-1}}\varphi_k^{1-\sum_{i=1}^{k-1}I{y=i}})} \ &= e^{(\sum_{i=1}^{k-1}I{y=i}\log\varphi_i + (1-\sum_{i=1}^{k-1}I{y=i})\log\varphi_k)} \ &= e^{(\sum_{i=1}^{k-1}I{y=i}\log\frac{\varphi_i}{\varphi_k} + \log\varphi_k)} \ &= e^{(\sum_{i=1}^{k-1}\log\frac{\varphi_i}{\varphi_k}T(y)_i + \log\varphi_k)} \ &= e^{(\sum_{i=1}^{k}\log\frac{\varphi_i}{\varphi_k}T(y)_i + \log\varphi_k)} (因为\log\frac{\varphi_k}{\varphi_k}为0,所以加上之后不影响)\ &= e^{(\eta^TT(y)-a(\eta))}\ \end{aligned} $$ 注意:上面是把求和写成了内积形式, 什么是内积

这样我们就把多项式分布写成了指数族分布, 而有了指数族分布, 就能推导出softmax回归的公式;

由指数族分布推导softmax回归

  • 由上面的式子, 有:

$$\eta = {\begin{bmatrix} \log\frac{\varphi_1}{\varphi_k} \ \log\frac{\varphi_2}{\varphi_k} \ \vdots \ \log\frac{\varphi_{k-1}}{\varphi_k} \ \log\frac{\varphi_{k}}{\varphi_k} \ \end{bmatrix}} $$

  • 由单个$\eta_i$ 推导$\varphi_i$

$$ {\eta_i = \frac{\varphi_i}{\varphi_k}} \Rightarrow {\varphi_i = \varphi_k e^{\eta_i}} \ 又 \because \sum_{i=1}^{k}\varphi_i = \sum_{i=1}^{k}\varphi_k e^{\eta_i} = 1 \ \therefore \varphi_k = \frac{1}{\sum_{i=1}^{k}e^{\eta_i}}\ \therefore \varphi_i = \frac{e^{\eta_i}}{\sum_{i=1}^{k}e^{\eta_i}}\ $$

回想:$\varphi_i$的含义:就是y属于i类的概率;

  • 至此, 我们就得到了softmax回归的公式

    softmax回归公式

$$ \hat{y^i} = h_{\theta}(x^i) = {\begin{bmatrix} P(y^i=1|x^i;\theta) \ P(y^i=2|x^i;\theta) \ \vdots \ P(y^i=k|x^i;\theta) \ \end{bmatrix}} = \frac{1}{\sum_{j=1}^{k}e^{\theta_j^Tx^i}} {\begin{bmatrix} e^{\theta_1^Tx^i} \ e^{\theta_2^Tx^i} \ \vdots \ e^{\theta_k^Tx^i} \ \end{bmatrix}} $$

图示softmax回归模型

图示softmax回归模型

softmax回归的Loss函数

推导的流程基本上与Logistic回归的推导类似:

flowchart TD
    最大似然估计构造损失函数 --> 最大化正确分类的概率 -- 取对数 --> 将连乘变为连加 --取负号--> 将取最大变成Loss取最小
  • 最大似然估计构造损失函数 $$ \begin{aligned} {\Bbb{L}(\theta)} &= \prod_{i=1}^{m} P(y^i|x^i;\theta)\ &= \prod_{i=1}^{m}\prod_{j=1}^{k}\varphi_j^{I{y^i=j}}\ \end{aligned} $$ 注意:上面这个式子看上去会有点懵, 但是根据最大化分对的概率, 写成连乘就是这样;

    i还是表示第i个样本, j表示第j个类别, 如: $I{y^i=j}$则表示第i个样本属于j类的标签(属于为1, 不属于为0)

  • 取对数

$$ \begin{aligned} \log {\Bbb{L}(\theta)} &= \sum_{i=1}^{m}\log P(y^i|x^i;\theta) \ &= \sum_{i=1}^{m}\log \prod_{j=1}^{k} (\frac{\theta_j^Tx^i}{\sum_{l=1}^{k}\theta_l^Tx^i})^{I{y^i=j}} \ \end{aligned} $$

  • 稍微改写取负数 $$ \begin{aligned} Loss &= -\sum_{i=1}^{m}\sum_{j=1}^{k} {I{y^i=j}} \log (\frac{\theta_j^Tx^i}{\sum_{l=1}^{k}\theta_l^Tx^i}) \ \end{aligned} $$

注意: $\log后面就是预测值\hat{y}, \log前面就是实际值y$

逻辑回归和 Softmax 回归的关系

逻辑回归可以看成是 Softmax 回归的特例,就是 k=2 时候的 softmax 回归,因为当 我们把 softmax 回归公式 k=2 带入的话

$$ \begin{aligned} h_{\theta}(x) &= \frac{1}{e^{\theta_1^Tx + \theta_2^Tx}} {\begin{bmatrix} e^{\theta_1^Tx^i} \ e^{\theta_2^Tx^i} \ \end{bmatrix}} \ &= \frac{1}{e^{\vec{0}^Tx + (\theta_2-\theta_1)^Tx}} {\begin{bmatrix} e^{\vec{0}^Tx^i} \ e^{(\theta_2-\theta_1)^Tx^i} \ \end{bmatrix}} \ &= {\begin{bmatrix} \frac{1}{1 + e^{(\theta_2-\theta_1)^Tx^i}} \ 1-\frac{1}{1 + e^{(\theta_2-\theta_1)^Tx^i}} \ \end{bmatrix}} \ \end{aligned} $$

此时softmax回归就是参数为$(\theta_2-\theta_1)$的逻辑回归

实战softmax回归

因为sklearn没有封装专门的softmax回归, 而是把他放进了LogisticRegression里面, 还记得前面的OVR和OVO嘛? LogisticRegression的OVO就是softmax(网上说的), 但是根据前面的原理, 他俩显然不一样, 所以这里有待考证...

关键是知道直接多分类的算法就是softmax; 算法实现好处理

就把他当作softmax吧, 话不多说, 上代码!!!

#%%softmax回归实现多分类
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
import seaborn as sns
path = 'iris.csv'
data = pd.read_csv(path)

np.random.seed(2)
x = data.iloc[:,2:4]
y = data.iloc[:,4]
y.replace(['setosa','versicolor','virginica'],[0,1,2],inplace = True)#把品种转化为0 1 2

sns.set()
sns.scatterplot(data['petal_length'],data['petal_width'],hue = data['species'])
#划分训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.3)

log_reg = LogisticRegression(solver='sag',max_iter=100000,multi_class='multinomial')  #multinomial表示softmax 回归
#公式中默认自带penalty L2正则项   和  L2 前面的系数1/C  C 默认是1
log_reg.fit(x_train,y_train)
log_reg.coef_

y_hat = log_reg.predict_proba(x_test)
#这个第一列表示是零这一类的的概率
#将概率转化为预测结果
idx = np.argmax(y_hat, axis=1)

#比较预测结果与实际值
print(idx == y_test) 
#发现结果中有一个错误

softmax回归就是这样了, 继续下一章吧!pd的Machine Learning