整理总结:机器学习常用九大算法

参考资料:极客时间的《数据分析实战45讲》

一、决策树

在现实生活中,我们总会遇到需要各种抉择的场景,而抉择背后的逻辑结构图就是决策树。根据决策树在构建时所参考的指标的不同,决策树算法一共分为ID3算法、C4.5算法和CART算法等。

I、ID3算法 (信息增益)
1. 基本原理

通过以下公式的计算来获得决策树搭建所必需的指标:
G a i n ( D , a ) = E n t r o p y ( D ) − ∑ i = 1 k ∣ D i ∣ ∣ D ∣ E n t r o p y ( D i ) ( 1 ) E n t r o p y ( D ) = − ∑ i = 0 c − 1 p ( C i ∣ D ) l o g 2 P ( C i ∣ D ) ( 2 ) Gain(D,a)=Entropy(D)-\sum_{i=1}^{k} \frac{|D_i|}{|D|}Entropy(D_i) \qquad \qquad \qquad (1)\\ Entropy(D)=-\sum_{i=0}^{c-1}p(C_i|D)log_2^{P(C_i|D)} \qquad \qquad \qquad \qquad (2) Gain(D,a)=Entropy(D)i=1kDDiEntropy(Di)(1)Entropy(D)=i=0c1p(CiD)log2P(CiD)(2)
其中 D 、 a 、 k 、 D i 、 c 、 p ( C i ∣ D ) D、a、k、D_i、c、p(C_i|D) DakDicp(CiD)分别代表的是当前数据集、特征、特征a的所有取值个数、划分后的子数据集、分类标签个数和在当前数据集中被划分为第i个分类标签的概率。

假设当前数据集如下:

天气温度湿度狂风是否打篮球
晴天
晴天
阴天
小雨
小雨
晴天
阴天

我们将整个数据集 D D D作为根结点,运用公式来选择哪一个特征作为分支依据。假设初始数据集 D D D被特征天气分成了三个子集合 D 1 、 D 2 、 D 3 D_1、D_2、D_3 D1D2D3,那么

E n t r o p y ( D ) = − ( 3 7 l o g 2 3 7 + 4 7 l o g 2 4 7 ) = 0.985 E n t r o p y ( D 1 ) = − ( 1 3 l o g 2 1 3 + 2 3 l o g 2 2 3 ) = 0.918 E n t r o p y ( D 2 ) = − ( 1 2 l o g 2 1 2 + 1 2 l o g 2 1 2 ) = 1.0 E n t r o p y ( D 3 ) = − ( 1 3 l o g 2 1 3 + 2 3 l o g 2 2 3 ) = 0.918 G a i n ( D , 天 气 ) = E n t r o p y ( D ) − ∑ i = 1 3 ∣ D i ∣ ∣ D ∣ E n t r o p y ( D i ) = 0.985 − ( 3 / 7 ∗ 0.918 + 2 / 7 ∗ 1.0 + 2 / 7 ∗ 1.0 ) = 0.020 Entropy(D)=-(\frac{3}{7}log_2^{\frac{3}{7}}+\frac{4}{7}log_2^{\frac{4}{7}})=0.985 \\ Entropy(D_1)=-(\frac{1}{3}log_2^{\frac{1}{3}}+\frac{2}{3}log_2^{\frac{2}{3}})=0.918 \\ Entropy(D_2)=-(\frac{1}{2}log_2^{\frac{1}{2}}+\frac{1}{2}log_2^{\frac{1}{2}})=1.0 \\ Entropy(D_3)=-(\frac{1}{3}log_2^{\frac{1}{3}}+\frac{2}{3}log_2^{\frac{2}{3}})=0.918 \\ Gain(D,天气)=Entropy(D)-\sum_{i=1}^{3} \frac{|D_i|}{|D|}Entropy(D_i)=0.985-(3/7*0.918+2/7*1.0+2/7*1.0)=0.020 \\ Entropy(D)=(73log273+74log274)=0.985Entropy(D1)=(31log231+32log232)=0.918Entropy(D2)=(21log221+21log221)=1.0Entropy(D3)=(31log231+32log232)=0.918Gain(D,)=Entropy(D)i=13DDiEntropy(Di)=0.985(3/70.918+2/71.0+2/71.0)=0.020
同理求出当前数据集下其余特征对应的信息增益值
G a i n ( D , 温 度 ) = 0.128 G a i n ( D , 湿 度 ) = 0.020 G a i n ( D , 刮 风 ) = 0.020 Gain(D,温度)=0.128 \\ Gain(D , 湿度)=0.020 \\ Gain(D , 刮风)=0.020 Gain(D,)=0.128Gain(D,湿)=0.020Gain(D,)=0.020
通过数值的对比,我们发现以温度为对象的信息增益最大,因此我们可以判断出在当前数据集中选择温度特征来进行数据集的划分是最好的。
在这里插入图片描述
随后将得到的三个集合再次当作原数据集执行上述步骤,最终得到完整的决策树。
在这里插入图片描述
之所以规定选择信息增益最大的特征来进行数据集的划分,这是因为通过公式一,我们可以发现所谓的信息增益不过是父子节点间的信息熵的差值,而选择信息增益最大的特征来进行创建分支,本质上是选择某一特征来展开枝干使得父节点所丢失的信息熵最大,如此一来就使逐渐搭建成的树的纯度更高。

2. 优势与缺陷

ID3 的算法规则相对简单,可解释性强。同样也存在缺陷,比如我们会发现 ID3 算法倾向于选择取值比较多的属性。如果我们把“编号”作为一个属性,那么“编号”将会被选为最优属性 ,但实际上“编号”是无关属性的。


II、C4.5算法 (信息增益率)
1. 基本原理

C4.5算法是ID3算法的改进版本,因此与ID3算法的步骤是基本一致的,其主要改进的部分在于以下几点:

  1. 采用信息增益率来作为决策树搭建的参考指标
  2. 采用悲观剪枝,减少模型过拟合从而导致容错能力低、泛化能力差、死板的可能
  3. 离散化处理连续属性
  4. 自定义了处理缺失值的方法
2. 优势与缺陷

C4.5 在 ID3 的基础上,用信息增益率代替了信息增益,解决了噪声敏感的问题,并且可以对构造树进行剪枝、处理连续数值以及数值缺失等情况,但是由于 C4.5 需要对数据集进行多次扫描,算法效率相对较低。


III、CART算法 (基尼指数)
1. 基本原理

通过以下公式的计算来获得决策树搭建所必需的指标:

