数据分析笔记整理之分类问题(1)

620 阅读13分钟

数据分析笔记整理之分类问题(1)

1 分类问题与对应模型

1.1 分类问题的目的

  1. 分类分析之前,要先明确建模的目的是推断还是预测
  • 如果是以推断/分析为主,那么在建模时最好采用易于解释的白盒模型,探究各自变量对分类决策的影响。如一众线性模型(如:Logistic回归、Probit回归等)
  • 如果是以预测为主,则建模的依据主要是预测的精度,模型的可解释性与线性模型相比较差(如:支持向量机、随机森林、Xgboost等)

1.2 分类问题的类别

  1. 分类问题按照被分类对象的类别划分,总共可分为三类:二分类问题、无序多分类问题、有序多分类问题
  2. 二分类问题是最简单且最常见的分类问题
  • 模型选用
    • 二分类Logistic回归模型
    • Probit模型
  • 问题举例
    • 例如要研究客户流失跟哪些因素有关,从而对客户流失做出预警,此时因变量就是客户“是”与“否”会流失
    • 根据短信正文的内容判断邮件是垃圾邮件还是正常邮件
  1. 无序多分类问题是二分类问题的延伸
  • 模型选用
    • 多分类Logistic回归
  • 问题举例
    • 根据新闻内容对新闻主题进行分类,分类主题有体育、政治、娱乐、生活等。这种因变量类别多于两个,且类别间没有大小顺序的分类问题,被称为无序多分类问题
  1. 有序多分类问题也称为定序问题,在问卷调查中常出现
  • 模型选用
    • 有序Logistic回归
  • 问题举例
    • 例如要求消费者对产品进行满意度评价,评价结果包括不满意、一般、满意三个选项,可以将之赋值为1/2/3。这三个取值是存在先后大小之分的,这是与无序多分类问题最大的不同

2 二分类问题

