机器学习笔记2-0:分类模型

*注:本博客参考李宏毅老师2020年机器学习课程. 视频链接

目录


1 分类模型

回归模型和分类模型都是一种输入到输出之间的映射关系,不同的是,回归模型是值到值的映射,分类模型是值到类别的映射。

1.1 应用

分类模型应用广泛,比如可以解决如下几种问题:

  • 输入患者的年龄、身高、体重、血糖、血压等等一系列指标,输出该患者得了哪一种病;
  • 输入一张图片,判断该图片的内容是什么物体;

1.2 分类与回归的区别

如果使用回归的方法来解决分类问题,例如规定回归模型输出1则表示类别1,输出2则表示类别2,输出3则表示类别3,等等。这种方法看上去可行,然而实际上会出现以下问题:

  • 从输出的设定来看,越接近于某个值则表示属于该类的可能性越大,然而,如果输出值远大于设定的最后一个类别的值,尽管直观上来看它仍属于最后一个类别,但是在梯度下降时,为了减小损失,最后两个类别的分界线将会偏离“正确”的位置,而向这个较大的输出值偏移。
  • 由于相邻两个类别的输出值较接近,从逻辑上来说,它们应该具有较强的关联关系,而不相邻的类别之间具有较弱的关联。如果实际上这种关联不存在,将会导致模型精度变差。这使得训练数据的选取变难,能够解决的问题范围变小。

因此,不能简单地使用回归模型来处理分类问题。

1.3 分类模型

1.3.1 目标函数

在回归模型中,目标函数描述为 y = g ( x ) y=g\left(x\right) y=g(x),表示从输入值到输出值之间的映射。在分类模型中,目标函数可能会更复杂一些。例如,假设我们使用分类模型处理一个三分类的问题,则可能需要三个函数,分别对应于三个类别, c i = g i ( x ) c_i=g_i\left(x\right) ci​=gi​(x),若 c i > 0 c_i>0 ci​>0,则说明x属于类别i。最后比较大于0的 c i , i = 1 , 2 , 3 c_i,i=1,2,3 ci​,i=1,2,3的大小,最大的即为x的类别。因而目标函数可以表示为:
y = f ( x ) = m a x _ i n d e x ( g i ( x ) ) y=f\left(x\right)=max\_index(g_i\left(x\right)) y=f(x)=max_index(gi​(x))

1.3.2 损失函数

除此之外,在回归模型中,我们使用了均方差作为损失函数,在使用上述目标函数的情况下,由于相邻类别之间可能不存在关联关系,因此不能使用均方差。一种可能的替代方案是,使用分类错误的数量作为损失函数,例如:
L o s s ( f ) = ∑ f ( x ) ≠ y ^ Loss(f)=\sum{f\left(x\right)\neq\hat{y}} Loss(f)=∑f(x)​=y^​
上述方法最大的问题在于,损失函数无法求导。

1.4 朴素贝叶斯分类模型

让我们反过来思考,假设有两类数据A和B,他们具有相同的特征维度 X X X。


现在,有一个新的个体,其特征值为 X 0 X_0 X0​(假设 X 0 X_0 X0​中各分量相互独立),我们要根据 X 0 X_0 X0​去推断它属于哪一个类别。虽然A类和B类中都可能会出现特征值为 X 0 X_0 X0​的个体,但由于两个类别的差异性,产生这一特征值的个体的概率是不一样的。设A类产生 X 0 X_0 X0​特征值的概率为: P ( X 0 ∥ A ) P\left(X_0\|A\right) P(X0​∥A),B类产生该特征值的概率为 P ( X 0 ∥ B ) P\left(X_0\|B\right) P(X0​∥B)。设不考虑特征值的情况下,对任意的个体,其属于A类和B类的概率分别为: P ( A ) P\left(A\right) P(A)和 P ( B ) P\left(B\right) P(B),那么容易得到, X = X 0 X=X_0 X=X0​的个体属于A类的概率为:
P ( A ∥ X 0 ) = P ( X 0 ∥ A ) P ( A ) P ( X 0 ∥ A ) P ( A ) + P ( X 0 ∥ B ) P ( B ) (1) P\left(A\|X_0\right)=\frac{P\left(X_0\|A\right)P\left(A\right)}{P\left(X_0\|A\right)P\left(A\right)+P\left(X_0\|B\right)P\left(B\right)} \tag{1} P(A∥X0​)=P(X0​∥A)P(A)+P(X0​∥B)P(B)P(X0​∥A)P(A)​(1)
因此,只要分别计算出个体属于A类和B类的概率,就可以估计该个体的类别。在这个例子中,由于有且仅有两个类别,因此
P ( A ∥ X 0 ) + P ( B ∥ X 0 ) = 1 P\left(A\|X_0\right)+P\left(B\|X_0\right)=1 P(A∥X0​)+P(B∥X0​)=1
所以只要计算 P ( A ∥ X 0 ) P\left(A\|X_0\right) P(A∥X0​)即可。


