机器学习和统计

集成学习(5) - 基本分类模型

2021-03-27  本文已影响0人  木头里有虫911

1. 分类模型的模型性能度量指标

这四个就是真假和阴阳的排列组合,有T的都表示True,可以理解成预测正确。比如TP就是真阳,也就是说检测是阳性,实际上也是阳性。同理,TN就是真阴,检测是阴性,实际上也是阴性。

有F则表示False, 即预测错误,FP是假阳,也就是检测是阳性,但是实际上是阴性,表示检测错了。同理,FN是假阴,检测是阴性,但是实际上是阳性。
我们用医院检测代入这几个值当中一下就理解了,TP和TN表示检测试剂给力,检测准确,检测是阴就是阴,是阳就是阳。而FP和FN说明检测试剂不行,检测错了,要么就把没病的检测出了有病,要么就是明明有病没检测出来。

显然在医疗检测的场景当中,假阳是可以接受的,假阴不行。因为假阳我们还可以再检测,来确定究竟是阴还是阳,如果假阴放过了病例会对病人产生不好的影响,所以一般来说医疗检测试剂都会比标准更加敏感,这样才能尽量不放过漏网之鱼。

召回率的英文是recall,那么什么叫召回呢?
我们假设一个场景,比如说甲是一个排长,手下有10个小兵,有一个任务需要甲召集所有成员去执行。甲一声令下,召来了8个。那么召回率就是80%。我们放入机器学习的场景当中去也是一样的,在二分类场景当中,一般情况下模型考虑的主要都是正例。可以理解成沙里淘金,负例就是沙,一般价值不大,而金子就是正例,就是我们需要的。所以召回率就是我们预测准确的正例占所有正例的比例
我们把上面的TP、TN、FP和FN代入计算,我们可以得到召回率REC的公式:
REC = \frac{TP}{TP+FN}

还是和之前我们从英文解释来弄懂这两个词。

在英文当中,精确率的英文是precision,词典当中的解释是:precision is defined as the proportion of the true positives against all the positive results (both true positives and false positives). 翻译过来是所有预测为正例的样本当中,正确的比例。所以精确率PRE的公式为:
PRE = \frac{TP}{TP+FP}
准确率英文是accuracy,英文解释是:accuracy is the proportion of true results (both true positives and true negatives) in the population. 翻译过来也就是预测结果准确的概率,既然是预测结果准确,那么显然既包含了正例也包含了负例。所以准确率ACC的公式为:
ACC = \frac{TP+TN}{FP+FN+TP+TN}

从英文的描述上我们可以明显地看出这两个概念的差异,两个都是预测正确的部分,但精确率只针对正例,而准确率针对的是所有样本,既包含正例也包含负例。我个人觉得这两者翻译成筛选正确率和判断正确率比较容易理解一些,如果只有精确率和准确率可能还好,再加上上面说的召回率,可能真的要晕菜的。

1.4 F1 score

F1 score反应了对模型召回率recall和精确率precision的取舍, 公式为:


image.png

在机器学习领域当中,recall和precision是不可调和的两个值,一个模型精确率高了,往往召回就低,如果熟悉数学的同学会发现f1-score本质上是recall和precision的调合平均数,我们可以用它来均衡recall和precision,方便我们做取舍。

2. 常用的基本分类模型

这里主要介绍3种分类模型: 逻辑回归LR, 决策树模型和SVM支持向量机模型

2.1 逻辑回归Logistic Regression:

逻辑回归虽然名叫回归,其实是一个用于分类的模型。逻辑回归在之前的线性回归模型中最后一步加入一个softmax函数,将线性回归的取值隐射到(0,1)区间,从而将结果当成一个概率用于分类。从这点上说LR模型可以被认为就是一个被Sigmoid函数(logistic方程)所归一化后的线性回归模型!函数形式为:
log_i(z) = \frac{1}{1+e^{-z}}
对应的函数图像如下:

image.png

逻辑回归模型可是说是机器学习中最简单的模型之一,但同时它具有极强的解释性,广泛的应用于各个领域,同时也可以作为很多分类算法的基础组件。例如使用GBDT + LR用于信用卡交易的反欺诈等。另外,在很多实际用用中,由于逻辑回归易于实现,可以作为很多问题baseline。

代码演示:使用鸢尾花数据集
step1: 导入数据集并查看:

from sklearn import datasets
iris = datasets.load_iris()
y = iris.target
iris_features = pd.DataFrame(data = iris.data, columns = iris.feature_names)
iris_features.head()
image.png

step2: 构建模型并训练预测:

from sklearn.model_selection import train_test_split

# 选择其中类别为0和1的样本(不包括2),先进行二分类
iris_part = iris_features.iloc[:100]
iris_part_target = iris.target[:100]