G I N I ( D , a ) = ∑ i = 1 k D i D G I N I ( D i ) G I N I ( D ) = 1 − ∑ i = 0 c − 1 [ p ( C i ∣ D ) ] 2 GINI(D,a)=\sum_{i=1}^{k}\frac{D_i}{D}GINI(D_i) \\ GINI(D)=1-\sum_{i=0}^{c-1}[p(C_i|D)]^2 GINI(D,a)=i=1kDDiGINI(Di)GINI(D)=1i=0c1[p(CiD)]2
其中 D 、 a 、 k 、 D i 、 c 、 p ( C i ∣ D ) D、a、k、D_i、c、p(C_i|D) DakDicp(CiD)分别代表的是当前数据集、特征、特征a的所有取值个数、划分后的子数据集、分类标签个数和在当前数据集中被划分为第i个分类标签的概率。

假设当前数据集如下:

天气温度湿度狂风是否打篮球
晴天
晴天
阴天
小雨
小雨
晴天
阴天
晴天
小雨
小雨
晴天
晴天

我们将整个数据集作为根结点,运用公式来选择哪一个特征作为分支依据。假设初始数据集 D D D被特征天气分成了三个子集合 D 1 、 D 2 D_1、D_2 D1D2,那么

G I N I ( D 1 ) = 1 − 1 = 0 G I N I ( D 2 ) = 1 − ( 0. 5 2 + 0. 5 2 ) = 0.5 G I N I ( D , 狂 风 ) = 6 12 G I N I ( D 1 ) + 6 12 G I N I ( D 2 ) = 0 + 0.5 ∗ 0.5 = 0.25 GINI(D_1)=1-1=0 \\ GINI(D_2)=1-(0.5^2+0.5^2)=0.5 \\ GINI(D,狂风)=\frac{6}{12}GINI(D_1)+\frac{6}{12}GINI(D_2)=0+0.5*0.5=0.25 GINI(D1)=11=0GINI(D2)=1(0.52+0.52)=0.5GINI(D,)=126GINI(D1)+126GINI(D2)=0+0.50.5=0.25
同理可以求出当前数据集下其余特征对应的信息增益值。
G I N I ( D , 天 气 ) = ⋯ G I N I ( D , 温 度 ) = ⋯ G I N I ( D , 湿 度 ) = ⋯ GINI(D,天气)=\cdots \\ GINI(D,温度)=\cdots \\ GINI(D,湿度)=\cdots GINI(D,)=GINI(D,)=GINI(D,湿)=
通过数值的对比,假设我们发现以狂风为对象的基尼指标值最小,那么我们可以判断出在当前数据集中选择狂风特征来进行数据集的划分是最好的。
在这里插入图片描述
随后将得到的两个集合再次当作原数据集执行上述步骤,最终就可以得到完整的决策树。

2. Python代码实战
# encoding=utf-8
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
# 准备数据集
iris=load_iris()
# 获取特征集和分类标识
features = iris.data
labels = iris.target
# 随机抽取33%的数据作为测试集,其余为训练集
train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size=0.33, random_state=0)
# 创建CART分类树
clf = DecisionTreeClassifier(criterion='gini')
# 拟合构造CART分类树
clf = clf.fit(train_features, train_labels)
# 用CART分类树做预测
test_predict = clf.predict(test_features)
# 预测结果与测试集结果作比对
score = accuracy_score(test_labels, test_predict)
print("CART分类树准确率 %.4lf" % score)

IV、泰坦尼克乘客生存预测实战

给定某一乘客的相关信息,预测其是否生存。

1. 初始数据集

在这里插入图片描述

2. 数据获取
import pandas as pd
# 数据加载
train_data = pd.read_csv('./Titanic_Data/train.csv')
test_data = pd.read_csv('./Titanic_Data/test.csv')
3. 数据探索
# 数据探索
print(train_data.info())
print('-'*30)
print(train_data.describe())
print('-'*30)
print(train_data.describe(include=['O']))
print('-'*30)
print(train_data.head())
print('-'*30)
print(train_data.tail())
4. 数据清洗
# 使用平均年龄来填充年龄中的nan值
train_data['Age'].fillna(train_data['Age'].mean(),inplace=True)
test_data['Age'].fillna(test_data['Age'].mean(),inplace=True)
# 使用票价的均值填充票价中的nan值
train_data['Fare'].fillna(train_data['Fare'].mean(),inplace=True)
test_data['Fare'].fillna(test_data['Fare'].mean(),inplace=True)
# 使用登录最多的港口来填充登录港口的nan值
train_data['Embarked'].fillna('S', inplace=True)
test_data['Embarked'].fillna('S',inplace=True)
5. 特征选择

# 特征选择
features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
train_features = train_data[features]
train_labels = train_data['Survived']
test_features = test_data[features]		
from sklearn.feature_extraction import DictVectorizer	【特征值里有一些是字符串,这样不方便后续的运算,需要转成数值类型。即宽边长方法】
dvec=DictVectorizer(sparse=False)
train_features=dvec.fit_transform(train_features.to_dict(orient='record'))
6. 模型搭建
from sklearn.tree import DecisionTreeClassifier
# 构造ID3决策树
clf = DecisionTreeClassifier(criterion='entropy')	【指定使用ID3算法搭建决策树模型】
# 决策树训练
clf.fit(train_features, train_labels)
7. 模型预测
test_features=dvec.transform(test_features.to_dict(orient='record'))
# 决策树预测
pred_labels = clf.predict(test_features)
8. 模型评估
# 得到决策树准确率
acc_decision_tree = round(clf.score(train_features, train_labels), 6)
print(u'score准确率为 %.4lf' % acc_decision_tree) 【使用训练集来评估,准确率的可信度较低。使用测试集或者K折交叉验证】
import numpy as np
from sklearn.model_selection import cross_val_score
# 使用K折交叉验证 统计决策树准确率
print(u'cross_val_score准确率为 %.4lf' % np.mean(cross_val_score(clf, train_features, train_labels, cv=10)))
9. 结果可视化
借用 Graphviz 可视化工具帮我们把决策树呈现出来

在这里插入图片描述


二、贝叶斯

I. 基本原理

初始数据集(离散型):

编号身高体重鞋码性别
1
2
3
4
5
6
7
8

