前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >sklearn入门教程:监督学习流程与线性分类器

sklearn入门教程:监督学习流程与线性分类器

作者头像
生信技能树
发布2019-05-15 10:19:44
1.1K0
发布2019-05-15 10:19:44
举报
文章被收录于专栏:生信技能树生信技能树

监督学习是机器学习中的一个方法,其原理是根据已有经验知识对未知样本的目标/标记进行预测。根据目标预测变量的类型不同,我们可以把监督学习任务大体分为分类学习(预测一个分类标签)与回归预测(函数输出是一个连续的值)两类。

  • 监督学习任务的基本架构和流程可以如下图所示:
  • 首先准备训练数据,可以是统计数据或文本、图像、音频等;
  • 然后抽取所需要的特征(featureextractor),形成特征向量(features),或者称该过程为矢量化;
  • 接着,把这些特征向量连同对应的标记/目标(label)一并送入机器学习算法,例如分类模型(machinelearning algorithm)中,训练出一个预测模型,图中是分类模型(classifiermodel);
  • 然后,采用同样的特征抽取方法作用于新测试数据,得到用于测试的特征向量;
  • 最后,使用预测模型对这些待测试的特征向量进行预测并得到结果。

监督学习任务的基本架构和流程

分类学习是最为常见的监督学习问题,并且其中的经典模型也最为广泛地被应用。其中,最基础的便是二分类(binary classification)问题,即判断是非,从两个类别中选择一个作为预测结果;除此之外还有多类分类(multiclass classification)的问题,即在多于两个类别中选择一个;甚至还有多标签分类(multi-label classification)问题,与上述二分类以及多类分类问题不同,多标签分类问题判断一个样本是否同时属于多个不同类别。

在实际生活和工作中,我们会遇到许许多多的分类问题,比如,医生对肿瘤性质的判定;邮政系统对手写体邮编数字进行识别;生物学家对物种类型的鉴定;生物信息工程师对基因功能的鉴定;甚至,我们还能够对某些大灾难的经历者是否生还进行预测等。

为了展现其广泛的应用环境,对于每一种分类学习模型,我会整理一系列文章,使用不同的任务以及数据样例进行说明。

■ ■

首先我们先看一下线性分类器的原理和代码。

线性分类器(Linear Classifiers),是一种假设特征与分类结果存在线性关系的模型。这个模型通过累加计算每个维度的特征与各自权重的乘积来帮助类别决策。

首先,如果我们定义x=[x1,x2,...,xn]来代表n维特征列向量,同时用n维列向量w=[w1,w2,...,wn]来代表对应的权重,或者叫做系数(Coefficient);同时为了避免其过坐标原点这种硬性假设,增加个1截距(Intercept)。由此这种线性关系便可以表达为:

公式1

这里的f∈R,取值范围分布在整个实数域中。

然而,我们所要处理的最简单的二分类问题希望f∈{0,1}因此需要一个函数把原先的f∈R映射到(0, 1)之间。于是我们想到了逻辑斯蒂(Logistic)函数:

公式2

这里的z∈R,并且g∈(0,1),并且其函数图像如下图所示。

综上,如果将z替换为f,整合方程式(1)和方程式(2),就获得了一个经典的线性分类器,逻辑斯蒂回归模型(Logistic Regression):

公式3

从逻辑斯蒂函数图像中便可以观察到该模型如何处理一个待分类的特征向量:如果z=0,那么g = 0.5;若z<0,则g<0.5,这个特征向量被判别为一类;反之,若z>0,则g>0.5,其被归为另外一类。

当使用一组m个用于训练的特征向量X=[x1,x2,...,xm]和其所对应的分类目标y=[y1,y2,...,ym],我们希望逻辑斯蒂模型可以在这组训练集上取得最大似然估计(MaximumLikelihood)的概率L(w,b)。或者说,至少要在训练集上表现如此:

公式4

为了学习到决定模型的参数(Parameters),即系数w和截距h,我们普遍使用一种精确计算的解析算法和一种快速估计的随机梯度上升(Stochastic Gradient Ascend)算法。这里我们不会过多介绍这些算法的细节,有兴趣的读者可以自行查阅斯坦福大学吴恩达(Andrew Ng)教授的机器学习课件。

我这里只会向大家介绍如何使用这两种算法求解模型参数。原始数据的下载地址为:http://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data

我们可以在其网页中找到该数据描述:

我们得知该原始数据共有699条样本,每条样本有11列不同的数值:1列用于检索的id,9列与肿瘤相关的医学特征,以及一列表征肿瘤类型的数值。所有9列用于表示肿瘤医学特质的数值均被量化为1-10之间的数字,而肿瘤的类型也借由数字2和数字4分别指代良性与恶性。不过,这份数据也声明其中包含16个缺失值,并且用“?”标出。事实上,缺失值问题广泛存在于现实数据中,也是机器学习任务无法回避的问题;本文中,先对于存在缺失值的数据,都暂时予以忽略,而用于处理缺失数据的方法会在后续为大家介绍。

下面这段代码用于预处理原始肿瘤数据:

代码语言:javascript
复制
#导入pandas与numpy工具包
代码语言:javascript
复制
importpandasaspd
代码语言:javascript
复制
importnumpyasnp
代码语言:javascript
复制
#创建特征名称列表
代码语言:javascript
复制
columns_names=['Sample code number','Clump Thickness','Uniformity of Cell Size','Uniformity of Cell Shape','Marginal Adhesion','Single Epithelial Cell Size','Bare Nuclei','Bland Chromatin','Normal Nucleoli','Mitoses','Class']
代码语言:javascript
复制
#使用pandas.read_csv函数从互联网读取指定数据data=pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data',names=columns_names)
代码语言:javascript
复制
#将'?'替换为标准缺失值表示
代码语言:javascript
复制
data=data.replace(to_replace='?',value=np.nan)
代码语言:javascript
复制
#丢弃带有缺失值的数据(只要一个维度有缺失值)
代码语言:javascript
复制
data=data.dropna(how='any')
代码语言:javascript
复制
#输出data的数据量和维度
代码语言:javascript
复制
data.shape#(683,11)

如以上代码的输出所示,经过简单的处理之后,无缺失值的数据样本共有683条,特征包括细胞厚度、细胞大小、形状等9个维度,并且每个维度的特征均量化为1-10之间的数值进行表示,如下图所示:

由于原始数据没有提供对应的测试样本用于评估模型性能,因此需要对带有标记的数据进行分割。通常情况下,25%的数据会作为测试集,其余75%的数据用于训练,如以下代码所示。

代码语言:javascript
复制
#使用sklearn.cross_validation里的train_test_split模块用于分割数据
代码语言:javascript
复制
fromsklearn.cross_validation importtrain_test_split
代码语言:javascript
复制
#随机采样25%的数据用于测试,剩下的75%用于构建训练集合X_train,X_test,y_train,y_test=train_test_split(data[columns_names[1:10]],data[columns_names[10]],test_size=0.25,random_state=33)#查验训练样本的数量和类别分布
代码语言:javascript
复制
y_train.value_counts()#2  344#4  168#查验测试样本的数量和类别分布
代码语言:javascript
复制
y_test.value_counts()#2  100#4  71

综上,我们用于训练样本共有512条(344条良性肿瘤数据、168条恶性肿瘤数据),测试样本有171条(100条良性肿瘤数据、71条恶性肿瘤数据)。

有了数据后,接下来我们在以下代码中使用逻辑斯蒂回归与随机梯度参数估计两种方法对上述处理后的训练数据进行学习,并且根据测试样本特征进行预测。

代码语言:javascript
复制
#从sklearn.preprocessing里导入StandardScaler
代码语言:javascript
复制
fromsklearn.preprocessingimportStandardScaler
代码语言:javascript
复制
#从sklearn.linear_model里导入LogisticsRegression与SGDClassifier
代码语言:javascript
复制
fromsklearn.linear_modelimportLogisticRegression
代码语言:javascript
复制
fromsklearn.linear_modelimportSGDClassifier
代码语言:javascript
复制
#标准化数据,保证每个维度的特征数据方差为1,均值为0,使得预测结果不会被某些数值过大的特征值主导
代码语言:javascript
复制
ss=StandardScaler()
代码语言:javascript
复制
X_train=ss.fit_transform(X_train)
代码语言:javascript
复制
X_test=ss.transform(X_test)
代码语言:javascript
复制
#初始化LogisticRegression与SGDClassifier#调用LogisticRegression中的fit函数/模块用来训练模型参数#使用训练好的模型lr对X_test进行预测,结果存储在变量lr_y_predict中
代码语言:javascript
复制
lr=LogisticRegression()
代码语言:javascript
复制
sgdc=SGDClassifier()
代码语言:javascript
复制
lr.fit(X_train,y_train)
代码语言:javascript
复制
lr_y_predict=lr.predict(X_test)
代码语言:javascript
复制
#调用SGDClassifier中的fit函数/模块用来训练模型参数#使用训练好的模型sgdc对X_test进行预测,结果存储在变量sgdc_y_predict中
代码语言:javascript
复制
sgdc.fit(X_train,y_train)
代码语言:javascript
复制
sgdc_y_predict=sgdc.predict(X_test)