# 分割测试集(20%)和训练集(80%)
X_train, X_test, y_train,y_test = train_test_split(iris_part, iris_part_target, 
                                                   test_size = 0.2, random_state = 2020)
# 创建并训练模型
clf = LogisticRegression(random_state=0, solver='lbfgs')
clf.fit(X_train, y_train)

>>> LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
          intercept_scaling=1, max_iter=100, multi_class='warn',
          n_jobs=None, penalty='l2', random_state=0, solver='lbfgs',
          tol=0.0001, verbose=0, warm_start=False)

查看训练后的模型参数:

# 查看对应的w
print('The weight of Logistic_Regression: ', clf.coef_)
#查看对应的w0
print( 'The intercept(w0) of Logistic_Regression: ', clf.intercept_)
>>> The weight of Logistic_Regression:  [[ 0.45181973 -0.81743611  2.14470304  0.89838607]]
>>> The intercept(w0) of Logistic_Regression:  [-6.53367714]

在计算模型精度

from sklearn.metrics import accuracy_score, confusion_matrix
train_predict = clf.predict(X_train)
test_predict = clf.predict(X_test)

train_res = accuracy_score(y_train, train_predict)
test_res = accuracy_score(y_test, test_predict)

print('The accuracy of Logistic_Regression on train set is : ', train_res)
print('The accuracy of Logistic_Regression on test set is : ', test_res)
>>> The accuracy of Logistic_Regression on train set is :  1.0
>>> The accuracy of Logistic_Regression on test set is :  1.0

可以看到在训练集和测试集上模型都获得了100% 的正确度。这个从之前的数据可视化中也能看到一丝端倪,因为类别0和类别1很容易区分,即区分的边界比较明显。

下面查看混淆矩阵,并用热力图进行可视化

confusion_matrix_res = confusion_matrix(test_predict, y_test)
print('The confusion matrix result: \n', confusion_matrix_res)

#利用热力图进行可视化,
plt.figure(figsize=(8,6))
sns.heatmap(confusion_matrix_res, annot=True, cmap='Blues')
plt.xlabel('Predict lables')
plt.ylabel('True labels')

效果如下:


捕获.JPG

2.2 决策树

从前面的回归算法中,我们知道决策树分类算法的实现关键在于如何根据训练数据构建一颗决策树。而构建决策树的核心问题就在于如何选择一个合适的分裂属性进行一次分裂以及如何制定合适的分裂标准。在最初的决策树ID3算法中,采用信息熵(Information Entropy)来进行分裂。算法会根据所有样本 信息熵的变化(信息增益)来选择最佳分类。 因而信息熵就是决策树方法中分支产生的衡量标准之一。

信息熵来源热力学中的熵(Entropy)的概念。最早由德国物理学家克劳修斯提出,用来表述某个体系的混乱程度。在此基础上,美国的数学家,信息论的创始人香农提出了信息熵的概念。它代表了一个给定数据集中的不确定性或者随机性程度的度量。当一个数据集中的记录全部为同一类时,则没有不确定性,此时熵为0。因此我们也可以把熵看成是信息的数学期望。若要求出熵的大小,则先要计算信息:

设某个事物具有n种相互独立的可能结果,则信息的定义为:
l(x_i) = -log_2p(x_i)
为什么是以2为底的对数?这个可能和信息中的最小单位比特有关(一个比特只有0/1 2种状态其中),其中x_i表示第i个分类,p(x_i)表示第i个分类的概率函数,并且:\sum_{i=1}^np(x_i) = 1
由此,信息熵H(X)就可以表示为:
H(X) = - \sum_{i=1}^np(x_i) log_2p(x_i)
对于一个简单的二元分类,此时n=2,那么其熵为:
H(X) = - p(x_1) log_2p(x_1) - p(x_2) log_2p(x_2)

决策树分类算法的完整步骤:
a. 选择最优切分特征j以及该特征上的最优点s:
遍历特征j以及固定j后遍历切分点s,选择使得基尼系数或者交叉熵最小的(j,s)
b. 按照(j,s)分裂特征空间,每个区域内的类别为该区域内样本比例最多的类别。
c. 继续调用步骤1,2直到满足停止条件,就是每个区域的样本数小于等于5。
d. 将特征空间划分为J个不同的区域,生成分类树。

代码演示:
下面我们就用Python中内置的鸢尾花数据集来实现决策树算法。

1. 导入计算库和数据

注意决策树分类算法是放在sklearn.tree下面

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn import datasets
from sklearn import tree

再把鸢尾花的数据导进来

iris = datasets.load_iris()

X = iris['data']
y = iris['target']