现在我们想根据一条记录的特征值{身高=“高”,体重=“中”,鞋码=“中”}来预测拥有这些特征值的人的性别。
假设 A 1 A_1 A1={身高=“高”}、 A 2 A_2 A2={体重=“中”}、 A 3 A_3 A3={鞋码=“中”}, C 1 C_1 C1= 男性, C 2 C_2 C2= 女性。那么,根据贝叶斯公式
P ( C j ∣ A 1 A 2 A 3 ) = P ( A 1 A 2 A 3 ∣ C j ) P ( C j ) P ( A 1 A 2 A 3 ) = P ( A 1 ∣ C j ) P ( A 2 ∣ C j ) P ( A 3 ∣ C j ) P ( C j ) P ( A 1 ) P ( A 2 ) P ( A 3 ) P(C_j|A_1A_2A_3)=\frac{P(A_1A_2A_3|C_j)P(C_j)}{P(A_1A_2A_3)} =\frac{P(A_1|C_j) P(A_2|C_j) P(A_3|C_j) P(C_j)}{P(A_1)P(A_2)P(A_3)} P(CjA1A2A3)=P(A1A2A3)P(A1A2A3Cj)P(Cj)=P(A1)P(A2)P(A3)P(A1Cj)P(A2Cj)P(A3Cj)P(Cj)
可以直接获得分类概率,其中 P ( A 1 ∣ C j ) P(A_1|C_j) P(A1Cj)为在性别为 C j C_j Cj的记录中满足 A 1 A_1 A1记录的比例、 P ( A i ) P(A_i) P(Ai)代表的是在初始数据中满足 A i A_i Ai记录的占比。
由于对于任意一个 j j j P ( C j ∣ A 1 A 2 A 3 ) P(C_j|A_1A_2A_3) P(CjA1A2A3)的分母都是一样的,因此选取里面的最大值本质是选择分子最大的。经计算,
P ( A 1 A 2 A 3 ∣ C 1 ) = 1 / 16 P ( A 1 A 2 A 3 ∣ C 2 ) = 0 P(A_1A_2A_3|C_1)=1/16 \\ P(A_1A_2A_3|C_2)=0 P(A1A2A3C1)=1/16P(A1A2A3C2)=0
因为 P ( C i ) P(C_i) P(Ci)是个非负数,因此可以推测出 P ( C 1 ∣ A 1 A 2 A 3 ) P(C_1|A_1A_2A_3) P(C1A1A2A3)值是最大的,从而判断拥有{身高=“高”,体重=“中”,鞋码=“中”}特征的人的性别最大概率是男性。


初始数据集(连续型):

编号身高(CM)体重(斤)鞋码(欧码)性别
118316445
218217044
317816043
417514040
51608835
616510037
716311038
816812039

现在我们想根据一条记录的特征值{身高=“180”,体重=“120”,鞋码=“41”}来预测拥有这些特征值的人的性别。
同样的,我们假设 A 1 A_1 A1={身高=“180”}、 A 2 A_2 A2={体重=“120”}、 A 3 A_3 A3={鞋码=“41”}, C 1 C_1 C1= 男性, C 2 C_2 C2= 女性。
由于数据是连续型的,因此使用贝叶斯来实现分类需要另外的一些步骤,以方便我们计算各个概率的值,如 P ( A i ∣ C j ) 和 P ( A i ) P(A_i|C_j)和P(A_i) P(AiCj)PAi
在计算这些概率前,我们要先通过初始数据集确定各个的分布函数的参数,搭建身高、体重、鞋码、男性的身高、男性的体重、男性的鞋码、女性的身高、女性的体重、女性的鞋码的分布函数,最后通过各自的分布函数找到概率密度函数,从而计算出 P ( A i ) 和 P ( A i ∣ C j ) P(A_i)和P(A_i|C_j) PAiP(AiCj),带入贝叶斯公式中,选择结果值最大的类别即可。


II、文档分类实战

根据输入文档,判断其文章类型,比如垃圾邮件等。

1. 初始数据集

文档 1:this is the bayes document;
文档 2:this is the second second document;
文档 3:and the third one;
文档 4:is this the document。

2. 对文档进行分词
import nltk
word_list = nltk.word_tokenize(text) #英文分词
nltk.pos_tag(word_list) #标注单词的词性


import jieba
word_list = jieba.cut (text) #中文分词
3. 加载停用词表
stop_words = [line.strip().decode('utf-8') for line in io.open('stop_words.txt').readlines()] 
 #停用词就是在分类中没有用的词,这些词一般词频 TF 高,但是 IDF 很低,起不到分类的作用
4. 计算单词的权重
tf = TfidfVectorizer(stop_words=stop_words, max_df=0.5)
features = tf.fit_transform(train_contents)  #得到TF-IDF特征空间 features
#词频TF=单词出现的次数/该文档的总单词数
#逆向文档频率IDF=log(文档总数/()该单词出现的文档树+1))
5. 生成朴素贝叶斯分类器
# 多项式贝叶斯分类器
from sklearn.naive_bayes import MultinomialNB  
clf = MultinomialNB(alpha=0.001).fit(train_features, train_labels)
6. 使用生成的分类器做预测
test_tf = TfidfVectorizer(stop_words=stop_words, max_df=0.5, vocabulary=train_vocabulary)
test_features=test_tf.fit_transform(test_contents)
7. 计算准确率
from sklearn import metrics
print metrics.accuracy_score(test_labels, predicted_labels)

三、支持向量机(SVM)

I、基本原理

一般的分类算法,其本质都是在许多不同类别的点集中勾勒出一条线性直线,使得线性直线尽可能将点集划分成不同的区域,其中每个区域都是同样的类别,在得到新的输入点后可以通过该线性直线快速得将输入点划分到某一个相似类别区域,达成分类的效果。
在这里插入图片描述
但是如果碰到下面的分布情况,就很难以线性方程来描述曲线。

在这里插入图片描述
因此需要支持向量机来解决这种的非线性分类问题。它是通过将二维空间内无法通过直线轻易划分的问题转化成三维空间寻找最佳超平面(最优决策面)的问题,而升维是由支持向量机的核函数来实现。
在这里插入图片描述
更加细致的讲,SVM 就是帮我们找到一个超平面,这个超平面能将不同的样本划分开,同时使得样本集中的点到这个分类超平面的最小距离(即分类间隔)最大化。其中我们定义某类样本集到超平面的距离是这个样本集合内的样本到超平面的最短距离。支持向量就是离分类超平面最近的样本点,因此实际上如果确定了支持向量也就确定了这个超平面。
我们假设这个超平面的方程为
g ( x ) = w T x + b , w ∈ R n , x ∈ R n g(x)=w^Tx+b,w\in R^n,x \in R^n g(x)=wTx+b,wRn,xRn
而点到平面的距离的数学表达式为
d i = ∣ w x i + b ∣ ∣ ∣ w ∣ ∣ d_i=\frac{|wx_i+b|}{||w||} di=wwxi+b
那么我们可以通过凸优化的知识来得到具体的 w 、 b w、b wb 的值,从而得到最佳决策面模型。