在公式(1)中, P ( A ) P\left(A\right) P(A)和 P ( B ) P\left(B\right) P(B)的计算相对简单。设在已知的具有n条数据的数据集中,有a条数据为A类,则 P ( A ) = a n , P ( B ) = n − a n P\left(A\right)=\frac{a}{n},P\left(B\right)=\frac{n-a}{n} P(A)=na​,P(B)=nn−a​


而 P ( X 0 ∥ A ) P\left(X_0\|A\right) P(X0​∥A)也就是类别A中的个体所服从的概率分布在 X 0 X_0 X0​处的概率密度,一般假设服从正态分布。即:
P ( X 0 ∥ A ) = 1 2 π σ e − ( x − μ ) 2 2 σ 2 (2) P\left(X_0\|A\right)=\frac{1}{\sqrt{2\pi}\sigma}e^{-\frac{(x-\mu)^2}{2\sigma^2}} \tag{2} P(X0​∥A)=2π ​σ1​e−2σ2(x−μ)2​(2)
其中 μ \mu μ表示样本均值, σ \sigma σ表示样本标准差。
根据上述论断,如果一个模型能够将A类的个体划分为A类,即 P ( X 0 ∥ A ) P\left(X_0\|A\right) P(X0​∥A)越大,则其分类效果越好,因此可以将损失函数定义为:
L o s s ( f ) = ∑ ( y c ^ − P ( C ∥ X ) ) 2 Loss\left(f\right)=\sum(\hat{y_c}-P\left(C\|X\right))^2 Loss(f)=∑(yc​^​−P(C∥X))2
其中, y c ^ \hat{y_c} yc​^​表示个体属于类别C的概率,如果 y ^ = 1 \hat{y}=1 y^​=1,则该个体属于C类,如果 y ^ = 0 \hat{y}=0 y^​=0,则该个体不属于C类。

2 分类实例

一般来说,男性和女性在身高和体重上有着较明显的差异,我们获取了400个样本数据,用其中的100个作为训练集,300个作为测试集,来通过身高和体重对人的性别进行分类。


使用到的数据如下:

import numpy as np
import matplotlib.pyplot as plt
from datas.hws_data import get_data
train, test = get_data()
s = 20
plt.scatter(train[train[:, 2] == 1][:, 0], train[train[:, 2] == 1]
            [:, 1], c="green", label="males_train", s=s)
plt.scatter(train[train[:, 2] == 0][:, 0], train[train[:, 2] == 0]
            [:, 1], c="orange", label="females_train", s=s)
plt.legend()
plt.show()
plt.scatter(test[test[:, 2] == 1][:, 0], test[test[:, 2] == 1]
            [:, 1], c="green", label="males_test", s=s)
plt.scatter(test[test[:, 2] == 0][:, 0], test[test[:, 2] == 0]
            [:, 1], c="orange", label="females_test", s=s)
plt.legend()
plt.show()

机器学习笔记2-0:分类模型机器学习笔记2-0:分类模型

假设身高和体重分别服从正态分布,根据100个数据分别计算男性和女性的身高和体重的样本均值和方差,估计其分布。然后根据前述的贝叶斯公式计算个体属于男性的概率,如果大于0.5则认为是男性。


注意:该方法不需要梯度下降。

males = train[train[:, 2] == 1][:,:2]
females = train[train[:, 2] == 0][:,:2]
# 男性的概率
P_male = (males.shape[0])/(males.shape[0]+females.shape[0])
# 女性的概率
P_female = 1-P_male
# 计算均值
E_male, E_female = males.mean(axis=0), females.mean(axis=0)
# 计算方差,共享方差
F_male = F_female = ((males-E_male)**2).sum(axis=0) / \
    males.shape[0]