iris_feature_names = iris.feature_names
iris_feature_names
print(iris_feature_names)
>>>['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

上面的代码中,我们鸢尾花数据集中的样本的4个维度的特征,单独拿出来用于后面的散点图矩阵分析和决策树分裂属性查看,直观一点。这4个维度分别是花萼长度/宽度,花瓣长度/宽度。

2. 数据初步分析与查看

在之前的文章中,我们已经使用过这个数据集了,知道了大体情况。这里就不再使用shape/size/等查看数据集了。我们直接把数据iris['data']和feature_names即4个维度的名称合并成一个DataFrame,在调用pandas的散点图矩阵观察一下数据集

df = pd.DataFrame(iris['data'], columns = iris_feature_names)
df.head()
image.png
pd.plotting.scatter_matrix(df, c =iris['target'], figsize=(20, 20), marker='o', 
                                       hist_kwds={"bins": 20}, s=40, alpha=.8)

画出4个维度的直方图以及两两之间的散点图,这样可以直观的看到数据分类情况,如下:

matrix.png

稍微观察一下我们就可以发现使用petal length区分度最好,从上面图中的第三行我们可以发现有一种花的petal length特别小,和其他两种有很大的距离。另外petal width也有类似的情况(这两个特征在直方图中中间有断开的地方,以这里作为标准可以很容易的裂分出一类)。下面我们就创建决策树算法,看看算法是不是也是这么“想”的。

3. 构建决策树算法模型并查看模型精度

X_train, X_test, y_train, y_test = train_test_split(X, y , test_size = 0.2, random_state = 1024)

clf = DecisionTreeClassifier(criterion= 'entropy') #以entropy熵作为分裂标准构建决策树
clf.fit(X_train, y_train) #训练
y_ = clf.predict(X_test) #预测
tree_score = accuracy_score(y_test, y_) #查看模型预测结果的精度
print('该决策树模型在测试集上的精度为: {:.2f}'.format(tree_score))
>>>该决策树模型在测试集上的精度为: 1.00

之前我们反复的提到过在sklearn中构建算法模型训练预测都是统一的格式,3-4行代码搞定。上面也是用3行代码完成了模型的创建/训练和预测,之后打印出来模型在测试集上精度。因为数据简单,我们获得了100%的精度,这个和之前的KNN差不多。
决策树算法的构建中同样有很多参数可以调,我们下次再细说。这里最后我们输出一下上面算法的裂分条件和标准,这个是决策树比较赞的地方。我们可以直观的看到算法是如何归纳训练数据集的数据特征并选择最佳分裂条件进行裂分,这个就是算法的学习过程。

plt.figure(figsize=(15,8))
_ = tree.plot_tree(clf, filled = True, feature_names=iris_feature_names,fontsize = 11)

结果如下图:


tree_new.png

可以看到和我们之前预想的一致,算法第一步是按照petal length来裂分,直接得到一个叶子。我们在来套用熵的公式手算验证一下图中第一步得到的信息熵 entroy 为 1.584:

p1 = 39/120
p2 = 42/120
p3 = 39/120
H = -(p1 * np.log2(p1) + p2 * np.log2(p2) + p3 * np.log2(p3))
print(H)
>>>1.5840680553754911

结果和算法一致。有了这个树,我们就可以清晰的知道算法是怎么分类的了。这个是决策树比较好的地方,可视化/可解释性强。有些算法我们不知道或者很难理解算法究竟做了什么来预测或者分类的,比如神经网络。

2.3 SVM支持向量机

支持向量机(Support Vector Machine,SVM)是一个非常强大的算法,具有非常完善的数学理论,常用于数据分类.从学术的角度来看,SVM是最接近深度学习的机器学习算法。线性SVM可以看成是神经网络的单个神经元(虽然损失函数与神经网络不同),非线性的SVM则与两层的神经网络相当,非线性的SVM中如果添加多个核函数,则可以模仿多层的神经网络。
当然了,没有算法是完美的,比SVM强大的算法在集成学习和深度学习中还有很多很多。但不可否认,在传统的机器学习领域,SVM是一个非常耀眼的存在。

支持向量机的基本原理非常简单,如图所示,红色和蓝色的点各为一类,我们的目标是找到一个分割平面将两个类别分开。

通常来说,如果数据本身是线性可分的,那么事实上存在无数个这样的超平面。这是因为给定一个分割平面稍微上移下移或旋转这个超平面,只要不接触这些观测点,仍然可以将数据分开。一个很自然的想法就是找到最大间隔超平面,即找到一个分割平面距离最近的观测点最远。下面我们来严格推导:
我们根据距离超平米那最近的点,只要同时缩放w和b可以得到:
w^Tx_1 + b = 1$与$w^Tx_2+b = -1
因此:
\begin{array}{l} w^{T} x_{1}+b=1 \\ w^{T} x_{2}+b=-1 \\ \left(w^{T} x_{1}+b\right)-\left(w^{T} x_{2}+b\right)=2 \\ w^{T}\left(x_{1}-x_{2}\right)=2 \\ \qquad \begin{array}{l} w^{T}\left(x_{1}-x_{2}\right)=\|w\|_{2}\left\|x_{1}-x_{2}\right\|_{2} \cos \theta=2 \\ \left\|x_{1}-x_{2}\right\|_{2} \cos \theta=\frac{2}{\|w\|_{2}} \end{array} \\ \qquad \begin{array}{l} d_{1}=d_{2}=\frac{\left\|x_{1}-x_{2}\right\|_{2} \cos \theta}{2}=\frac{\frac{2}{\|w\|_{2}}}{2}=\frac{1}{\|w\|_{2}} \\ d_{1}+d_{2}=\frac{2}{\|w\|_{2}} \end{array} \end{array}
由此可知道SVM模型的具体形式:
\begin{aligned} \min _{w, b} & \frac{1}{2}\|w\|^{2} \\ \text { s.t. } & y^{(i)}\left(w^{T} x^{(i)}+b\right) \geq 1, \quad i=1, \ldots, n \end{aligned}
可以将约束条件写为: g_{i}(w)=-y^{(i)}\left(w^{T} x^{(i)}+b\right)+1 \leq 0
可以将优化问题拉格朗日化
\mathcal{L}(w, b, \alpha)=\frac{1}{2}\|w\|^{2}-\sum_{i=1}^{n} \alpha_{i}\left[y^{(i)}\left(w^{T} x^{(i)}+b\right)-1\right]
因此:
\mathcal{L}(w, b, \alpha)=\frac{1}{2}\|w\|^{2}-\sum_{i=1}^{n} \alpha_{i}\left[y^{(i)}\left(w^{T} x^{(i)}+b\right)-1\right]
欲构造 dual 问题, 首先求拉格朗日化的问题中 \mathrm{w}\mathrm{b} 的值, 对 \mathrm{w} 求梯度, 令梯度为 0, 可求得 w:
对 b 求梯度, 令梯度为 0, 可得:
\frac{\partial}{\partial b} \mathcal{L}(w, b, \alpha)=\sum_{i=1}^{n} \alpha_{i} y^{(i)}=0

\mathrm{w} 带入拉格朗日化的原问题可得
\begin{array}{l} \mathcal{L}(w, b, \alpha)=\sum_{i=1}^{n} \alpha_{i}-\frac{1}{2} \sum_{i, j=1}^{n} y^{(i)} y^{(j)} \alpha_{i} \alpha_{j}\left(x^{(i)}\right)^{T} x^{(j)}-b \sum_{i=1}^{n} \alpha_{i} y^{(i)} \\ \mathcal{L}(w, b, \alpha)=\sum_{i=1}^{n} \alpha_{i}-\frac{1}{2} \sum_{i, j=1}^{n} y^{(i)} y^{(j)} \alpha_{i} \alpha_{j}\left(x^{(i)}\right)^{T} x^{(j)} \end{array}
因此:
\begin{aligned} &\text { 对拉格朗日化的原问题求最小值, 得到了 } \mathrm{w} \text { , 现在可以构造 dual 问題 }\\ &\begin{aligned} \max _{\alpha} & W(\alpha)=\sum_{i=1}^{n} \alpha_{i}-\frac{1}{2} \sum_{i, j=1}^{n} y^{(i)} y^{(j)} \alpha_{i} \alpha_{j}\left\langle x^{(i)}, x^{(j)}\right\rangle \\ \text { s.t. } & \alpha_{i} \geq 0, \quad i=1, \ldots, n \\ & \sum_{i=1}^{n} \alpha_{i} y^{(i)}=0 \end{aligned}\\ &\text { 可以推导出 b的值为: } b^{*}=-\frac{\max _{i: y^{(i)}=-1} w^{* T} x^{(i)}+\min _{i: y^{(i)}=1} w^{* T} x^{(i)}}{2}\\ &\begin{array}{r} \text { SVM的决策子如下,值的符号为类别. } \\ \qquad w^{T} x+b=\left(\sum_{i=1}^{n} \alpha_{i} y^{(i)} x^{(i)}\right)^{T} x+b=\sum_{i=1}^{n} \alpha_{i} y^{(i)}\left\langle x^{(i)}, x\right\rangle+b \end{array} \end{aligned}

参考:

  1. 召回、精确、准确,这些让人头大的概念一文全都讲清楚, 源于TechFlow ,作者梁唐
  2. Datawhale开源项目:机器学习集成学习与模型融合(基于python)
    作者: 李祖贤,陈琰钰,赵可,杨毅远,薛传雨
上一篇下一篇

猜你喜欢

热点阅读