2.1 线性回归模型如何处理分类问题

  1. 以具体的案例来说明(Example12

​ ST是我国股市特有的一项保护投资者利于的决策,当上市公司因财务状况不佳导致投资者难以预测其前景时,交易所会标记该公司股票为ST,并进行一系列限制措施。我们想研究被ST的公司其背后的因素,并尝试通过利用公司的财务指标提前预测某上市公司在未来是否会被ST,是一件很有意义的举措。而在这项任务中,因变量就是公司是否会被ST,数学表示为:y={1,ST0, Otherwise y= \begin{cases}1, & S T \\ 0, & \text { Otherwise }\end{cases}

​ 该例中自变量是一些财务指标,如ARA、ASSET等。

  1. 回归问题中,对于一个待预测样本 xx,模型输出值 y^\hat{y} 的性质就是因变量的性质
  • 例如:如果某个问题中因变量是价格,那么模型输出的值也应当是价格。但是分类问题不一样,以这个例子为例,模型是不可能直接回答我们结果是0还是1

  • 分类问题中模型一般输出——概率,准确来说是在给定 xx 下, y=1y=1 的概率

P(y=1x)P(y=1 \mid x)

2.2 概率的映射

  1. 与回归问题因变量天然确定的情况不一样,分类问题中概率的形式是需要我们人为确定的,即我们要确定如何将线性模型的直接输出值 yy 映射成概率值 P(y=1x)P(y=1∣x)
  2. 多元线性模型 y=β0+β1x1++βkxk+uy=\beta_{0}+\beta_{1} x_{1}+\cdots+\beta_{k} x_{k}+u
  • 其输出值 yy 是一个连续变量,而概率也是一个连续变量
  • 若让输出值 y=P(y=1x)=β0+β1x1++βkxk+uy=P(y=1 \mid x)=\beta_{0}+\beta_{1} x_{1}+\cdots+\beta_{k} x_{k}+u ,这样做有一个最大的缺点—— y^\hat{y} 可能不在区间 (0,1)(0,1) 内,而概率只能在 (0,1)(0,1) 区间内
  • 因此需要将 yy 放在一个映射函数中,将之映射为一个概率。而映射函数的不同决定了模型的形式、解释、训练方法的不同
  1. 若映射函数为 Logistic函数 G(y)=11+eyG(y)=\frac{1}{1+e^{-y}},则整个预测模型被称为Logistic线性回归模型
  2. 若映射函数为 Probit函数 Φ(y)=P(Yy)=y12πexp(12x2)dx\Phi(y)=P(Y \leq y)=\int_{-\infty}^{y} \frac{1}{\sqrt{2 \pi}} \exp \left(-\frac{1}{2} x^{2}\right) d x,则整个预测模型被称为Probit线性回归模型
  • Probit函数实际上就是标准正态分布的累积函数
  1. 图示 在这里插入图片描述
  • 这两个函数都具有单调递增性质的可逆函数,且值域位于(0,1)之间,是理想的概率映射函数

2.2 Logistic线性回归模型

  1. 模型形式

​ 记 y=xβ=β0+β1x1++βkxky=x^{\prime} \beta=\beta_{0}+\beta_{1} x_{1}+\cdots+\beta_{k} x_{k},则Logistic回归模型形式为

P(y=1x)=p(x)=11+ey=11+exβP(y=1 \mid x)=p(x)=\frac{1}{1+e^{-y}}=\frac{1}{1+e^{-x^{\prime} \beta}}

​ 以上形式还可以恒等变换为以下形式,便于我们对模型进行解释

log(p(x)1p(x))=β0+β1x1++βkxk\log \left(\frac{p(x)}{1-p(x)}\right)=\beta_{0}+\beta_{1} x_{1}+\cdots+\beta_{k} x_{k}
  • Logistic回归模型与一般多元回归模型的一大区别在于,前者的因变量是一个有关概率 p(y=1x)p(y=1 \mid x) 的函数,而后者的因变量是其本身
  1. 模型解释

​ 如果把 y=1y=1 看作“成功", y=0y=0 看作失败,则 p(x)/[1p(x)]p(x) /[1-p(x)] 就是成功与失败的概率比,被称为胜率(odd)。对于系数 βj\beta_{j} ,解释是: 当其他自变量不变时,变量 xix_{i} 提升一个单位,胜率odd会提升 βj%\beta_{j} \%

  1. 代码
# 加载基础包
import pandas as pd
import numpy as np
import statsmodels.api as sm
from scipy import stats
# 读取数据
ST=pd.read_csv('ST.csv')
ST.head()

在这里插入图片描述

st_logit=sm.formula.logit('ST~ARA+ASSET+ATO+ROA+GROWTH+LEV+SHARE',data=ST).fit()
print(st_logit.summary())

2.3 Probit线性回归模型

  1. 模型形式

​ Probit回归模型形式为

p(x)=Φ(xβ)p(x)=\Phi\left(x^{\prime} \beta\right)

​ 其中, Φ\Phi 就是标准正态分布的累积函数

  1. 模型解释

​ Probit模型的系数解释不直观,但可以确定的是,当 βj>0\beta_{j}>0 时, xjx_{j} 的增加会导致响应概率 p(x)p(x) 的增加

  1. 代码
st_probit=sm.formula.probit('ST~ARA+ASSET+ATO+ROA+GROWTH+LEV+SHARE',data=ST).fit()
print(st_probit.summary())

2.4 模型推断

​ Logistic回归与Probit回归在统计推断上是一致的

  • 与OLS估计的多元线性回归不同的是,这两种分类回归模型采用的是极大似然估计法对模型参数进行估计。在极大似然估计的一般理论下,我们可以证明模型估计系数 β^\hat{\beta}β\beta 的一 致估计
  • 基于极大似然估计的Logistic回归与Probit回归与基于OLS的多元线性回归在参数假设检验的思想上是相似的,只不过它们的检验统计量所服从的分布会有所不同

2.4.1 单参数显著性检验

  1. 假设设置如下:
H0:βj=βj0H1:βjβj0H_{0}: \beta_{j}=\beta_{j 0} \leftrightarrow H_{1}: \beta_{j} \neq \beta_{j 0}

​ 则单参数检验统计量为

β^jβjsd(β^j)N(0,1)\frac{\hat{\beta}_{j}-\beta_{j}}{s d\left(\hat{\beta}_{j}\right)} \Rightarrow N(0,1)

​ 该统计量渐进服从标准正态分布,可以看到,python中播报的也是z统计量的p值

  1. 代码
print('logistic回归报告')
print(st_logit.summary().tables[1])
print('--------------------------------------------------')
print('probit回归报告')
print(st_probit.summary().tables[1])

2.4.2 多参数联合显著性检验

  1. 在Logit模型与Probit模型中,我们同样可以检验部分因素的统计显著性,且检验的思想依旧是比较有约束模型与无约束模型的“差异度”。与多元线性回归模型不一样的是,分类模型没有残差平方和RSS的概念,那么联合检验的检验统计量自然也不是原来的F统计量了。但是,在似然理论下,存在一个比残差平方和更广泛的概念——离差(Deviance),定义为
 Deviance =2log( likelihood (model))\text { Deviance }=-2 \cdot \log (\text { likelihood }(\operatorname{model}))
  • 它是-2倍的模型对数似然比,而模型的对数似然比在summary播报中正是指标Log-Likelihood
  • 当两个模型的离差足够大时
DrDur>CD_{r}-D_{u r}>C

​ 我们便可以拒绝原假设,认为参数是联合显著的

  1. 与其他假设检验一样,我们需要知道该检验所采用的检验统计量及其服从的分布,计算p值后再判断是否拒绝原假设。在这个检验中,似然比检验统计量定义为
LR=2(lurlr)=DrDurH0χq2L R=2\left(l_{u r}-l_{r}\right)=D_{r}-D_{u r} \sim^{H_{0}} \chi_{q}^{2}
  • 它服从自由度为约束个数𝑞的卡方分布,因此我们需要用卡方分布累积分布函数
  1. 用python实现Logit模型多参数显著性检验,原假设为
H0:β1=β2==β7=0H_{0}: \beta_{1}=\beta_{2}=\cdots=\beta_{7}=0
  1. 代码实现
# 训练有约束模型
st_logit_r=sm.formula.logit('ST~1',data=ST).fit()

# 计算检验统计量
st_logit_ll=st_logit.llf
st_logit_r_ll=st_logit_r.llf
LR=2*(st_logit_ll-st_logit_r_ll)

# 计算p值
pvalue=stats.chi2.sf(LR,7)
print('联合检验的p值为:{}'.format(pvalue))

2.5 分类预测

2.5.1 模型预测的原理

  • 模型训练完成后,就可以针对给定的数据进行预测,以Logit模型为例,简述模型预测的原理
  1. 对于一组给定的解释变量取值 x0x_{0} ,我们将之代入模型中计算概率值 p(x)p(x)
p^(x0)=ex0β^1+ex0β^\hat{p}\left(x_{0}\right)=\frac{e^{x_{0}^{\prime} \hat{\beta}}}{1+e^{x_{0}^{\prime} \hat{\beta}}}

​ 这一概率是在样本自变量 x=x0x=x_{0} 下, y0=1y_{0}=1 的概率

  1. 代码实现
# 输出st_logit模型对ST数据集前五个样本的预测p(x)
logit_pred=st_logit.predict()
print(logit_pred[:5])
  1. 有计算出的概率后,接下来就要根据概率判断样本应当被划分为 1 类还是 0 类
  • 如何判断?可以规定一个阈值 α\alpha ,当概率 p(x)>αp(x)>\alpha 时,样本被划分为 1 类否则划分为 0 类,即
y^0={1,p^(x0)>α0, Otherwise \hat{y}_{0}=\left\{\begin{array}{lc} 1, & \hat{p}\left(x_{0}\right)>\alpha \\ 0, & \text { Otherwise } \end{array}\right.

​ 一般情况下,阈值 α\alpha 默认为 0.50.5

  1. 代码实现
# 我们构建一个判定函数,使其可以输出st_logit模型对ST数据集前五个样本在阈值为0.5时的预测判定
logit_res=list()
for i in np.arange(len(logit_pred)):
    if logit_pred[i]>0.5: #阈值
        logit_res.append(1)
    else:
        logit_res.append(0)

# 输出前五个样本的预测
print('前五个样本的预测结果:{}'.format(logit_res[:5]))

2.5.2 预测结果呈现

a)混淆矩阵

  1. 代码
import mglearn
mglearn.plots.plot_binary_confusion_matrix()
  1. 图示

在这里插入图片描述

  • 在分类问题中,negative通常指代“反类”,分类标签通常设置为0;positive通常指代“正类”,分类标签通常设置为1
  • 在二分类混淆矩阵中,横行表示样本实际的属性,纵列表示样本被模型预测的属性,如果两者不一致(FN/FP)就意味着预测错误,如果两者一致则意味着预测正确(TN/TP)
  • 简记为:横行为真实情况,纵列为预测情况
  1. 横行为真实情况,纵列为预测情况
from sklearn.metrics import confusion_matrix
confusion_matrix(ST.ST,logit_res) # 注意:第一个值输入的是真实的标签集,第二个值输入的是预测的标签集

b)多指标

  1. 先计算一下在阈值 α=0.5\alpha=0.5 下,logit模型的分类精度(也就是分类正确率),分类精度的公式为
Accuracy=TP+TNTP+TN+FP+FNAccuracy=\frac{T P+T N}{T P+T N+F P+F N}
  1. 代码
# 计算logits模型分类精度
logit_accuracy=(647+1)/(647+1+35+1)
print('分类精度为{}'.format(logit_accuracy))
  • 输出结果:分类精度为0.9473684210526315
  • 看上去分类精度接近95%,是一个非常不错的表现。但是我们稍加观察就会发现问题没有那么简单:在648个ST=0样本中,有647个样本被正确分类,只有1个样本被错误分类;但是在36个ST=1样本中,高达35个样本被错误分类,这说明logit模型在这个阈值下完全丧失了对1样本的预测能力。这是模型非常糟糕的表现,然而如果我们只关注到了约95%的高分类精度,我们会错误地认为模型表现得很好
  • 这种样本种类分布极其不均衡的现象被称为“样本不均衡”,对于这种样本的模型分类预测效果判断,仅靠分类精度是远远不够的,我们需要引入以下几个指标来解决这一问题——精确率、召回率、F分数
  1. 精确率(Precision) 衡量的是所有被预测为正类的样本中,预测正确的比例,公式为:
 Precision =TPTP+FP\text { Precision }=\frac{T P}{T P+F P}
  • 代码实现
# 以st=1为正类,计算logits模型精确率
logit_precision=(1)/(1+1)
print('精确率为{}'.format(logit_precision))
  • 输出:精确率为0.5
  1. 召回率(Recall) 衡量的是所有正类样本中,预测正确的比例,公式为:
 Recall =TPTP+FN\text { Recall }=\frac{T P}{T P+F N}
  • 代码实现
# 以st=1为正类,计算logits模型召回率
logit_recall=(1)/(1+35)
print('召回率为{}'.format(logit_recall))
  • 输出:召回率为0.027777777777777776
  1. F分数(F-score) 是精确率与召回率的调和平均,是两者的综合取舍,公式为:
F score =2 precision  recall  precision + recall F-\text { score }=2 \cdot \frac{\text { precision } \cdot \text { recall }}{\text { precision }+\text { recall }}
  • 代码实现
# 以st=1为正类,计算logits模型F分数
logit_f1=2*logit_recall*logit_precision/(logit_recall+logit_precision)
print('F分数为{}'.format(logit_f1))
  • 输出:F分数为0.05263157894736842
  1. 输出以0为正类、以1为正类的精确率、召回率、f分数(实际上这根据我们传入的标签集内的标签来定)
from sklearn.metrics import classification_report
print(classification_report(ST.ST,logit_res)) # 注意:第一个值输入的是真实的标签集,第二个值输入的是预测的标签集
  • 输出
 precision  recall  f1-score  support 00.951.000.9764810.500.030.0536 accuracy 0.95684 macro avg 0.720.510.51684 weighted avg 0.930.950.92684\begin{array}{rrrrr} & \text { precision } & \text { recall } & \text { f1-score } & \text { support } \\ 0 & 0.95 & 1.00 & 0.97 & 648 \\ 1 & 0.50 & 0.03 & 0.05 & 36 \\ \text { accuracy } & & & 0.95 & 684 \\ \text { macro avg } & 0.72 & 0.51 & 0.51 & 684 \\ \text { weighted avg } & 0.93 & 0.95 & 0.92 & 684 \end{array}
  • 第一行就是以ST=0为正类的三种指标,第二行就是以ST=1为正类的三种指标,这也正是我们前面手动计算的三个指标
  1. 精确率和召回率的对比
  • 如果分类目标是限制假正例(ST=0被预测为ST=1),那么精确率就可以很好的度量

  • 如果想限制假反例(ST=1被预测为ST=0),那么召回率就可以很好的度量

  • 举例

    • ex1. 垃圾短信为正类1,正常短信为反类0

      在进行垃圾短信分类时,将垃圾短信正确预测固然重要,但是我们更要防止将正常短信预测为垃圾短信(message=0被预测为message=1),因为遗漏正常短信的代价远远大于遗漏垃圾短信,此时,以垃圾短信为正类的精确率就是一个很好的度量指标

    • ex2. 有癌症为正类1,无癌症为反类0

      对病人进行癌症诊断时,一旦将实际上有癌症的病人预测为无癌症(cancer=1被预测为cancer=0),癌症病人将错失最佳治疗时机而产生危险,因此遗漏有癌症的代价远远大于遗漏无癌症,此时,以有癌症为正类的召回率就是一个很好的度量指标

2.5.3 对抗不平衡数据集

  1. 不平衡的数据集会导致模型的训练产生偏好性,由于ST=0的样本远远多于ST=1的样本,模型会更多地学习到ST=0的样本特征,而对ST=1的样本特征学习不足,于是对于一个未知样本,模型会更倾向于将它预测成大样本的类别
  2. 在数学层面上,由于我们的概率 pp 本质上是 P(y=1x)P(y=1 \mid x) ,但是 y=0y=0 样本却 占了大多数,于是各样本预测出来的概率 pp 将普遍偏小 (小于 0.50.5 ),我们可以观察一下
# 观察前50个样本的预测p
print(logit_pred[:50]>0.5)
  • 输出
[False False False False  True False False False False False  True False
 False False False False False False False False False False False False
 False False False False False False False False False False False False
 False False False False False False False False False False False False
 False False]
  1. 既然样本的预测p普遍偏小,可以降低“门槛” 𝛼 ,让其等于一个很小的数,这样可以有更多的样本被预测到ST=1的行列
logit_res=list()
for i in np.arange(len(logit_pred)):
    if logit_pred[i]>0.0526: #阈值
        logit_res.append(1)
    else:
        logit_res.append(0)

# 混淆矩阵
print(confusion_matrix(ST.ST,logit_res))

# 综合报告
print(classification_report(ST.ST,logit_res))
  • 输出
[[463 185]
 [ 11  25]]
              precision    recall  f1-score   support

           0       0.98      0.71      0.83       648
           1       0.12      0.69      0.20        36

    accuracy                           0.71       684
   macro avg       0.55      0.70      0.51       684
weighted avg       0.93      0.71      0.79       684
  1. 可以发现
  • 在调整了阈值后,以ST=1为正类的召回率显著提升,更多的正类样本被正确划分
  • 与此同时,以ST=1为正类的精确率却下降了很多,假反例大大增加,这就是调整阈值所付出的代价
  1. 事实上,调整阈值是一把“双刃剑”,对于一个既定的模型,改变阈值并不会改变模型的预测性能,它只能改变样本预测的分布,使分布更符合我们实际的需求。如果需要改进预测效果,要么换一种精度更高的模型,要么进行调参处理

注:本文整理内容来自datawhale社区和gitmodel联合的开源课程,感谢开源组织成员们的辛勤付出!