1.决策树
1.决策树的基本原理:
决策树是一种在分类与回归中都有着非常广泛应用的算法,它的原理是通过一系列问题进行if/else的推导,最终实现决策。
决策树(Decision Tree,简称DT)是最经典的机器学习模型之一,它的预测结果容易理解,易于向业务部门解释,预测速度快,可以处理离散型数据和连续型数据。
2.决策树的构建:
#导入numpy
import numpy as np
#导入画图工具
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
#导入tree模型和和数据集加载工具
from sklearn import tree,datasets
#导入数据集拆分工具
from sklearn.model_selection import train_test_split
wine = datasets.load_wine()
#只选取数据集的前两个特征
X,y = wine.data[:,:2],wine.target
#将数据集拆分成训练集和测试集
X_train,X_test,y_train,y_test = train_test_split(X,y)
#设定决策树分类器最大深度为1
clf = tree.DecisionTreeClassifier(max_depth=1)
#拟合训练数据集
clf.fit(X_train,y_train)
#定义图像中分区的颜色和散点的颜色
cmap_light = ListedColormap(['#FFAAAA','#AAFFAA','#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000','#00FF00','#0000FF'])
#分别用样本的两个特征值创建图像的横轴和纵轴
x_min,x_max = X_train[:,0].min()-1,X_train[:,0].max()+1
y_min,y_max = X_train[:,1].min()-1,X_train[:,1].max()+1
xx,yy = np.meshgrid(np.arange(x_min,x_max,.02),np.arange(y_min,y_max,.02))
Z =clf.predict(np.c_[xx.ravel(),yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx,yy,Z,cmap=cmap_light)
#用散点把样本表示出来
plt.scatter(X[:,0],X[:,1],c=y,cmap=cmap_bold,edgecolor='k',s=20)
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
plt.title("Classifier:(max_depth=1)")
plt.show()
运行代码,得到如图所示的结果:
结果分析:很显然,最大深度为1时分类器的表现肯定不会太好,分类器只分了两类,我们需要加大深度试试看结果会有什么变化。
#设定决策树深度为3
clf2 = tree.DecisionTreeClassifier(max_depth=3)
#重新拟合数据
clf2.fit(X_train,y_train)
#这次我们让max_depth=3,进行绘图
#定义图像中分区的颜色和散点的颜色
cmap_light=ListedColormap(['#FFAAAA','#AAFFAA','#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000','#00FF00','#0000FF'])
cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])
#分别用样本的两个特征值创建图像的横轴和纵轴
x_min,x_max = X_train[:,0].min()-1,X_train[:,0].max()+1
y_min,y_max = X_train[:,1].min()-1,X_train[:,1].max()+1
xx,yy = np.meshgrid(np.arange(x_min,x_max,.01),np.arange(y_min,y_max,.01))
Z=clf2.predict(np.c_[xx.ravel(),yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx,yy,Z,cmap=cmap_light)
#用散点把样本表示出来
plt.scatter(X[:,0],X[:,1],c=y,cmap=cmap_bold,edgecolor='k',s=20)
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
plt.title("Classifier:(max_depth=3)")
plt.show()
运行代码,得到如图所示的结果:
结果分析:大部分数据点都进入了正确的分类,接下来进一步调整max_depth的值,看会有什么变化?
#设定决策树深度为5
clf3 = tree.DecisionTreeClassifier(max_depth=5)
#重新拟合数据
clf3.fit(X_train,y_train)
#这次我们让max_depth=3,进行绘图
#定义图像中分区的颜色和散点的颜色
cmap_light=ListedColormap(['#FFAAAA','#AAFFAA','#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000','#00FF00','#0000FF'])
#分别用样本的两个特征值创建图像的横轴和纵轴
x_min,x_max = X_train[:,0].min()-1,X_train[:,0].max()+1
y_min,y_max = X_train[:,1].min()-1,X_train[:,1].max()+1
xx,yy = np.meshgrid(np.arange(x_min,x_max,.02),np.arange(y_min,y_max,.02))
Z=clf3.predict(np.c_[xx.ravel(),yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx,yy,Z,cmap=cmap_light)
#用散点把样本表示出来
plt.scatter(X[:,0],X[:,1],c=y,cmap=cmap_bold,edgecolor='k',s=20)
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
plt.title("Classifier:(max_depth=5)")
plt.show()
运行代码,得到如图所示的结果:
结果分析:分类器的表现进一步提升了。它在更加努力地把每一个数据点放入正确的分类当中。
3.决策树的工作过程:
分析:为了控制图片不要太大,我们选择了用max_depth=3的分类器来绘制图形,可以方便观看。
先从决策树的根部开始看起,第一个条件是酒精含量小于或等于12.745,samples=133指在根节点上,有133个样本。Value=[41,53,39]是指有41个样本属于class_0,53个样本属于class_1,其余39个样本属于class_2.接下来我们跟着树枝一起前进,在酒精度小于或等于12.745这个条件为true的时候,决策树判断分类为class_1,如果是False,则判断为class_0,这样到下一层,判断为class_1的样本共有53个,而判断class_0的样本则有80个,而再下一层则对酒的苹果酸含量进行判断,进一步对样本进行分类。左边class_1的分支的判断条件是苹果酸含量小于或等于2.445,如果为True,则再判断酒精含量是否小于或等于12.49,如果为False则判断酒精含量是否低于12.12,一次类推,直到将样本全部放进3个分类当中。
4.决策树的优势与不足:
优势:
1.可以很容易地将模型进行可视化,看得明白。
2.由于决策树算法对每个样本特征进行单独处理,因此并不需要对数据进行转换,因此不需要对数据进行预处理。
不足:
1.即便我们在建模的时候可以使用类似max_depth或是max_leaf_nodes等参数来对决策树进行预剪枝处理,但它还是不可避免会出现过拟合的问题,也就让模型的泛化性能大打折扣了。为了避免过拟合问题,下面介绍随机森林算法。
2.随机森林基本原理
1.随机森林的概念:随机森林有的时候也被称为随机决策森林,是一种集合学习方法,既可以用于分类,也可以用于回归。而所谓集合学习算法,其实就是把多个机器学习算法综合在一起,制造出一个更大模型的意思。
2.随机森林的构建
from sklearn.model_selection import train_test_split
#导入随机森林
from sklearn.ensemble import RandomForestClassifier
#载入红酒数据集
from sklearn import datasets
wine = datasets.load_wine()
#选择数据集的前两个特征
X = wine.data[:,:2]
y = wine.target
#将数据集拆分为训练集和测试集
X_train,X_test,y_train,y_test = train_test_split(X,y)
#设定随机森林中有6棵树
forest = RandomForestClassifier(n_estimators=6,random_state=3)
#使用模型拟合数据
forest.fit(X_train,y_train)
运行结果如图所示:
结果分析:随机森林向我们返回了包含自身全部参数的信息,让我们重点看一下其中几个必要重要的参数:
1.bootstrap参数:
代表的是bootstrap sample,也就是“有放回抽样”的意思,指每次从样本空间中可以重复抽取同一个样本(因为样本在第一次被抽取之后又被放回去了),形象一点来说,如原始样本是['西瓜',‘苹果’,‘香蕉’,‘桃子’],那么经过bootstrap sample重构的样本就可能是[‘西瓜’,‘西瓜’,‘香蕉’,‘桃子’],还可能是[‘苹果’,‘香蕉’,‘桃子’,‘桃子’].Bootstrap sample生成的数据集和原始数据集在数据量上是完全一样的,但由于进行了重复采样,因此其中有一些数据点会丢失。
2.max_features:
max_features参数的设置,还是有些讲究的,假如把max_features设置为样本全部的特征数n_features就意味着模型会在全部特征中进行筛选,这样在特征选择这一步,就没有随机性可言了。而如果把max_features的值设为1,就意味着模型在数据特征上完全没有选择的余地,只能去寻找这一个被随机选出来的特征向量的阈值了。所以说,max_features的取值越高,随机森林里的每一棵决策树就会“长得越像”,它们因为有更多的不同特征可以选择,也就会更容易拟合数据;反之,如果max_features取值越低,就会迫使每棵决策树的样子更加不同,而且因为特征太少,决策树们不得不制造更多节点来拟合数据。
3.n_estimators:
这个参数控制的是随机森林中决策树的数量。在随机森林构建完成之后,每棵决策树都会单独进行预测。如果是用来进行回归分析的话,随机森林会把所有决策树的值取平均数;如果进行分类,在森林内部会进行“投票”,每棵树预测出数据类别的概率,比如其中一棵树说“这瓶酒80%属于class_1”,另外一棵树说,“这瓶酒60%属于class_2”,随机森林会把这些概率取平均值,然后把样本放入概率最高的分类当中。
4.random_state:
因为随机森林生成的每棵决策树的方法是随机的(所以名字叫随机森林嘛),那么不同的random_state参数会导致模型完全不同,所以如果不希望建模的结果太过于不稳定,一定要固化random_state这个参数的数值。
用图像直观地看一下随机森林分类的表现:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap
#定义图像中分区的颜色和散点的颜色
cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])
#分别用样本的两个特征值创建图像和横轴和纵轴
x_min, x_max = X_train[:, 0].min() - 1, X_train[:, 0].max() + 1
y_min, y_max = X_train[:, 1].min() - 1, X_train[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, .02),
np.arange(y_min, y_max, .02))
Z = forest.predict(np.c_[xx.ravel(), yy.ravel()])
#给每个分类中的样本分配不同的颜色
Z = Z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx, yy, Z, cmap=cmap_light)
#用散点把样本表示出来
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Classifier:RandomForest")
plt.show()
3.随机森林的优势与不足:
优势:
1.集成了决策树的所有优点,而且能弥补决策树的不足。但从便于展示决策过程的角度来说,决策树依旧表现强悍。
2.随机森林算法支持并行处理,对于超大规模数据集来说,随机森林会比较耗时(毕竟要建立很多决策树),不过我们可以用多进程并行处理的方式来解决这个问题。实现方式是调节随机森林的n_jobs参数,记得把n_jobs参数值设为和CPU内核数一致,比如你的CPU内核数是2,那么n_jobs参数设为3或者更大就没有意义了。当然如果你搞不清楚自己的CPU到底多少内核,可以设置n_jobs=-1,这样随机森林会使用CPU的全部内核,速度就会极大提升了。
缺点:
1.并行处理功能在处理超大数据集时能提供良好的性能表现,但也有不足,例如,对于超高纬度数据集、稀疏数据集来说,随机森林就有点捉襟见肘了,在这种情况下,线性模型要比随机森林的表现更好一些。
2.随机森林相对更消耗内存,速度也比线性模型要慢,所以如果程序希望更节省内存和时间,还是选择线性模型。
3.随机森林实例----要不要和相亲对象进一步发展
1.数据集的准备
网上有一个注明的数据集--成年人数据集,包括了数万条样本数据。其中,样本特征包括年龄、工作单位性质、统计权重、学历、受教育时长、婚姻状况、职业、家庭情况、种族、性别、资产所得、资产损失、每周工作时长、原籍、收入。
这个数据集下载地址:http://archive.ics.uci.edu/ml/machine-learning-databases/adult/
载入数据集:
import numpy as np
#导入pandas库
import pandas as pd
#用pandas打开csv文件
data = pd.read_csv('adult.csv',header=None,index_col=False,names=['年龄','单位性质'
,'权重','学历','受教育时长','婚姻状况','职业','家庭情况','种族','性别','资产所得','资产损失','周工作时长','原籍','收入'])
data_lite = data[['年龄','单位性质','学历','性别','周工作时长','职业','收入']]
#数据前五行
data_lite.head()
运行代码,如图所示:
2.用get_dummies处理数据
#使用get_dummies将文本数据转化为数值
data_dummies = pd.get_dummies(data_lite)
#对比样本原始特征和虚拟变量特征
print('样本原始特征:\n',list(data_lite.columns),'\n')
print('虚拟变量特征:\n',list(data_dummies.columns))
运行代码,如图所示:
结果分析:可以看到get_dummies很聪明,他把字符串类型的特征拆分开,把单位性质分为“单位性质_Federal-gov” “单位性质_Local-gov”等,如果样本人群的工作单位是联邦政府,那么“单位性质_Federal-gov”这个特征的值就是1,而其他的工作单位性质特征值就是0,这样把字符串巧妙地转换成了0和1这两个整型数据
查看前五行:
data_dummies.head()
结果:
从图中可以看出,新的数据集已经扩充到了46列,原因就是get_dummies把元数据集的特征拆分了很多列,现在我们把各列分配给特征向量X和分类标签y
#定义数据集的特征值
features = data_dummies.loc[:,'年龄':'职业_ Transport-moving']
X=features.values
y = data_dummies['收入_ >50K'].values
print('特征形态:{} 标签形态:{}'.format(X.shape,y.shape))
在这段代码中,我们让特征为“年龄”这一列到“职业_Transportation-moving”这一列,而标签y是“收入>=50k”这一列,如果大于50K,则y=1,否则y=0.运行代码:
结果:特征形态:(32561, 44) 标签形态:(32561,)
3.用决策树建模
from sklearn import tree
from sklearn.model_selection import train_test_split
X_train,X_test, y_train,y_test= train_test_split(X,y,random_state=0)
go_dating_tree = tree.DecisionTreeClassifier(max_depth=5)
go_dating_tree.fit(X_train,y_train)
print('模型得分:{:.2f}'.format(go_dating_tree.score(X_test,y_test)))
运行代码后,结果:
模型得分:0.80
结果分析:
可以看到,基于训练数据集的模型在测试集中得到了0.8的评分,还是可以接受的。也就是这个模型的预测准确率在80%。
4.新数据测试
我们知道,MR.Z年龄37岁,在省机关工作,学历是硕士,性别男(当然了。。。),每周工作40小时,职业是文员,现在我们把MR.Z的数据进行输入,并用模型对他的收入进行预测:
Mr_Z =[[37, 40,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,0]]
dating_dec = go_dating_tree.predict(Mr_Z)
print(dating_dec)
运行结果:[0]
结果分析:是的,机器冰冷地告诉小Q这个残酷的事实,MR.Z并不符合她的要求。
注意:本节用到的adult数据集其实是从没过1994年人口普查数据库抽取而来,而且其中的收入指的是年收入,并非月收入。我们只是用这个数据集来演示决策树的用法,其对我们真实生活场景的参考意义不大。