def denstiny(mean, f, x):
    # 正态分布概率密度
    return np.exp(-(x-mean)**2/(2*f**2))/(np.sqrt(np.pi*2*f))


def check_gendar(x):
    p_m = denstiny(E_male, F_male, x)*P_male
    p_f = denstiny(E_female, F_female, x)*P_female
    p_m /= p_m+p_f
    return p_m

在测试集上计算模型的准确性和损失,结果如下:

counter = 0
loss = 0
for m in test:
    p_m = check_gendar(m[:2]).mean()
    sex = 1 if p_m > 0.5 else 0
    if m[2] == sex:
        counter += 1
    loss += (m[2]-p_m)**2+(m[2]-1+p_m)**2
print("准确率:{:.2f}%,损失:{:.2f}".format(counter/test.shape[0]*100, loss))
准确率:93.00%,损失:150.58

3 朴素贝叶斯分类器进一步讨论

如果将公式1的分子和分母同时除以分子,那么将得到:
P ( A ∥ X 0 ) = 1 1 + P ( X 0 ∥ B ) P ( B ) P ( X 0 ∥ A ) P ( A ) (3) P\left(A\|X_0\right)=\frac{1}{1+\frac{P\left(X_0\|B\right)P\left(B\right)}{P\left(X_0\|A\right)P\left(A\right)}} \tag{3} P(A∥X0​)=1+P(X0​∥A)P(A)P(X0​∥B)P(B)​1​(3)
令 z = ln ⁡ P ( X 0 ∥ A ) P ( A ) P ( X 0 ∥ B ) P ( B ) = ln ⁡ P ( X 0 ∥ A ) P ( X 0 ∥ B ) + ln ⁡ P ( A ) P ( B ) z=\ln{\frac{P\left(X_0\|A\right)P\left(A\right)}{P\left(X_0\|B\right)P\left(B\right)}}=\ln{\frac{P\left(X_0\|A\right)}{P\left(X_0\|B\right)}}+\ln{\frac{P\left(A\right)}{P\left(B\right)}} z=lnP(X0​∥B)P(B)P(X0​∥A)P(A)​=lnP(X0​∥B)P(X0​∥A)​+lnP(B)P(A)​,则式3可以简化为:
P ( A ∥ X 0 ) = 1 1 + e − z (4) P\left(A\|X_0\right)=\frac{1}{1+e^{-z}} \tag{4} P(A∥X0​)=1+e−z1​(4)
即sigmoid函数,将式2带入z,得:
z = ln ⁡ P ( A ) P ( B ) + ln ⁡ σ B σ A + ( x − μ B ) 2 2 σ B 2 − ( x − μ A ) 2 2 σ A 2 = ln ⁡ P ( A ) P ( B ) + ln ⁡ σ B σ A + ( 1 2 σ B 2 − 1 2 σ A 2 ) x 2 + ( μ A σ A 2 − μ B σ B 2 ) x + ( μ B 2 2 σ B 2 − μ A 2 2 σ A 2 ) \begin{aligned} z&=\ln{\frac{P\left(A\right)}{P\left(B\right)}}+\ln{\frac{\sigma_B}{\sigma_A}}+\frac{(x-\mu_B)^2}{2\sigma_B^2}-\frac{(x-\mu_A)^2}{2\sigma_A^2}\\ &=\ln{\frac{P\left(A\right)}{P\left(B\right)}}+\ln{\frac{\sigma_B}{\sigma_A}}+(\frac{1}{2\sigma_B^2}-\frac{1}{2\sigma_A^2})x^2+(\frac{\mu_A}{\sigma_A^2}-\frac{\mu_B}{\sigma_B^2})x+(\frac{\mu_B^2}{2\sigma_B^2}-\frac{\mu_A^2}{2\sigma_A^2}) \end{aligned} z​=lnP(B)P(A)​+lnσA​σB​​+2σB2​(x−μB​)2​−2σA2​(x−μA​)2​=lnP(B)P(A)​+lnσA​σB​​+(2σB2​1​−2σA2​1​)x2+(σA2​μA​​−σB2​μB​​)x+(2σB2​μB2​​−2σA2​μA2​​)​
假设 σ A = σ B = σ \sigma_A=\sigma_B=\sigma σA​=σB​=σ,即假设两个特征值的变化幅度相同,则上式进一步简化为:
z = ln ⁡ P ( A ) P ( B ) + ( μ A − μ B σ 2 ) x + ( μ B 2 − μ A 2 2 σ 2 ) (5) z=\ln{\frac{P\left(A\right)}{P\left(B\right)}}+(\frac{\mu_A-\mu_B}{\sigma^2})x+(\frac{\mu_B^2-\mu_A^2}{2\sigma^2})\tag{5} z=lnP(B)P(A)​+(σ2μA​−μB​​)x+(2σ2μB2​−μA2​​)(5)
令 w = μ A − μ B σ 2 , b = ln ⁡ P ( A ) P ( B ) + ( μ B 2 − μ A 2 2 σ 2 ) w=\frac{\mu_A-\mu_B}{\sigma^2},b=\ln{\frac{P\left(A\right)}{P\left(B\right)}}+(\frac{\mu_B^2-\mu_A^2}{2\sigma^2}) w=σ2μA​−μB​​,b=lnP(B)P(A)​+(2σ2μB2​−μA2​​),则最终得到:
z = w x + b z=wx+b z=wx+b
即一个一次线性表达式。到这里我们发现,经过一系列复杂的计算之后,我们又回到了最初的起点——线性回归。


