机器学习笔记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(X0A),B类产生该特征值的概率为 P ( X 0 ∥ B ) P\left(X_0\|B\right) P(X0B)。设不考虑特征值的情况下,对任意的个体,其属于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(AX0)=P(X0A)P(A)+P(X0B)P(B)P(X0A)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(AX0)+P(BX0)=1
所以只要计算 P ( A ∥ X 0 ) P\left(A\|X_0\right) P(AX0)即可。


在公式(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)=nna


P ( X 0 ∥ A ) P\left(X_0\|A\right) P(X0A)也就是类别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(X0A)=2π σ1e2σ2(xμ)2(2)
其中 μ \mu μ表示样本均值, σ \sigma σ表示样本标准差。
根据上述论断,如果一个模型能够将A类的个体划分为A类,即 P ( X 0 ∥ A ) P\left(X_0\|A\right) P(X0A)越大,则其分类效果越好,因此可以将损失函数定义为:
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(CX))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()

假设身高和体重分别服从正态分布,根据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(AX0)=1+P(X0A)P(A)P(X0B)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(X0B)P(B)P(X0A)P(A)=lnP(X0B)P(X0A)+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(AX0)=1+ez1(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)22σA2(xμA)2=lnP(B)P(A)+lnσAσB+(2σB212σA21)x2+(σA2μAσB2μB)x+(2σB2μB22σ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+ewxb1ewxbw1x1+b1+w2x2+b2x2=0.5=1=0=w2b1b2w2w1x1
在训练集和测试集上分别作出两条分界线,这是一条直线。

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()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值