导语:
本次内容主要是利用sklearn处理分类任务:介绍分类模型的评价指标、基础的分类模型,最后结合数据集进行实现。本次的基础模型介绍非常详细,也有很多推导过程,由于时间关系,这里不再赘述。想要详细学习可直接查看开源项目,学习链接:
集成学习: EnsembleLearning项目-github.
1.分类任务
1.1 分类模型的度量指标
度量分类模型的指标和回归的指标有很大的差异,首先是因为分类问题本身的因变量是离散变量,因此像定义回归的指标那样,单单衡量预测值和因变量的相似度可能行不通。其次,在分类任务中,我们对于每个类别犯错的代价不尽相同。
分类模型的指标:
- 准确率:分类正确的样本数占总样本的比例,即: A C C = T P + T N F P + F N + T P + T N ACC = \frac{TP+TN}{FP+FN+TP+TN} ACC=FP+FN+TP+TNTP+TN.
- 精度:预测为正且分类正确的样本占预测值为正的比例,即: P R E = T P T P + F P PRE = \frac{TP}{TP+FP} PRE=TP+FPTP.
- 召回率:预测为正且分类正确的样本占类别为正的比例,即: R E C = T P T P + F N REC = \frac{TP}{TP+FN} REC=TP+FNTP.
- F1值:综合衡量精度和召回率,即: F 1 = 2 P R E × R E C P R E + R E C F1 = 2\frac{PRE\times REC}{PRE + REC} F1=2PRE+RECPRE×REC.
- ROC曲线:以假阳率为横轴,真阳率为纵轴画出来的曲线,曲线下方面积(AUC)越大越好。
图源:西瓜书
更多分类问题的评价指标请参考:
https://scikit-learn.org/stable/modules/model_evaluation.html#classification-metrics
1.2 分类模型的选择
(1)逻辑回归logistic regression
逻辑回归的基本思想是将线性回归的结果通过某一函数映射至区间[0:1]上,让连续的y标签转变成一个分类的概率,通过设定阈值,就可完成分类。这里的映射函数选择对数几率函数:
p
(
X
)
=
e
β
0
+
β
1
X
1
+
e
β
0
+
β
1
X
{p(X) = \dfrac{e^{\beta_0 + \beta_1X}}{1+e^{\beta_0 + \beta_1X}}}
p(X)=1+eβ0+β1Xeβ0+β1X
图源:西瓜书
注意:逻辑回归在实际中不太用于多分类问题,因为实际效果不是很好。
(2)基于概率的分类模型
A.线性判别分析
线性判别分析是一个比较久远的算法,可以从两个方向去描述这个算法,分别是基于贝叶斯公式和降维分类的思想。
基于贝叶斯公式对线性判别分析的理解如下图,虚线是线性判别分析的决策边界,正态曲线哪边高样本就是哪一类。
基于降维分类的思想理解线性判别分析如下图,“类内方差小,类间方差大”。
B.朴素贝叶斯
在线性判别分析中,我们假设每种分类类别下的特征遵循同一个协方差矩阵,每两个特征之间是存在协方差的,因此在线性判别分析中各种特征是不独立的。但是,朴素贝叶斯算法对线性判别分析作进一步的模型简化,它将线性判别分析中的协方差矩阵中的协方差全部变成0,只保留各自特征的方差,也就是朴素贝叶斯假设各个特征之间是不相关的。在之前的偏差-方差理论中,我们知道模型的简化可以带来方差的减少但是增加偏差,因此朴素贝叶斯也不例外,它比线性判别分析模型的方差小,偏差大。虽然简化了模型,实际中使用朴素贝叶斯的案例非常多,甚至多于线性判别分析,例如鼎鼎大名的新闻分类,垃圾邮件分类等。
(3)决策树
在之前的回归问题中,我们使用决策树进行了回归分析,然而,决策树也可以用来处理分类问题。分类树的构造过程与回归树也很类似,与回归树一样,分类树也是采用递归二叉分裂。但是在分类树中,均方误差无法作为确定分裂节点的准则,只需要选择:
(1) 基尼系数:
G
=
∑
k
=
1
K
p
^
m
k
(
1
−
p
^
m
k
)
G = \sum\limits_{k=1}^{K} \hat{p}_{mk}(1-\hat{p}_{mk})
G=k=1∑Kp^mk(1−p^mk)
在基尼系数的定义中,我们发现这个指标衡量的是K个类别的总方差。不难发现,如果所有的
p
^
m
k
\hat{p}_{mk}
p^mk的取值都接近0或者1,基尼系数会很小。因此基尼系数被视为衡量结点纯度的指标----如果他的取值小,那就意味着某个节点包含的观测值几乎来自同一个类别。
由基尼系数作为指标得到的分类树叫做:CART。
(2) 交叉熵:
可以替代基尼系数的指标是交叉熵,定义如下:
D
=
−
∑
k
=
1
K
p
^
m
k
l
o
g
p
^
m
k
D = -\sum\limits_{k=1}^{K} \hat{p}_{mk}log\;\hat{p}_{mk}
D=−k=1∑Kp^mklogp^mk
显然,如果所有的
p
^
m
k
\hat{p}_{mk}
p^mk都接近于0或者1,那么交叉熵就会接近0。因此,和基尼系数一样,如果第m个结点的纯度越高,则交叉熵越小。事实证明,基尼系数和交叉熵在数值上很接近。
(4)支持向量机SVM
支持向量机SVM是20世纪90年代在计算机界发展起来的一种分类算法,在许多问题中都被证明有较好的效果,被认为是适应性最广的算法之一。
支持向量机的基本原理非常简单,如图所视,白色和蓝色的点各为一类,我们的目标是找到一个分割平面将两个类别分开。通常来说,如果数据本身是线性可分的,那么事实上存在无数个这样的超平面。这是因为给定一个分割平面稍微上移下移或旋转这个超平面,只要不接触这些观测点,仍然可以将数据分开。一个很自然的想法就是找到最大间隔超平面,即找到一个分割平面距离最近的观测点最远。
非线性支持向量机
实际中的例子遇到的更多的是非线性可分的情况,这时候可以通过核技巧,在避开高维数据复杂运算量的同时对数据进行升维,升维后的数据就会变得线性可分,简单示意图如下:
几种常用的核函数:
1)多项式核函数:
多项式核函数(Polynomial Kernel)是线性不可分SVM常用的核函数之一,表达式为:
K
(
x
i
,
x
j
)
=
(
⟨
x
i
,
x
j
⟩
+
c
)
d
K\left(\mathbf{x}_{i}, \mathbf{x}_{j}\right)=\left(\left\langle\mathbf{x}_{i}, \mathbf{x}_{j}\right\rangle+c\right)^{d}
K(xi,xj)=(⟨xi,xj⟩+c)d
C用来控制低阶项的强度,C=0,d=1代表无核函数。
2) 高斯核函数:
高斯核函数(Gaussian Kernel),在SVM中也称为径向基核函数(Radial Basis Function,RBF),它是非线性分类SVM最主流的核函数。libsvm默认的核函数就是它。表达式为:
K
(
x
i
,
x
j
)
=
exp
(
−
∥
x
i
−
x
j
∥
2
2
2
σ
2
)
K\left(\mathbf{x}_{i}, \mathbf{x}_{j}\right)=\exp \left(-\frac{\left\|\mathbf{x}_{i}-\mathbf{x}_{j}\right\|_{2}^{2}}{2 \sigma^{2}}\right)
K(xi,xj)=exp(−2σ2∥xi−xj∥22)
使用高斯核函数之前需要将特征标准化,因此这里衡量的是样本之间的相似度。
3) Sigmoid核函数:
Sigmoid核函数(Sigmoid Kernel)也是线性不可分SVM常用的核函数之一,表达式为:
K
(
x
i
,
x
j
)
=
tanh
(
α
x
i
⊤
x
j
+
c
)
K\left(\mathbf{x}_{i}, \mathbf{x}_{j}\right)=\tanh \left(\alpha \mathbf{x}_{i}^{\top} \mathbf{x}_{j}+c\right)
K(xi,xj)=tanh(αxi⊤xj+c)
此时的SVM相当于没有隐藏层的简单神经网络。
4) 余弦相似度核:
常用于衡量两段文字的余弦相似度,表达式为:
K
(
x
i
,
x
j
)
=
x
i
⊤
x
j
∥
x
i
∥
∥
x
j
∥
K\left(\mathbf{x}_{i}, \mathbf{x}_{j}\right)=\frac{\mathbf{x}_{i}^{\top} \mathbf{x}_{j}}{\left\|\mathbf{x}_{i}\right\|\left\|\mathbf{x}_{j}\right\|}
K(xi,xj)=∥xi∥∥xj∥xi⊤xj
2. 模型实例对比
2.1 导入数据集
处理分类问题,收集数据集并选择合适的特征,在数据集上我们使用我们比较熟悉的IRIS鸢尾花数据集。导入IRIS数据集,并查看每个特征的含义,为方便后续模型的对比,这里先统一将数据集进行划分,75%的数据用于训练,25%的数据用于测试。
import pandas as pd
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
X = iris.data
y = iris.target
feature = iris.feature_names
data = pd.DataFrame(X,columns=feature)
data['target'] = y
#数据划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)
data.head()
数据集前几行:
各个特征的相关解释:
sepal length (cm):花萼长度(厘米)
sepal width (cm):花萼宽度(厘米)
petal length (cm):花瓣长度(厘米)
petal width (cm):花瓣宽度(厘米)
2.2 模型训练,结果对比
这里针对同样的训练集和测试集,依次使用上面五种算法进行训练:
#使用各类分类模型进行建模预测
test_score = [] #存放各模型测试集得分
#1.逻辑回归
'''
penalty {‘l1’, ‘l2’, ‘elasticnet’, ‘none’}, default=’l2’正则化方式
dual bool, default=False 是否使用对偶形式,当n_samples> n_features时,默认dual = False。
C float, default=1.0
solver {‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’, ‘saga’}, default=’lbfgs’
l1_ratio float, default=None
'''
from sklearn.linear_model import LogisticRegression
log_iris = LogisticRegression()
log_iris.fit(X_train,y_train)
log_pred_test = log_iris.predict(X_test)
print("1.逻辑回归测试集得分:",log_iris.score(X_test,y_test))
test_score.append(log_iris.score(X_test,y_test))
#2.线性判别分析
'''
参数:
solver:{'svd','lsqr','eigen'},默认='svd'
solver的使用,可能的值:
'svd':奇异值分解(默认)。不计算协方差矩阵,因此建议将此求解器用于具有大量特征的数据。
'lsqr':最小二乘解,可以与收缩结合使用。
'eigen':特征值分解,可以与收缩结合使用。
'''
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda_iris = LinearDiscriminantAnalysis()
lda_iris.fit(X_train,y_train)
lda_iris_test = lda_iris.predict(X_test)
print("2.线性判别测试集得分:",lda_iris.score(X_test,y_test))
test_score.append(lda_iris.score(X_test,y_test))
#3.朴素贝叶斯
from sklearn.naive_bayes import GaussianNB
NB_iris = GaussianNB()
NB_iris.fit(X_train,y_train)
NB_iris_test = NB_iris.predict(X_test)
print("3.朴素贝叶斯测试集得分:",NB_iris.score(X_test,y_test))
test_score.append(NB_iris.score(X_test,y_test))
#4.决策树
'''
criterion:{“gini”, “entropy”}, default=”gini”
max_depth:树的最大深度。
min_samples_split:拆分内部节点所需的最少样本数
min_samples_leaf :在叶节点处需要的最小样本数。
'''
from sklearn.tree import DecisionTreeClassifier
tree_iris = DecisionTreeClassifier(min_samples_leaf=5)
tree_iris.fit(X_train,y_train)
tree_iris_test = tree_iris.predict(X_test)
print("4.决策树测试集得分:",tree_iris.score(X_test,y_test))
test_score.append(tree_iris.score(X_test,y_test))
#5.支持向量机
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
'''
C:正则化参数。正则化的强度与C成反比。必须严格为正。惩罚是平方的l2惩罚。
kernel:{'linear','poly','rbf','sigmoid','precomputed'},默认='rbf'
degree:多项式和的阶数
gamma:“ rbf”,“ poly”和“ Sigmoid”的内核系数。
shrinking:是否软间隔分类,默认true
'''
svc_iris = make_pipeline(StandardScaler(), SVC(gamma='auto'))
svc_iris.fit(X_train,y_train)
svc_iris_test = svc_iris.predict(X_test)
print("5.支持向量机测试集得分:",svc_iris.score(X_test,y_test))
test_score.append(svc_iris.score(X_test,y_test))
#可视化
import matplotlib
import matplotlib.pyplot as plt
plt.figure(1)
plt.plot(y_test,'g-o',label='real')
plt.plot(log_pred_test,'r-o',label='log')
plt.plot(lda_iris_test,'b-o',label='lda')
plt.plot(NB_iris_test,'k-o',label='NB')
plt.plot(tree_iris_test,'y-o',label='tree')
plt.plot(svc_iris_test,'m-o',label='svc')
plt.xlabel("test", fontsize=12)
plt.ylabel("class", fontsize=12)
plt.title("测试集表现")
plt.legend()
plt.rcParams['font.sans-serif']=['SimHei']
x_list = ["逻辑回归","线性判别","朴素贝叶斯","决策树","支持向量机"]
plt.figure(2)
plt.plot(x_list,test_score,'g-o',label='test_score')
plt.xlabel("models", fontsize=12)
plt.ylabel("R_score", fontsize=12)
plt.title('test_data R_score')
plt.legend()
plt.rcParams['font.sans-serif']=['SimHei']
matplotlib.rcParams['axes.unicode_minus'] =False
训练结果可视化:
从各模型测试集的
R
2
R^2
R2得分来看,逻辑回归和线性判别一致,最高;朴素贝叶斯和决策树一致,其次;支持向量机的分类结果最差。
从各模型训练集的
R
2
R^2
R2得分来看,前四种算法的预测表现相对效果与测试集一致,而SVM在训练集上表现得最高,在测试集上表现最差,可判断SVM存在过拟合现象,泛化能力差。
注意:这里的五种模型都使用的是默认参数,后续可进一步调参优化,特别是针对SVM。