因此我们可以实际计算出上述实例的 w w w和 b b b的值:

w=(E_male-E_female)/(F_male**2)
b=np.log(P_male/P_female)+(E_female**2-E_male**2)/(2*F_male**2)
print("w:{},b:{}".format(w,b))
loss=0
counter=0
for m in test:
    z=(w*m[:2]+b).sum()
    p_m=1/(1+np.exp(-z))
    sex = 1 if p_m > 0.5 else 0
    if m[2] == sex:
        counter += 1
    loss += (m[2]-p_m)**2+(m[2]-1+p_m)**2
print("准确率:{:.2f}%,损失:{:.2f}".format(counter/test.shape[0]*100, loss))
w:[0.02572485 0.0035972 ],b:[-4.3315505  -0.21241086]
准确率:93.00%,损失:152.29

根据 w w w和 b b b的值,可以求出两个类的分界线,即图像中当输出为0.5时的若干点。计算方法如下:
1 1 + e − w x − b = 0.5 e − w x − b = 1 w 1 x 1 + b 1 + w 2 x 2 + b 2 = 0 x 2 = − b 1 − b 2 w 2 − w 1 w 2 x 1 \begin{aligned} \frac{1}{1+e^{-wx-b}}&=0.5\\ e^{-wx-b}&=1\\ w_1x_1+b_1+w_2x_2+b_2&=0\\ x_2&=\frac{-b_1-b_2}{w_2}-\frac{w_1}{w_2}x_1 \end{aligned} 1+e−wx−b1​e−wx−bw1​x1​+b1​+w2​x2​+b2​x2​​=0.5=1=0=w2​−b1​−b2​​−w2​w1​​x1​​
在训练集和测试集上分别作出两条分界线,这是一条直线。

B = -(b.sum()/w[1])
A = -w[0]/w[1]
xx = np.linspace(100, 200)
plt.ylim(train[:,1].min()-5,train[:,1].max()+5)
plt.xlim(train[:,0].min()-5,train[:,0].max()+5)
plt.plot(xx, A*xx+B)
plt.scatter(train[train[:, 2] == 1][:, 0], train[train[:, 2] == 1]
            [:, 1], c="green", label="males_train", s=s)
plt.scatter(train[train[:, 2] == 0][:, 0], train[train[:, 2] == 0]
            [:, 1], c="orange", label="females_train", s=s)
plt.legend()
plt.show()
plt.ylim(test[:,1].min()-5,test[:,1].max()+5)
plt.xlim(test[:,0].min()-5,test[:,0].max()+5)
plt.plot(xx, A*xx+B)
plt.scatter(test[test[:, 2] == 1][:, 0], test[test[:, 2] == 1]
            [:, 1], c="green", label="males_test", s=s)
plt.scatter(test[test[:, 2] == 0][:, 0], test[test[:, 2] == 0]
            [:, 1], c="orange", label="females_test", s=s)
plt.legend()
plt.show()
机器学习笔记2-0:分类模型机器学习笔记2-0:分类模型
上一篇:数学笔记9——牛顿迭代法


下一篇:数学笔记7——曲线构图