可以看到这种支持向量机只能实现二分类的问题,但在实际应用中总能碰到多分类需求,那么此时们该如何使用支持向量机来解决呢?
第一种,一对多方法。
假设我们要把物体分成 A、B、C、D 四种分类,那么我们可以先把其中的一类作为类别一,其他类统一归为类别二。
这样我们可以构造 4 种 SVM:
(1)样本 A 作为正集,B,C,D 作为负集
(2)样本 B 作为正集,A,C,D 作为负集
(3)样本 C 作为正集,A,B,D 作为负集
(4)样本 D 作为正集,A,B,C 作为负集
这种方法,针对 K 个分类,需要训练 K 个分类器,分类速度较快,但训练速度较慢。
第二种,一对一方法。
假设我们要把物体分成 A、B、C 三个类,那么我们可以在任意两类样本之间构造一个 SVM。
这样我们可以构造 3 个分类器:
(1)分类器 1:A、B
(2)分类器 2:A、C
(3)分类器 3:B、C
当对一个未知样本进行分类时,每一个分类器都会有一个分类结果,即为 1 票,最终得票最多的类别就是整个未知样本的类别。

II、乳腺癌检测实战

根据患者乳腺肿块经过细针穿刺 (FNA) 后的数字化图像来判断是否患有乳腺癌

1. 初始数据集

在这里插入图片描述
在这里插入图片描述

2. 数据加载和探索
# 加载数据集,你需要把数据放到目录中
data = pd.read_csv("./data.csv")
# 数据探索
# 因为数据集中列比较多,我们需要把dataframe中的列全部显示出来
pd.set_option('display.max_columns', None)
print(data.columns)
print(data.head(5))
print(data.describe())
3. 数据清洗
# 将特征字段分成3组
features_mean= list(data.columns[2:12])
features_se= list(data.columns[12:22])
features_worst=list(data.columns[22:32])
# 数据清洗
# ID列没有用,删除该列
data.drop("id",axis=1,inplace=True)
# 将B良性替换为0,M恶性替换为1
data['diagnosis']=data['diagnosis'].map({'M':1,'B':0})
4. 特征选择
# 将肿瘤诊断结果可视化
sns.countplot(data['diagnosis'],label="Count")
plt.show()
# 用热力图呈现features_mean字段之间的相关性
corr = data[features_mean].corr()
plt.figure(figsize=(14,14))
# annot=True显示每个方格的数据
sns.heatmap(corr, annot=True)
plt.show()

# 特征选择
features_remain = ['radius_mean','texture_mean', 'smoothness_mean','compactness_mean','symmetry_mean', 'fractal_dimension_mean'] 
5. 数据准备
# 抽取30%的数据作为测试集,其余作为训练集
train, test = train_test_split(data, test_size = 0.3)# in this our main data is splitted into train and test
# 抽取特征选择的数值作为训练和测试数据
train_X = train[features_remain]
train_y=train['diagnosis']
test_X= test[features_remain]
test_y =test['diagnosis']

# 采用Z-Score规范化数据,保证每个特征维度的数据均值为0,方差为1
ss = StandardScaler()
train_X = ss.fit_transform(train_X)
test_X = ss.transform(test_X)
6. 模型搭建、预测和评估
# 创建SVM分类器
model = svm.SVC()
# 用训练集做训练
model.fit(train_X,train_y)
# 用测试集做预测
prediction=model.predict(test_X)
print('准确率: ', metrics.accuracy_score(test_y,prediction))

四、K最近邻(KNN)

I、基本原理

初始数据集:

电影名称打斗次数接吻次数电影类型
《战狼》1005动作
《红海行动》953动作
《碟中谍6》10531动作
《前任3》259爱情
《春娇救志明》360爱情
《泰坦尼克号》1080爱情

我们可以把打斗次数看成 X 轴,接吻次数看成 Y 轴,将每条记录看成一个个点在坐标系上标记,我们可以看出这些点集会根据各自的特征而聚集在不同的区域上,自动形成分类模型。此时对于一个输入点,我们只需要看其附近的K个点大部分处于哪个类别,就能评估出其大概率属于哪个类别。
在这里插入图片描述

II、手写数字识别实战

对值为0~9的图像进行计算机识别并给出其对应的数字

1. 初始数据集
sklearn 自带的MNIST 数据集,它只包括了 1797 幅数字图像,每幅图像大小是 8*8 像素,分别对应于0~9的值
2. 数据加载和探索
# 加载数据
digits = load_digits()
data = digits.data
# 数据探索
print(data.shape)
# 查看第一幅图像
print(digits.images[0])
# 第一幅图像代表的数字含义
print(digits.target[0])
# 将第一幅图像显示出来
plt.gray()
plt.imshow(digits.images[0])
plt.show()
3. 数据处理
# 分割数据,将25%的数据作为测试集,其余作为训练集(你也可以指定其他比例的数据作为训练集)
train_x, test_x, train_y, test_y = train_test_split(data, digits.target, test_size=0.25, random_state=33)
# 采用Z-Score规范化
ss = preprocessing.StandardScaler()
train_ss_x = ss.fit_transform(train_x)
test_ss_x = ss.transform(test_x)
4. 模型搭建、预测与评估
# 创建KNN分类器
knn = KNeighborsClassifier() 
knn.fit(train_ss_x, train_y) 
predict_y = knn.predict(test_ss_x) 
print("KNN准确率: %.4lf" % accuracy_score(test_y, predict_y))
5. KNN、SVM、贝叶斯和决策树的表现对比
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_digits
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import MultinomialNB
from sklearn.tree import DecisionTreeClassifier
import matplotlib.pyplot as plt
# 创建SVM分类器
svm = SVC()
svm.fit(train_ss_x, train_y)
predict_y=svm.predict(test_ss_x)
print('SVM准确率: %0.4lf' % accuracy_score(test_y, predict_y))
# 采用Min-Max规范化
mm = preprocessing.MinMaxScaler()
train_mm_x = mm.fit_transform(train_x)
test_mm_x = mm.transform(test_x)
# 创建Naive Bayes分类器
mnb = MultinomialNB()
mnb.fit(train_mm_x, train_y) 
predict_y = mnb.predict(test_mm_x) 
print("多项式朴素贝叶斯准确率: %.4lf" % accuracy_score(test_y, predict_y))
# 创建CART决策树分类器
dtc = DecisionTreeClassifier()
dtc.fit(train_mm_x, train_y) 
predict_y = dtc.predict(test_mm_x) 
print("CART决策树准确率: %.4lf" % accuracy_score(test_y, predict_y))

