# 多分类任务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的一个核心是生成假数据集;
当对红色做二分类时, 就要将其他两个变成同一类别:
- 将其表示为数学形式
$$ 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回归的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