训练结束后,在以上代码的最后,我们分别利用LogisticRegression与SGDClassifier针对171条测试样本进行预测工作。由于这171条测试样本拥有正确标记,并记录在变量y-test中,因此非常直观的做法是比对预测结果和原本正确标记,计算171条测试样本中,预测正确的百分比。我们在把这个百分比称作准确性(Accuracy),并且将其作为评估分类模型的一个重要性能指标。

顺便提一下评估分类模型的几个重要指标,在许多实际问题中,我们往往更加关注模型对某一特定类别的预测能力。这时,准确性指标就变得笼统了。比如,在“良/恶性肿瘤预测任务”里,医生和患者往往更加关心有多少恶性肿瘤被正确地诊断出来,因为这种肿瘤更加致命。也就是说,在二分类任务下,预测结果(Predicted Condition)和正确标记(True Condition)之间存在4种不同的组合,构成混淆矩阵(Confusion Matrix),如图2-4所示。如果恶性肿瘤为阳性(Positive),良性肿瘤为阴性(Negative),那么,预测正确的恶性肿瘤即为真阳性(True Positive),预测正确的良性肿瘤为真阴性(True Negative);原本是良性肿瘤(Condition negative)误判为恶性肿瘤(Predicted condition positive)的为假阳性(False Positive);而实际是恶性肿瘤,但是预测模型没有检测出来,则为假阴性(False Negative)。事实上,医生和病患最不愿看到的是有假阴性(False Negative)的结果,因为这种误诊会耽误病患的治疗,进而危及生命。

混淆矩阵示例

因此,除了准确性(Accuracy)之外,我们还引人了两个评价指标,分别是召回率(Recall)和精确率(Precision)。它们的定义分别是:

其中,#(True positive)代表真阳性样本的数量,其余以此类推。此外,为了综合考虑召回率与精确率,我们计算这两个指标的调和平均数,得到F1指标(F1 measure)。

F1值之所以使用调和平均数,是因为它除了具备平均功能外,还会对那些召回率和精确率更加接近的模型给予更高的分数;而这也是我们所期待的,因为那些召回率和精确率差距过大的学习模型,往往没有足够的实用价值。

回到本节所讨论的任务,对于乳腺癌肿瘤预测的问题,我们显然更加关注召回率,也就是应该被正确识别的恶性肿瘤的百分比。对于召回率更高的预测模型,医生和患者会更为信赖并给予更多关注。因此,让我们用代码16来更加细致地分析一下两个模型在上述4个指标(准确性、召回率、精确率以及F1指标)的表现情况。

代码语言:javascript
复制
#从sklearn.metrics里导入classification_report模块
代码语言:javascript
复制
fromsklearn.metricsimportclassification_report
代码语言:javascript
复制
#使用逻辑斯蒂回归墨香自带的评分函数score获得模型在测试集上的准确性结果
代码语言:javascript
复制
print('Accuracy of LR Classifier:',lr.score(X_test,y_test))
代码语言:javascript
复制
#使用classificaion_report模块获得LogisticRegression其他三个指标的结果
代码语言:javascript
复制
print(classification_report(y_test,lr_y_predict,target_names=['Benign','Malignant']))
代码语言:javascript
复制
#使用随机梯度下降自带的评分函数score获得模型在测试集上的准确性结果
代码语言:javascript
复制
print('Accuarcy of SGD Classifier:',sgdc.score(X_test,y_test))
代码语言:javascript
复制
#利用classification_report模块获得SGDClassifier其他三个指标的结果
代码语言:javascript
复制
print(classification_report(y_test,sgdc_y_predict,target_names=['Benign','Malignant']))

阅读了以上输出的报告之后,我们可以发现:LogisticRegression比起SGDClassifier在测试集上表现有更高的准确性(Accuracy)。这是因为sklearn中采用解析的方式精确计算LogisticRegression的参数。

线性分类器可以说是最为基本和常用的机器学习模型。尽管其受限于数据特征与分类目标之间的线性假设,我们仍然可以在科学研究与工程实践中把线性分类器的表现性能作为基准。这里所使用的模型包括LogisticRegrcssion与SGDClassifier。相比之下,前者对参数的计算采用精确解析的方式,计算时间长但是模型性能略高;后者采用随机梯度上升算法估计模型参数,计算时间短但是产出的模型性能略低。一般而言,对于训练数据规模在10万量级以上的数据考虑到时间的耗用,笔者更加推荐使用随机梯度算法对模型参数进行估计。

参考文献

[1] 周志华. 机器学习, 北京: 清华大学出版社, 2016.

[2] 范淼, 李超. Python机器学习及实践[M]. 清华大学出版社, 2016.

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 生信技能树 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档