五、K均值聚类(K-Means)

I、基本原理

初始数据集:
在这里插入图片描述
首先我们将每条记录映射成一个多维空间内的点,并随机选择K个点作为中心点,随后通过遍历各点分别计算距离中日韩三点的距离,选择距离最近的对应中心点作为归属类别,这样我们得到了就是以K个中心点为基础扩展而来的K个点集,接下来我们再以平均值的形式计算K个点集中的新的中心点,并不断重复上述的步骤,直至每一个点的分类结果不改变。
具体而言,我们需要先对初始数据集中记录的每一个特征进行规范化,得
在这里插入图片描述
计算每一个点到中国、日本和韩国中心点的距离,并进行分类划分。
在这里插入图片描述
在得到的多个类别点集中,再次计算出各点集的新中心点。重复操作,直至分类结果不变,亦或者中心点位置不变,得到最终的聚类结果。
在这里插入图片描述

II、图像分割实战
1. 初始数据集

在这里插入图片描述

2. 数据加载
# 加载图像,并对数据进行规范化
def load_data(filePath):
    # 读文件
    f = open(filePath,'rb')
    data = []
    # 得到图像的像素值
    img = image.open(f)
    # 得到图像尺寸
    width, height = img.size
    for x in range(width):
        for y in range(height):
            # 得到点(x,y)的三个通道值
            c1, c2, c3 = img.getpixel((x, y))
            data.append([c1, c2, c3])
    f.close()
    # 采用Min-Max规范化
    mm = preprocessing.MinMaxScaler()
    data = mm.fit_transform(data)
    return np.mat(data), width, height

# 加载图像,得到规范化的结果img,以及图像尺寸
img, width, height = load_data('./weixin.jpg')
3. 模型搭建
# 用K-Means对图像进行2聚类
kmeans =KMeans(n_clusters=2)
kmeans.fit(img)
label = kmeans.predict(img)
# 将图像聚类结果,转化成图像尺寸的矩阵
label = label.reshape([width, height])

4. 结果二颜色可视化
# 创建个新图像pic_mark,用来保存图像聚类的结果,并设置不同的灰度值
pic_mark = image.new("L", (width, height))
for x in range(width):
    for y in range(height):
        # 根据类别设置图像灰度, 类别0 灰度值为255, 类别1 灰度值为127
        pic_mark.putpixel((x, y), int(256/(label[x][y]+1))-1)
pic_mark.save("weixin_mark.jpg", "JPEG")
5. 结果十六颜色可视化

from skimage import color
# 将聚类标识矩阵转化为不同颜色的矩阵
label_color = (color.label2rgb(label)*255).astype(np.uint8)
label_color = label_color.transpose(1,0,2)
images = image.fromarray(label_color)
images.save('weixin_mark_color.jpg')

六、EM聚类

I、基本原理

通常,我们可以假设样本是符合高斯分布的,每个高斯分布都属于这个模型的组成部分,要分成 K 类就相当于是 K 个组成部分。
这样我们可以先初始化每个组成部分的高斯分布的参数,然后再看来每个样本是属于哪个组成部分。这也就是 E 步骤。
再通过得到的这些隐含变量结果,反过来求每个组成部分高斯分布的参数,即 M 步骤。反复 EM 步骤,直到每个组成部分的高斯分布参数不变为止,得到最终的聚类结果。

EM 算法相当于一个框架(最大似然估计法),可以采用不同的模型来进行聚类,比如 GMM(高斯混合模型),或者 HMM(隐马尔科夫模型)来进行聚类。

II、王者荣耀角色聚类实战

收集王者荣耀不同英雄的基本特征数据集,并在该数据集中实现聚类的效果。

# -*- coding: utf-8 -*-
import pandas as pd
import csv
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.mixture import GaussianMixture
from sklearn.preprocessing import StandardScaler
 
# 数据加载,避免中文乱码问题
data_ori = pd.read_csv('./heros7.csv', encoding = 'gb18030')
features = [u'最大生命',u'生命成长',u'初始生命',u'最大法力', u'法力成长',u'初始法力',u'最高物攻',u'物攻成长',u'初始物攻',u'最大物防',u'物防成长',u'初始物防', u'最大每5秒回血', u'每5秒回血成长', u'初始每5秒回血', u'最大每5秒回蓝', u'每5秒回蓝成长', u'初始每5秒回蓝', u'最大攻速', u'攻击范围']
data = data_ori[features]
 
# 对英雄属性之间的关系进行可视化分析
# 设置plt正确显示中文
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
# 用热力图呈现features_mean字段之间的相关性
corr = data[features].corr()
plt.figure(figsize=(14,14))
# annot=True显示每个方格的数据
sns.heatmap(corr, annot=True)
plt.show()
 
# 相关性大的属性保留一个,因此可以对属性进行降维
features_remain = [u'最大生命', u'初始生命', u'最大法力', u'最高物攻', u'初始物攻', u'最大物防', u'初始物防', u'最大每5秒回血', u'最大每5秒回蓝', u'初始每5秒回蓝', u'最大攻速', u'攻击范围']
data = data_ori[features_remain]
data[u'最大攻速'] = data[u'最大攻速'].apply(lambda x: float(x.strip('%'))/100)
data[u'攻击范围']=data[u'攻击范围'].map({'远程':1,'近战':0})
# 采用Z-Score规范化数据,保证每个特征维度的数据均值为0,方差为1
ss = StandardScaler()
data = ss.fit_transform(data)
# 构造GMM聚类
gmm = GaussianMixture(n_components=30, covariance_type='full')
gmm.fit(data)
# 训练数据
prediction = gmm.predict(data)
print(prediction)
# 将分组结果输出到CSV文件中
data_ori.insert(0, '分组', prediction)
data_ori.to_csv('./hero_out.csv', index=False, sep=',')

七、关联规则挖掘

I、基本原理

初始数据集:
在这里插入图片描述
我们先计算单个商品的支持度,支持度是指某个商品组合出现的次数与总次数之间的比例,也就是说支持度越高,代表这个组合出现的概率越大。

