Python机器学习及实践——基础篇:监督学习经典模型(分类学习)
机器学习中监督学习模型的任务重点在于,根据已有经验知识对未知样本的目标/标记进行预测。根据目标预测变量的类型不同,可以把监督学习任务大体分为分类学习和回归预测两类。
监督学习任务的基本架构和流程:首先准备训练数据,可以是文本、图像、音频等;然后抽取所需要的特征,形成特征向量(Feature Vectors);接着,把这些特征向量连同对应的标记/目标(Labels)一并送入学习算法(Machine Learning Algorithm)中,训练出一个预测模型(Predictive Model);然后采用同样的特征抽取方法作用于新测试数据,得到用于测试的特征向量;最后,使用预测模型对这些待测试的特征向量进行预测并得到结果(Expected Label)。
监督学习基本架构和流程
1.线性分类器
线性分类器(Linear Classifier)是一种假设特征与分类结果存在线性关系的模型。这个模型通过累加计算每个维度的特征与各自权重的乘积来帮助类别决策。
应用案例:良/恶性肿瘤预测 :原始数据共有699条样本,每条样本有11列不同的数值:1列用于检索的id,9列与肿瘤相关的医学特征,以及一列表征肿瘤类型的数值。所有9列用于表示肿瘤医学特质的数值均被量化为1~10之间的数字,而肿瘤的类型也借由数字2和数字4分别指代良性与恶性。不过,这份数据也声明其中包含16个缺失值,并用“?”标出。事实上,缺失值问题广泛存在于现实数据中,也是机器学习任务无法回避的问题。
# 良/恶性乳腺癌肿瘤数据预处理
import pandas as pd
import numpy as np
# 创建特征列表
colnames = ['SampleNum', 'Clump Thickness', 'Cell Size', 'Cell Shape', 'Marginal Adhesion',
'Single Epithelial Cell Size', 'Bare Nuclei', 'Bland Chromatin', 'Normal Nucleoli', 'Mitoses', 'Class']
# 使用pandas.read_csv函数从网络上读取指定数据
data = pd.read_csv(
'https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data',
names=colnames)
# print(data.head(10))
通常情况下,25%的数据会作为测试机,75%的数据会用于训练集。
# 准备良/恶性乳腺癌肿瘤训练、测试数据
# 使用sklearn.model_selection里的train_test_split模块用于分割数据
from sklearn.model_selection import train_test_split
# 随机采样25%的数据用于测试,剩下的75%用于构建训练集合
X_train,X_test,y_train,y_test = train_test_split(data[colnames[1:10]],data[colnames[10]],test_size=0.25,random_state=33)
# 查验训练样本的数量和类别分布
print(y_train.value_counts())
# 查验测试样本的数量和类别分布
print(y_test.value_counts())
接下来,使用Logistic回归和随机梯度参数估计两种方法对上述处理后的训练数据进行学习,并且根据测试样本特征进行预测。
# 从sklearn.preprocessing里导入StandardScaler。
from sklearn.preprocessing import StandardScaler
# 从sklearn.linear_model里导入LogisticRegression与SGDClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import SGDClassifier
# 标准化数据,保证每个维度的特征数据方差为1,均值为0。使得预测结果不会被某些维度过大的特征值而主导
ss = StandardScaler()
X_train = ss.fit_transform(X_train)
X_test = ss.fit_transform(X_test)
# 初始化LogisticRegression与SGDClassifier
lr = LogisticRegression()
sgdc = SGDClassifier()
# 调用LogisticRegression中的fit函数/模块用来训练模型参数
lr.fit(X_train, y_train)
# 使用训练好的模型lr对X_test进行预测,结果存储在变量lr_y_predict中
lr_y_predict = lr.predict(X_test)
# 调用SGDClassifier中的fit函数/模块用来训练模型参数。
sgdc.fit(X_train, y_train)
# 使用训练好的模型sgdc对X_test进行预测,结果存储在变量sgdc_y_predict中
sgdc_y_predict = sgdc.predict(X_test)
接下来,我们需要对性能进行测评,主要使用的指标有准确性(Accuracy)、召回率(Recall)、精确率(Precision)以及F1指标(F1 measure):
# 使用线性分类模型从事良/恶性肿瘤预测任务的性能分析
from sklearn.metrics import classification_report
# 使用Logistic回归模型自带的评分函数score获得模型在测试集上的准确性结果
print("Accuracy of LR Classifier: ", lr.score(X_test, y_test))
# 利用classification_report模块获得LogisticRegression其他三个指标的结果
print(classification_report(y_test, lr_y_predict, target_names=['Benign', 'Malignant']))
# 使用随机梯度下降模型自带的评分函数score获得模型在测试集上的准确性结果
print("Accuracy of SGD Classifier: ", sgdc.score(X_test, y_test))
# 利用classification_report模块获得SGDClassifier其他三个指标的结果
print(classification_report(y_test, sgdc_y_predict, target_names=['Benign', 'Malignant']))
发现LogisticRegression比SGDClassifier在测试集上的表现有更高的准确性。这是因为Scikit-learn中采用解析的方式精确计算LogisticRegression的参数,而使用梯度法估计SGDClassifier的参数。
一般而言,对于训练数据规模在10万量级以上的数据,考虑到时间的消耗,推荐使用随机梯度算法对模型参数进行估计。
2.支持向量机(分类)
支持向量机分类器(Support Vector Classifier)是根据训练样本的分布,搜索所有可能的线性分类器中最佳的那个。决定其直线位置的样本并不是所有训练数据,而是其中的两个空间间隔最小的两个不同类别的数据点,把这种可以用来真正帮助决策最优线性分类模型的数据点叫做“支持向量”
应用案例:手写字体数字图像识别
# 从sklearn.datasets中导入手写体数字加载器
from sklearn.datasets import load_digits
# 从通过数据加载器获得手写体数字的数码图像数据并存储在digits变量中
digits = load_digits()
# 检查数据规模和特征维度
print(digits.data.shape)
通过数据分隔获取75%的训练样本和25%的测试样本
# 使用sklearn.model_selection里的train_test_split模块用于分割数据
from sklearn.model_selection import train_test_split
# 随机采样25%的数据用于测试,剩下的75%用于构建训练集合
X_train, X_test, y_train, y_test = train_test_split(digits.data, digits.target, test_size=0.25, random_state=33)
# 检查训练数据和测试数据的规模
#print(y_train.shape)
#print(y_test.shape)
使用样本训练基于线性假设的支持向量机模型。
# 使用支持向量机(分类)对手写体数字图像进行识别
# 从sklearn.preprocessing中导入数据标准化模块
from sklearn.preprocessing import StandardScaler
# 从sklearn.svm中导入基于线性假设的支持向量机分类器LinearSVC
from sklearn.svm import LinearSVC
# 对训练和测试的特征数据进行标准化
ss = StandardScaler()
X_train = ss.fit_transform(X_train)
X_test = ss.fit_transform(X_test)
# 初始化线性假设的支持向量机分类器LinearSVC
lsvc = LinearSVC()
# 进行模型训练
lsvc.fit(X_train, y_train)
# 利用训练好的模型对测试样本的数字类别进行预测,预测结果保存到变量y_predict
y_predict = lsvc.predict(X_test)
与之前一样,使用准确性、召回率、精确率和F1指标。
# 性能测评
# 使用模型自带的评估函数进行准确性测评
print("The Accuracy of LinearSVC is: ", lsvc.score(X_test, y_test))
# 利用classification_report模块获得SGDClassifier其他三个指标的结果
from sklearn.metrics import classification_report
print(classification_report(y_test, y_predict, target_names=digits.target_names.astype(str)))
注意:召回率、准确率和F1指标最先适用于二分类任务。这里有10个类别,即10个数字,无法直接计算上述指标,通常的做法是逐一评估某个类别的这三个性能指标:把所有其他的类别堪称阴性(负)样本 ,这样一来,就创造了10个二分类任务。
3.朴素贝叶斯
朴素贝叶斯(Naive Bayes)分类器的构造基础是贝叶斯理论。
朴素贝叶斯分类器会单独考量每一维度特征被分类的条件概率,进而综合这些概率并对其所在的特征向量做出分类预测。因此,这个模型的基本数学假设是:各个维度上的特征被分类的 条件概率之间是相互独立的 。
应用案例:新闻文本分类
读取20类新闻文本的数据细节
# 从sklearn.datasets中导入新闻数据抓取器fetch_20newsgroups
from sklearn.datasets import fetch_20newsgroups
# fetch_20newsgroups即时从互联网下载数据
news = fetch_20newsgroups(subset='all')
# 查看数据规模和细节
print(len(news.data))
print(news.data[0])
20类新闻文本数据分割
# 使用sklearn.model_selection里的train_test_split模块用于分割数据
from sklearn.model_selection import train_test_split
# 随机采样25%的数据样本作为测试集
X_train, X_test, y_train, y_test = train_test_split(news.data, news.target, test_size=0.25, random_state=33)
先将文本转化为特征向量,然后利用朴素贝叶斯模型从训练数据中估计参数,最后利用这些概率参数对同样转化为特征向量的测试新闻样本进行类别预测。
使用朴素贝叶斯分类器对新闻文本数据进行类别预测
# 从sklearn.feature_extraction.text中导入用于文本特征向量转化模块
from sklearn.feature_extraction.text import CountVectorizer
vec = CountVectorizer()
X_train = vec.fit_transform(X_train)
X_test = vec.transform(X_test)
# 从sklearn.native_bayes中导入朴素贝叶斯模型
from sklearn.naive_bayes import MultinomialNB
# 使用默认参数初始化朴素贝叶斯模型
mnb = MultinomialNB()
# 利用训练数据对模型参数进行估计
mnb.fit(X_train, y_train)
# 对测试样本进行类别预测,结果存储在变量y_predict中
y_predict = mnb.predict(X_test)
对朴素贝叶斯分类器在新闻文本数据上的表现性能进行评估
# 利用classification_report模块获得详细的分类性能报告
from sklearn.metrics import classification_report
print('The Accuracy of Naive Bayes Classifier is:', mnb.score(X_test, y_test))
print(classification_report(y_test, y_predict, target_names=news.target_names))
朴素贝叶斯模型被广泛应用于海量互联网文本分类任务。由于其较强的特征条件独立假设,使得模型预测所需要估计的参数规模从幂指数量级向线性量级减少,极大地节约了内存消耗和计算时间。但是,也正是收到这种强假设的限制,模型训练时无法将各个特征之间的联系考量在内,使得该模型在其他数据特征关联性较强的分类任务上的性能表现不佳。
4.K近邻(分类)
寻找与待分类的样本在特征空间中距离最近的K个已标记样本作为参考,帮助做出分类决策。随着K的不同,会获得不同效果的分类器。
应用案例:鸢尾花分类
地区Iris数据集细节资料
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@File : Iris.py
@Author: Xinzhe.Pang
@Date : 2019/7/20 16:17
@Desc :
"""
# 从sklearn.datasets导入Iris数据加载器
from sklearn.datasets import load_iris
# 使用加载器读取数据并存入变量iris
iris = load_iris()
# 查看数据规模
print(iris.data.shape)
# 查看数据说明
print(iris.DESCR)
对数据进行随机分割,25%的样本用于测试,75%的样本用于模型的训练
# 使用sklearn.model_selection里的train_test_split模块用于分割数据
from sklearn.model_selection import train_test_split
# 使用train_test_split,利用随机种子random_state采样25%的数据作为测试集
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.25, random_state=33)
使用K紧邻分类器对鸢尾花数据进行类别预测
# 从sklearn.preprocessing中导入数据标准化模块
from sklearn.preprocessing import StandardScaler
# 从sklearn.neighbors选择导入KNeighborsClassifier,即K近邻分类器
from sklearn.neighbors import KNeighborsClassifier
# 对训练和测试的特征数据进行标准化
ss = StandardScaler()
X_train = ss.fit_transform(X_train)
X_test = ss.fit_transform(X_test)
# 使用K近邻分类器对测试数据进行类别预测,预测结果存储在变量y_predict中
knc = KNeighborsClassifier()
knc.fit(X_train, y_train)
y_predict = knc.predict(X_test)
对K近邻分类器在鸢尾花数据上的预测性能进行评估
# 使用模型自带的评估函数进行准确性测评
print("The Accuracy of K-Nearest Neighbor Classifier: ", knc.score(X_test, y_test))
# 利用classification_report模块获得详细的分类性能报告
from sklearn.metrics import classification_report
print(classification_report(y_test, y_predict, target_names=iris.target_names))
K近邻算法与其他模型最大的不同在于:该模型没有参数训练过程。也就是说,没有通过任何学习算法分析训练数据,而只是根据测试样本在训练数据的分布直接做出分类决策。因此,K近邻属于无参模型(Nonparametric model)中非常简单的一种。但是需要非常高的计算复杂度和内存消耗,是一种平方级别的算法。
5.决策树
决策树是描述非线性关系的不二之选。使用多种不同特征组合搭建搓成决策树中需要考虑特征节点的选取顺序。常用的度量方式有信息熵(In'formation Gain)和基尼不纯性(Gini Impurity)。
应用案例:泰坦尼克号乘客生存预测
import pandas as pd
titanic = pd.read_csv('http://biostat.mc.vanderbilt.edu/wiki/pub/Main/DataSets/titanic.txt')
print(titanic.head())
使用决策树模型预测泰坦尼克号乘客的生还情况
# 特征的选择
X = titanic[['pclass','age','sex']]
y = titanic['survived']
# 对当前选择的特征进行选择
print(X.info())
根据上面的输出结果,有几个数据处理任务:
1)age列,只有633个,需要补全
2)sex和pclass两个数据列的值都是类别的,需要转化为数值特征,用0/1代替
# 首先补充age数据,使用平均数或者中位数
X['age'].fillna(X['age'].mean(), inplace=True)
# 重新检查数据完整性
print(X.info())
对数据进行分割,划分训练集和测试集,并执行决策树分类器
# 数据分割
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=33)
# 使用scikit-learn.feature_extraction中的特征转换器
from sklearn.feature_extraction import DictVectorizer
vec = DictVectorizer(sparse=False)
# 转换特征后,发现所有的类别型的特征都被单独剥离出来了,形成单独的一列特征,数值型的则保持不变
X_train = vec.fit_transform(X_train.to_dict(orient='record'))
print(vec.feature_names_)
# 同样需要对测试数据的特征进行转化
X_test = vec.transform(X_test.to_dict(orient='record'))
# 从sklearn.tree中导入决策树分类器
from sklearn.tree import DecisionTreeClassifier
# 使用默认参数初始化决策树分类器
dtc = DecisionTreeClassifier()
# 使用分割到的训练数据进行模型学习
dtc.fit(X_train, y_train)
# 用训练好的决策树模型对测试特征数据进行预测
y_predict = dtc.predict(X_test)
决策树模型对泰坦尼克号乘客是否生还的预测性能
# 从sklearn.metrics导入classification_report
from sklearn.metrics import classification_report
# 输出预测准确性
print(dtc.score(X_test, y_test))
# 输出详细分类性能结果
print(classification_report(y_predict, y_test, target_names=['died', 'survived']))
决策树在模型描述上有着巨大的优势。决策树推理逻辑直观,具有清晰的可解释性,方便模型的可视化。但是决策树属于有参数模型,需要花费时间进行调参。
6.集成学习(分类)
集成(Ensemble)分类模型是综合考量多个分类器的预测结果,从而做出决策。大体分为两类:一类是利用相同的训练数据同时搭建多个独立的分类模型,然后通过投票的方式,以少数服从多数的原则作为最终的分类决策。如随机森林分类器(Ran'do'm Forest Classifier);另一种则是按照一定次序搭建多个分类模型。这些模型之间彼此存在以来关系。例如梯度提升决策树(Gradient Tree Boosting)
应用案例:泰坦尼克号乘客生存预测
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@File : TitanicEnsemble.py
@Author: Xinzhe.Pang
@Date : 2019/7/21 1:38
@Desc :
"""
import pandas as pd
titanic = pd.read_csv('http://biostat.mc.vanderbilt.edu/wiki/pub/Main/DataSets/titanic.txt')
# 特征的选择
X = titanic[['pclass', 'age', 'sex']]
y = titanic['survived']
# 首先补充age数据,使用平均数或者中位数
X['age'].fillna(X['age'].mean(), inplace=True)
# 数据分割
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=33)
# 使用scikit-learn.feature_extraction中的特征转换器
from sklearn.feature_extraction import DictVectorizer
vec = DictVectorizer(sparse=False)
X_train = vec.fit_transform(X_train.to_dict(orient='record'))
X_test = vec.transform(X_test.to_dict(orient='record'))
# 从sklearn.tree中导入决策树分类器
from sklearn.tree import DecisionTreeClassifier
# 使用默认参数初始化决策树分类器
dtc = DecisionTreeClassifier()
# 使用分割到的训练数据进行模型学习
dtc.fit(X_train, y_train)
# 用训练好的决策树模型对测试特征数据进行预测
dtc_y_predict = dtc.predict(X_test)
# 使用随机森林分类器进行集成模型的训练以及预测分析
from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier()
rfc.fit(X_train, y_train)
rfc_y_predict = rfc.predict(X_test)
# 使用梯度提升决策树进行集成模型的训练以及预测分析
from sklearn.ensemble import GradientBoostingClassifier
gbc = GradientBoostingClassifier()
gbc.fit(X_train, y_train)
gbc_y_predict = gbc.predict(X_test)
在测试数据集上比对单一决策树、随机森林分类器以及梯度提升决策树的性能差异。
# 从sklearn.metrics导入classification_report
from sklearn.metrics import classification_report
# 输出单一决策树在测试集上的分类准确性、精确率、召回率以及F1指标
print('The Accuracy of decision tree is: ', dtc.score(X_test, y_test))
print(classification_report(dtc_y_predict, y_test))
# 输出随机森林分类器在测试集上的分类准确性、精确率、召回率以及F1指标
print('The Accuracy of random forest classifier is: ', rfc.score(X_test, y_test))
print(classification_report(rfc_y_predict, y_test))
# 输出梯度提升决策树在测试集上的分类准确性、精确率、召回率以及F1指标
print('The Accuracy of gradient tree boosting is: ', gbc.score(X_test, y_test))
print(classification_report(gbc_y_predict, y_test))
一般而言,工业界为了追求更加强劲的预测性能,经常使用随机森林分类模型作为基线系统(Baseline System)。