商品项集支持度
牛奶4/5
面包4/5
尿布5/5
可乐2/5
啤酒3/5
鸡蛋1/5

进一步筛选,筛选的阀值这里假设为0.5,也就是最小支持度,筛选后的结果只有支持度大于等于这个值的集合。

商品项集支持度
牛奶4/5
面包4/5
尿布5/5
啤酒3/5

在这个基础上,我们再将商品两两组合,得到 k=2 项的支持度。

商品项集支持度
牛奶 、面包3/5
牛奶、尿布1/5
牛奶、啤酒2/5
面包、尿布4/5
面包、啤酒2/5
尿布、啤酒3/5

再次筛掉小于最小值支持度的商品组合。

商品项集支持度
牛奶 、面包3/5
面包、尿布4/5
尿布、啤酒3/5

再对商品进行K=3项的组合。

商品项集支持度
牛奶 、面包、尿布3/5
面包、尿布、啤酒2/5
牛奶、面包、啤酒1/5

再次筛选。

商品项集支持度
牛奶 、面包、尿布3/5

发现进行K=4的商品组合的支持度计算,结果为空,此时算法结束。

上述每一个经过筛选的结果项集都是频繁项集,频繁项集就是支持度大于等于最小支持度 (Min Support) 阈值的项集,因此Apriori 算法其实就是查找频繁项集 (frequent itemset) 的过程。
其中,除了支持度这个概念,关联规则还涉及置信度和提升度。置信度是一个条件概率,就是在 A 发生的情况下,B 发生的概率是多少。而提升度代表的是“商品 A 的出现,对商品 B 的出现概率提升了多少”。

II、导演选择演员的偏好探索实战
1. 数据抓取
# -*- coding: utf-8 -*-
# 下载某个导演的电影数据集
from efficient_apriori import apriori
from lxml import etree
import time
from selenium import webdriver
import csv
driver = webdriver.Chrome()
# 设置想要下载的导演 数据集
director = u'宁浩'
# 写CSV文件
file_name = './' + director + '.csv'
base_url = 'https://movie.douban.com/subject_search?search_text='+director+'&cat=1002&start='
out = open(file_name,'w', newline='', encoding='utf-8-sig')
csv_write = csv.writer(out, dialect='excel')
flags=[]
# 下载指定页面的数据
def download(request_url):
  driver.get(request_url)
  time.sleep(1)
  html = driver.find_element_by_xpath("//*").get_attribute("outerHTML")
  html = etree.HTML(html)
  # 设置电影名称,导演演员 的XPATH
  movie_lists = html.xpath("/html/body/div[@id='wrapper']/div[@id='root']/div[1]//div[@class='item-root']/div[@class='detail']/div[@class='title']/a[@class='title-text']")
  name_lists = html.xpath("/html/body/div[@id='wrapper']/div[@id='root']/div[1]//div[@class='item-root']/div[@class='detail']/div[@class='meta abstract_2']")
  # 获取返回的数据个数
  num = len(movie_lists)
  if num > 15: #第一页会有16条数据
    # 默认第一个不是,所以需要去掉
    movie_lists = movie_lists[1:]
    name_lists = name_lists[1:]
  for (movie, name_list) in zip(movie_lists, name_lists):
    # 会存在数据为空的情况
    if name_list.text is None: 
      continue
    # 显示下演员名称
    print(name_list.text)
    names = name_list.text.split('/')
    # 判断导演是否为指定的director
    if names[0].strip() == director and movie.text not in flags:
      # 将第一个字段设置为电影名称
      names[0] = movie.text
      flags.append(movie.text)
      csv_write.writerow(names)
  print('OK') # 代表这页数据下载成功
  print(num)
  if num >= 14: #有可能一页会有14个电影
    # 继续下一页
    return True
  else:
    # 没有下一页
    return False

# 开始的ID为0,每页增加15
start = 0
while start<10000: #最多抽取1万部电影
  request_url = base_url + str(start)
  # 下载数据,并返回是否有下一页
  flag = download(request_url)
  if flag:
    start = start + 15
  else:
    break
out.close()
print('finished')

在这里插入图片描述

2. 模型搭建,输出频繁项集和频繁规则
# -*- coding: utf-8 -*-
from efficient_apriori import apriori
import csv
director = u'宁浩'
file_name = './'+director+'.csv'
lists = csv.reader(open(file_name, 'r', encoding='utf-8-sig'))
# 数据加载
data = []
for names in lists:
     name_new = []
     for name in names:
           # 去掉演员数据中的空格
           name_new.append(name.strip())
     data.append(name_new[1:])
# 挖掘频繁项集和关联规则
itemsets, rules = apriori(data, min_support=0.5,  min_confidence=1)
print(itemsets)
print(rules)

在这里插入图片描述
可以看出,宁浩导演喜欢用徐峥和黄渤,并且有徐峥的情况下,一般都会用黄渤。

八、网页排名(PageRank)

I、基本原理

当我们在搜索引擎填写关键字得到的结果页面中,页面之间的排序顺序主要是由这个页面的影响力来决定的,一般而言,页面的影响力越大排名越在前面。
页面的影响力的计算公式如下:
P R ( u ) = ∑ v ∈ B u P R ( v ) L ( v ) PR(u)=\sum_{v \in B_u}{\frac{PR(v)}{L(v)}} PR(u)=vBuL(v)PR(v)
其中, u u u 为待评估的页面, B u Bu Bu​ 为页面 u u u 的入链集合。针对入链集合中的任意页面 v v v,它能给 u u u带来的影响力是其自身的影响力 P R ( v ) PR(v) PR(v)除以 v v v页面的出链数量,即页面 v v v把影响力 P R ( v ) PR(v) PR(v) 平均分配给了它的出链。

具体而言的话,假设我们现在有四个页面,它们之间的相互引用关系如下:
在这里插入图片描述
我们可以知道当用户访问 A 的时候,跳转到 B、C 或者 D 的可能性均为 1/3,同理对B、C和D也能分别得到一个4X1的矩阵,将这些矩阵进行列拼接可以得到这四个页面的转移矩阵 M M M
,

在这里插入图片描述

我们再假设每个页面的初始影响力都是平均的,即都是1/4,那么我么可以得到一个4X1的页面影响力矩阵 W 0 W_0 W0

,


在这里插入图片描述

将两个矩阵进行相乘,得到第一次转移后各页面的影响力。


在这里插入图片描述

不断用新的 w i w_i wi来乘以 M M M直至 w i w_i wi的值不再发生变化,此时 w i w_i wi的值就是各页面最终平衡状态下的影响力,在这里结果为 ( 0.3333 , 0.2222 , 0.2222 , 0.2222 ) (0.3333,0.2222,0.2222,0.2222) (0.3333,0.2222,0.2222,0.2222)
根据结果可知,A页面的影响力相对较大,因此其在排名中应位于最靠前的位置上。

II、希拉里邮件中的人物关系分析实战

通过 PageRank 算法计算每个人物在邮件关系网络中的权重,最后筛选出来最有价值的人物来进行关系网络图的绘制。

1. 初始数据集

Alises.csv:别名和人物的对应关系
Emails.csv:所有公开邮件的内容,发送者和接收者的信息
Persons.csv: 邮件中所有人物的姓名及对应的 ID

2. 代码实现
# -*- coding: utf-8 -*-
# 用 PageRank 挖掘希拉里邮件中的重要任务关系
import pandas as pd
import networkx as nx
import numpy as np
from collections import defaultdict
import matplotlib.pyplot as plt
# 数据加载
emails = pd.read_csv("./input/Emails.csv")
# 读取别名文件
file = pd.read_csv("./input/Aliases.csv")
aliases = {}
for index, row in file.iterrows():
    aliases[row['Alias']] = row['PersonId']
# 读取人名文件
file = pd.read_csv("./input/Persons.csv")
persons = {}
for index, row in file.iterrows():
    persons[row['Id']] = row['Name']
# 针对别名进行转换        
def unify_name(name):
    # 姓名统一小写
    name = str(name).lower()
    # 去掉, 和 @后面的内容
    name = name.replace(",","").split("@")[0]
    # 别名转换
    if name in aliases.keys():
        return persons[aliases[name]]
    return name
# 画网络图
def show_graph(graph, layout='spring_layout'):
    # 使用 Spring Layout 布局,类似中心放射状
    if layout == 'circular_layout':
        positions=nx.circular_layout(graph)
    else:
        positions=nx.spring_layout(graph)
    # 设置网络图中的节点大小,大小与 pagerank 值相关,因为 pagerank 值很小所以需要 *20000
    nodesize = [x['pagerank']*20000 for v,x in graph.nodes(data=True)]
    # 设置网络图中的边长度
    edgesize = [np.sqrt(e[2]['weight']) for e in graph.edges(data=True)]
    # 绘制节点
    nx.draw_networkx_nodes(graph, positions, node_size=nodesize, alpha=0.4)
    # 绘制边
    nx.draw_networkx_edges(graph, positions, edge_size=edgesize, alpha=0.2)
    # 绘制节点的 label
    nx.draw_networkx_labels(graph, positions, font_size=10)
    # 输出希拉里邮件中的所有人物关系图
    plt.show()
# 将寄件人和收件人的姓名进行规范化
emails.MetadataFrom = emails.MetadataFrom.apply(unify_name)
emails.MetadataTo = emails.MetadataTo.apply(unify_name)
# 设置遍的权重等于发邮件的次数
edges_weights_temp = defaultdict(list)
for row in zip(emails.MetadataFrom, emails.MetadataTo, emails.RawText):
    temp = (row[0], row[1])
    if temp not in edges_weights_temp:
        edges_weights_temp[temp] = 1
    else:
        edges_weights_temp[temp] = edges_weights_temp[temp] + 1
# 转化格式 (from, to), weight => from, to, weight
edges_weights = [(key[0], key[1], val) for key, val in edges_weights_temp.items()]
# 创建一个有向图
graph = nx.DiGraph()
# 设置有向图中的路径及权重 (from, to, weight)
graph.add_weighted_edges_from(edges_weights)
# 计算每个节点(人)的 PR 值,并作为节点的 pagerank 属性
pagerank = nx.pagerank(graph)
# 将 pagerank 数值作为节点的属性
nx.set_node_attributes(graph, name = 'pagerank', values=pagerank)
# 画网络图
show_graph(graph)

# 将完整的图谱进行精简
# 设置 PR 值的阈值,筛选大于阈值的重要核心节点
pagerank_threshold = 0.005
# 复制一份计算好的网络图
small_graph = graph.copy()
# 剪掉 PR 值小于 pagerank_threshold 的节点
for n, p_rank in graph.nodes(data=True):
    if p_rank['pagerank'] < pagerank_threshold: 
        small_graph.remove_node(n)
# 画网络图,采用circular_layout布局让筛选出来的点组成一个圆
show_graph(small_graph, 'circular_layout')

在这里插入图片描述

在这里插入图片描述

九、增强学习(Adaboost)

I、基本原理

初始数据集:

X0123456789
Y111-1-1-1111-1

假设第一轮训练中,我们得到10个样本的权重都是均匀的,那么整个样本集的权重矩阵 D 1 = ( 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 ) D_1=(0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1) D1=(0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1),同时假设我们已经获得了三个基础分类器 f i ( x ) f_i(x) fi(x).
f 1 ( x ) = { 1 , x ≤ 2.5 − 1 , x > 2.5 ; f 2 ( x ) = { − 1 , x ≤ 5.5 1 , x > 5.5 ; f 3 ( x ) = { 1 , x ≤ 8.5 − 1 , x > 8.5 f_1(x)= \left\{ \begin{array}{ll} 1, & x \leq 2.5\\ -1, & x > 2.5 \end{array} \right. \quad;\quad f_2(x)= \left\{ \begin{array}{ll} -1, & x \leq 5.5\\ 1, & x > 5.5 \end{array} \right. \quad ;\quad f_3(x)= \left\{ \begin{array}{ll} 1, & x \leq 8.5\\ -1, & x > 8.5 \end{array} \right. f1(x)={1,1,x2.5x>2.5;f2(x)={1,1,x5.5x>5.5;f3(x)={1,1,x8.5x>8.5
依次将X值带入分类器中,使得到的结果与实际对应的Y值对比,可以知道 f 1 、 f 2 、 f 3 f_1、f_2、f_3 f1f2f3的错误率分别为0.3、0.4和0.3,此时我们选择错误率最小的 f 1 、 f 3 f_1、f_3 f1f3中任选一个作为最优分类器,这里我们选择 f 1 f_1 f1,即 G 1 = f 1 G_1=f_1 G1=f1,并通过下面的公式计算该最优分类器的权重 α 1 = 0.4236 \alpha_1=0.4236 α1=0.4236
α i = 1 2 l o g 1 − e i e i \alpha_i=\frac{1}{2}log{\frac{1-e_i}{e_i}} αi=21logei1ei
再进一步利用下面的公式更新每一个样本的权重,即最新的样本集权重矩阵 D 2 = ( 0.0715 , 0.0715 , 0.0715 , 0.0715 , 0.0715 , 0.0715 , 0.1666 , 0.1666 , 0.1666 , 0.0715 ) D_2=(0.0715, 0.0715, 0.0715, 0.0715, 0.0715, 0.0715, 0.1666, 0.1666, 0.1666, 0.0715) D2=(0.0715,0.0715,0.0715,0.0715,0.0715,0.0715,0.1666,0.1666,0.1666,0.0715)

D k + 1 = ( w k + 1 , 1 , w k + 1 , 2 , … , w k + 1 , N ) w k + 1 , i = w k , i Z k e x p ( − α k y i G k ( x i ) ) , i = 1 , 2 , … , N D_{k+1}=(w_{k+1,1},w_{k+1,2},\dots,w_{k+1,N}) \\ w_{k+1,i}=\frac{w_{k,i}}{Z_k}exp(-\alpha_ky_iG_k(x_i)),i=1,2,\dots,N Dk+1=(wk+1,1,wk+1,2,,wk+1,N)wk+1,i=Zkwk,iexp(αkyiGk(xi)),i=1,2,,N
其中 w k + 1 , i w_{k+1,i} wk+1,i指的是在 k + 1 k+1 k+1轮训练中第 i i i个样本的权重。
接下来开始第二轮训练,重复上述的操作, f 1 、 f 2 、 f 3 f_1、f_2、f_3 f1f2f3的错误率分别为0.16663、 0.07154和0.0715*3,此时我们选择错误率最小的 f 3 f_3 f3作为最优分类器,即 G 2 = f 3 G_2=f_3 G2=f3,并计算出了 α 2 = 0.6496 \alpha_2=0.6496 α2=0.6496 D 3 = ( 0.0455 , 0.0455 , 0.0455 , 0.1667 , 0.1667 , 0.01667 , 0.1060 , 0.1060 , 0.1060 , 0.0455 ) D_3=(0.0455,0.0455,0.0455,0.1667, 0.1667,0.01667,0.1060, 0.1060, 0.1060, 0.0455) D3=(0.0455,0.0455,0.0455,0.1667,0.1667,0.01667,0.1060,0.1060,0.1060,0.0455)
开始第三轮,仍然是重复操作,得到 G 3 = f 2 、 α 3 = 0.7514 G_3=f_2、\alpha_3=0.7514 G3=f2α3=0.7514。此时得到最终的强分类器 G ( x ) = 0.4236 G 1 ( x ) + 0.6496 G 2 ( x ) + 0.7514 G 3 ( x ) G(x) = 0.4236G1(x) + 0.6496G2(x)+0.7514G3(x) G(x)=0.4236G1(x)+0.6496G2(x)+0.7514G3(x)

II、房价预测实战
1. 初始数据集

在这里插入图片描述

2. 代码实现
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.datasets import load_boston
from sklearn.ensemble import AdaBoostRegressor
# 加载数据
data=load_boston()
# 分割数据
train_x, test_x, train_y, test_y = train_test_split(data.data, data.target, test_size=0.25, random_state=33)
# 使用AdaBoost回归模型
regressor=AdaBoostRegressor()
regressor.fit(train_x,train_y)
pred_y = regressor.predict(test_x)
mse = mean_squared_error(test_y, pred_y)
print("房价预测结果 ", pred_y)
print("均方误差 = ",round(mse,2))


# 使用决策树回归模型
dec_regressor=DecisionTreeRegressor()
dec_regressor.fit(train_x,train_y)
pred_y = dec_regressor.predict(test_x)
mse = mean_squared_error(test_y, pred_y)
print("决策树均方误差 = ",round(mse,2))
# 使用KNN回归模型
knn_regressor=KNeighborsRegressor()
knn_regressor.fit(train_x,train_y)
pred_y = knn_regressor.predict(test_x)
mse = mean_squared_error(test_y, pred_y)
print("KNN均方误差 = ",round(mse,2))
3. 模型的对比
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.metrics import zero_one_loss
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import  AdaBoostClassifier
# 设置AdaBoost迭代次数
n_estimators=200
# 使用
X,y=datasets.make_hastie_10_2(n_samples=12000,random_state=1)
# 从12000个数据中取前2000行作为测试集,其余作为训练集
train_x, train_y = X[2000:],y[2000:]
test_x, test_y = X[:2000],y[:2000]
# 弱分类器
dt_stump = DecisionTreeClassifier(max_depth=1,min_samples_leaf=1)
dt_stump.fit(train_x, train_y)
dt_stump_err = 1.0-dt_stump.score(test_x, test_y)
# 决策树分类器
dt = DecisionTreeClassifier()
dt.fit(train_x,  train_y)
dt_err = 1.0-dt.score(test_x, test_y)
# AdaBoost分类器
ada = AdaBoostClassifier(base_estimator=dt_stump,n_estimators=n_estimators)
ada.fit(train_x,  train_y)
# 三个分类器的错误率可视化
fig = plt.figure()
# 设置plt正确显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
ax = fig.add_subplot(111)
ax.plot([1,n_estimators],[dt_stump_err]*2, 'k-', label=u'决策树弱分类器 错误率')
ax.plot([1,n_estimators],[dt_err]*2,'k--', label=u'决策树模型 错误率')
ada_err = np.zeros((n_estimators,))
# 遍历每次迭代的结果 i为迭代次数, pred_y为预测结果
for i,pred_y in enumerate(ada.staged_predict(test_x)):
     # 统计错误率
    ada_err[i]=zero_one_loss(pred_y, test_y)
# 绘制每次迭代的AdaBoost错误率 
ax.plot(np.arange(n_estimators)+1, ada_err, label='AdaBoost Test 错误率', color='orange')
ax.set_xlabel('迭代次数')
ax.set_ylabel('错误率')
leg=ax.legend(loc='upper right',fancybox=True)
plt.show()

在这里插入图片描述
从图中可以看出,弱分类器的错误率最高,只比随机分类结果略好,准确率稍微大于 50%。决策树模型的错误率明显要低很多。 AdaBoost 模型在迭代次数超过 25 次之后,错误率有了明显下降,经过 125 次迭代之后错误率的变化形势趋于平缓。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值