一、决策树优缺点
(1)优点:易于理解;数据的预处理工作可以较少;使用树的成本比如预测数据的时候,对于训练树的数据点往往使用的是数量的对数;能够同时处理数值和分类数据‘处理多输出的问题;属于易于理解的白盒模型;可通过统计测试试验模型;
(2)缺点:如果树过于复杂,即过拟合,导致不能很好的推广;可能不稳定;基于贪婪算法;
二、泰坦尼克号幸存者案例
【1】导入库
#(1)导入库 import pandas as pd from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split from sklearn.model_selection import GridSearchCV from sklearn.model_selection import cross_val_score import matplotlib.pyplot as plt
【2】导入数据集
#(2)导入数据集 data = pd.read_csv(r"data.csv",index_col= 0) data.head() data.info()
【3】对数据集进行预处理 特征筛选
# (3)对数据集进行预处理 特征筛选 data.drop(["Cabin","Name","Ticket"],inplace=True,axis=1) data["Age"] = data["Age"].fillna(data["Age"].mean()) data = data.dropna() data["Sex"] = (data["Sex"]== "male").astype("int") labels = data["Embarked"].unique().tolist() data["Embarked"] = data["Embarked"].apply(lambda x: labels.index(x)) data.head()
【4】提取标签和特征矩阵,分测试集和训练集
# (4)提取标签和特征矩阵,分测试集和训练集 X = data.iloc[:,data.columns != "Survived"] y = data.iloc[:,data.columns == "Survived"] from sklearn.model_selection import train_test_split Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3) for i in [Xtrain, Xtest, Ytrain, Ytest]: i.index = range(i.shape[0]) Xtrain.head()
【5】导入模型,试运行查看结果
#(5) 导入模型,试运行查看结果 clf = DecisionTreeClassifier(random_state=25) clf = clf.fit(Xtrain, Ytrain) score_ = clf.score(Xtest, Ytest) score_ score = cross_val_score(clf,X,y,cv=10).mean() score
【6】在不同max_depth下观察模型的拟合状况
# (6)在不同max_depth下观察模型的拟合状况 tr = [] te = [] for i in range(10): clf = DecisionTreeClassifier(random_state=25 ,max_depth=i+1 ,criterion="entropy" ) clf = clf.fit(Xtrain, Ytrain) score_tr = clf.score(Xtrain,Ytrain) score_te = cross_val_score(clf,X,y,cv=10).mean() tr.append(score_tr) te.append(score_te) print(max(te)) plt.plot(range(1,11),tr,color="red",label="train") plt.plot(range(1,11),te,color="blue",label="test") plt.xticks(range(1,11)) plt.legend() plt.show()
【7】用网格搜索调整参数,枚举参数
网格搜索:
它是通过遍历给定的参数组合来优化模型表现的方法。网格搜索从候选参数集合中,选出一系列参数并把他们组合起来,得到候选参数列表。然后遍历参数列表,把候选参数放在模型中,计算得到该参数组合的得分。而后再从候选参数列表中,选择得分最高的参数,作为模型的最优参数。
# (7)用网格搜索调整参数,枚举参数 import numpy as np gini_thresholds = np.linspace(0,0.5,20) parameters = {'splitter':('best','random') ,'criterion':("gini","entropy") ,"max_depth":[*range(1,10)] ,'min_samples_leaf':[*range(1,50,5)] ,'min_impurity_decrease':[*np.linspace(0,0.5,20)] } clf = DecisionTreeClassifier(random_state=25) GS = GridSearchCV(clf, parameters, cv=10) GS.fit(Xtrain,Ytrain) GS.best_params_
通过网格搜索得到的最佳参数:
分类树在合成数据上的表现:
以sklearn的红酒数据集为例子,展示多个参数会对树形造成怎样的影响。
import numpy as np import matplotlib.pyplot as plt from matplotlib.colors import ListedColormap from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.datasets import make_moons, make_circles, make_classification from sklearn.tree import DecisionTreeClassifier
生成三种数据集:
我们先从sklearn自带的数据库中生成三种类型的数据集:
【1】月亮型数据
【2】环形数据
【3】二分型数据
在这三种数据集上测试决策树的效果。
make_classification库生成随机的二分型数据
# 生成三种数据集 # 我们先从sklearn自带的数据库中生成三种类型的数据集:1)月亮型数据,2)环形数据,3)二分型数据 #make_classification库生成随机的二分型数据 X, y = make_classification(n_samples=100, #生成100个样本 n_features=2, #包含2个特征,即生成二维数据 n_redundant=0, #添加冗余特征0个 n_informative=2, #包含信息的特征是2个 random_state=1, #随机模式1 n_clusters_per_class=1 #每个簇内包含的标签类别有1个 ) plt.scatter(X[:,0],X[:,1])
下面这张图两种数据分得较开,使得机器很容易将数据分成两类。但是这样就不利于机器学习。
#承接 rng = np.random.RandomState(2) X += 2 * rng.uniform(size=X.shape) linearly_separable = (X, y) plt.scatter(X[:,0],X[:,1])
为数据添加噪声,提升机器学习的难度。
构建不同的数据类型:
# 构建不同的数据类型 datasets = [make_moons(noise=0.3, random_state=0), make_circles(noise=0.2, factor=0.5, random_state=1), linearly_separable]
meshgrid的用法:从坐标向量中返回坐标矩阵
例子:二维坐标系中,X轴可以取三个值 1,2,3, Y轴可以取三个值 7,8, 请问可以获得多少个点的坐标?
显而易见是 6 个:
(1, 7) (2, 7) (3, 7)
(1, 8) (2, 8) (3, 8)
可以用meshgrid实现这个:
import numpy as np # 坐标向量 a = np.array([1,2,3]) # 坐标向量 b = np.array([7,8]) # 从坐标向量中返回坐标矩阵 # 返回list,有两个元素,第一个元素是X轴的取值,第二个元素是Y轴的取值 res = np.meshgrid(a,b) #返回结果: [array([ [1,2,3] [1,2,3] ]), array([ [7,7,7] [8,8,8] ])]
画出三种数据集和三棵决策树的分类效应图像:
figure = plt.figure(figsize=(6, 9)) i = 1 for ds_index, ds in enumerate(datasets): # 枚举 X, y = ds # X:全部数据 X = StandardScaler().fit_transform(X) # 标准化,分为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4, random_state=42) # 最小值最大值分别做扰动,创造一个比两个特征区间本身更大范围的区间 x1_min, x1_max = X[:, 0].min() - .5, X[:, 0].max() + .5 x2_min, x2_max = X[:, 1].min() - .5, X[:, 1].max() + .5 # meshgrid函数用两个坐标轴上的点在平面上画格。 # meshgrid生成网格数据,目的是为了绘制决策的边缘 array1,array2 = np.meshgrid(np.arange(x1_min, x1_max, 0.2), np.arange(x2_min, x2_max, 0.2)) cm = plt.cm.RdBu # 生成带有特定颜色的画布 cm_bright = ListedColormap(['#FF0000', '#0000FF']) ax = plt.subplot(len(datasets), 2, i) # 绘制子图 # 行数:len(datasets) ,列数:2 if ds_index == 0: # 设置图表的标签 ax.set_title("Input data") ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright,edgecolors='k') #训练集数据 ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, alpha=0.6,edgecolors='k') # 测试集数据 ax.set_xlim(array1.min(), array1.max()) ax.set_ylim(array2.min(), array2.max()) ax.set_xticks(()) # 设置标签 ax.set_yticks(()) # 设置标签 i += 1 # 循环 ax = plt.subplot(len(datasets),2,i) clf = DecisionTreeClassifier(max_depth=5) clf.fit(X_train, y_train) score = clf.score(X_test, y_test) # 准确率 Z = clf.predict_proba(np.c_[array1.ravel(),array2.ravel()])[:, 1] Z = Z.reshape(array1.shape) ax.contourf(array1, array2, Z, cmap=cm, alpha=.8) ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright, edgecolors='k') ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, edgecolors='k', alpha=0.6) ax.set_xlim(array1.min(), array1.max()) ax.set_ylim(array2.min(), array2.max()) ax.set_xticks(()) ax.set_yticks(()) if ds_index == 0: ax.set_title("Decision Tree") ax.text(array1.max() - .3, array2.min() + .3, ('{:.1f}%'.format(score*100)), size=15, horizontalalignment='right') i += 1 plt.tight_layout() plt.show()
针对数据拟合的结果:
上图中的第二类对于环形数据使用决策树得到的结果并不准确,因此需要引入新的模型与算法,去解决类似的较复杂的数据的分类和预测。
三、随机森林介绍
集成学习:ensemble learning
,对同一个数据集构建多个模型,集成所有模型的建模结果 。
集成算法的目标:考虑多个评估器的建模结果,汇总后得到一个综合结果,一依次获取比单个模型更理想的分类或回归表现。
多个模型集成的模型称为集成评估器(ensemble estimator),组成集成评估器的每个模型称为基评估器(base estimator)
1、集成算法主要类型包括:随机森林,梯度提升树(GBDT),Xgboost等
2、集成算法包括:装袋法Bagging,提升法Boosting和堆叠法Stacking
【1】装袋法的核心思想是构建多个相互独立的评估器,然后对其预测进行平均或多数表决原则来决定集成评估器的结果。
【2】提升法中,基评估器是相关的,是按顺序一一构建的。其核心思想是结合弱评估器的力量一次次对难以评估的样本进行预测,从而构成一个强评估器 。
【3】堆叠法。整合多个分类器,比如随机森林,线性回归,支持向量机等,每个分类器(弱分类器)通过K折交叉验证学习得到一个结果,第二个阶段拿另一个分类器对第一个阶段的进行再学习,训练和测试。
装袋法与提升法的区别?
通俗理解:有一道判断题,一群学习不好的人怎么去做能让题目的成功率比较高呢。
在这里就有两种方法:
第一种是序列集成方法 (提升法Boosting):
先让学渣A做一遍,然后再让学渣B做,且让B重点关注A做错的那些题,再让C做,同样重点关注B做错的,依次循环,直到所有的学渣都把题目做了一遍为止
第二种就是并行集成方法 (装袋法Bagging):
多个学渣一起做, 每个人随机挑选一部分题目来做,最后将所有人的结果进行汇总,然后根据将票多者作为最后的结果
装袋法的一个必要条件:
基分类器要尽量独立,所以,基评估器的判断准确率至少要超过随机分类器。因此基分类器的准确率要超过50%
# 假设有25颗树,i是判断错误的次数,也是判断错误的树的数量。Ω是判断错误的树的概率,1-Ω是正确的概率。共判断对25-i。采用comb是因为25颗树种,有任意i颗都可能判断错误。0.2是假设一棵树判断错误的可能性是0.2。 import numpy as np from scipy.special import comb np.array([comb(25,i)*(0.2**i)*((1-0.2)**(25-i)) for i in range(13,26)]).sum()
import numpy as np x=np.linspace(0,1,20) y=[] for epsilon in np.linspace(0,1,20): E=np.array([comb(25,i)*(epsilon**i)*((1-epsilon)**(25-i)) for i in range(13,26)]).sum() y.append(E) plt.plot(x,y,"o-",label="when estimators are different") plt.plot(x,x,"--",color="red",label="if all estimators are same") plt.xlabel("individual estimator's error") plt.ylabel("RandomForest's error" ) plt.legend() plt.show()
下图表明
当当单个分类器的错误小于50%的情况下,随机森林分类器的准确性会大于单个的分类器。
反之,当单个分类器的错误大于50%的情况下,随机森林的错误率就会高于单个分类器。
1、随机森林的分类
使用的参数是基尼系数:
sklearn.ensemble.RandomForestClassifier (n_estimators='10', criterion='gini', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, class_weight=None)
(1)导入我们需要的包,这里使用sklearn自带的红酒数据集
%matplotlib inline from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.datasets import load_wine
(2)导入需要的数据集
import pandas as pd import numpy as np wine = load_wine() wine.data wine.target
总共有三类红酒:
红酒特征:
(3)对数据进行分割 :
用train_test_split
函数划分出训练集和测试集,测试集占比0.3
from sklearn.model_selection import train_test_split Xtrain,Xtest,Ytrain,Ytest=train_test_split(wine.data,wine.target,test_size=0.3)
关于train_test_split的用法如下:
import numpy as np from sklearn.model_selection import train_test_split #创建一个数据集X和相应的标签y,X中样本数目为100 X, y = np.arange(200).reshape((100, 2)), range(100) #用train_test_split函数划分出训练集和测试集,测试集占比0.33 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.33, random_state=42) #打印出原始样本集、训练集和测试集的数目 print("The length of original data X is:", X.shape[0]) print("The length of train Data is:", X_train.shape[0]) print("The length of test Data is:", X_test.shape[0])
(4)绘制决策树与随机森林交叉验证后的效果对比
from sklearn.model_selection import cross_val_score import matplotlib.pyplot as plt rfc = RandomForestClassifier(n_estimators=25) # 随机森林 rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10) clf = DecisionTreeClassifier() # 决策树 clf_s = cross_val_score(clf,wine.data,wine.target,cv=10) plt.plot(range(1,11),rfc_s,label = "RandomForest") plt.plot(range(1,11),clf_s,label = "Decision Tree") plt.legend() plt.show()
从图上看出决策树总体的正确率在随机森林下面。随机森林效果更好。
rfc_l = [] clf_l = [] for i in range(10): rfc = RandomForestClassifier(n_estimators=25) rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean() rfc_l.append(rfc_s) clf = DecisionTreeClassifier() clf_s = cross_val_score(clf,wine.data,wine.target,cv=10).mean() clf_l.append(clf_s) plt.plot(range(1,11),rfc_l,label = "Random Forest") plt.plot(range(1,11),clf_l,label = "Decision Tree") plt.legend() plt.show()
通过修改随机森林当中n_estimators的个数来绘制学习曲线:
superpa = [] for i in range(200): rfc = RandomForestClassifier(n_estimators=i+1,n_jobs=-1) rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean() superpa.append(rfc_s) print(max(superpa),superpa.index(max(superpa))) plt.figure(figsize=[20,5]) plt.plot(range(1,201),superpa) plt.show()
2、重要参数
【1】n_estimators
n_estimators
:森林中树的数量,即基评估器的数量。越大则模型往往越好;但是也是有边界的。如果n_estimators=100,需要10次交叉验证,则需要1000颗树。 默认为10(低版本),新版本默认为100。
【2】random_state
random_state:随机森林每次的基评估器的结果是可能不同的。主要原因在于决策树自带的随机性参数。与决策树不同的是,随机森林生成的不是一棵树,而是一片树。如果random_state是固定的,则随机森林会生成一组固定的树,但是每棵树的细节部分还是不一致的。原因在于挑选的随机性。并且随机性越大,则装袋法的效果越好。如果总体样本特征不够,实际上就限制了随机森林的创建。因此需要其他的随机性参数。
查看第1次的random_state结果:
rfc =RandomForestClassifier(n_estimators=20,random_state=2) rfc = rfc.fit(Xtrain, Ytrain) #训练 rfc.estimators_[0]
for循环查看每一次random_state
的结果:
for i in range(len(rfc.estimators_)): print(rfc.estimators_[i].random_state)
【3】bootstrap
bootstrap:用来控制有放回的抽样技术参数。放回抽样有可能会导致一些样本多次出现,而另外一些则几乎被忽略。 放回数据集的敛财概率一般是:1-(1/e) 0.63,剩下37%的数据可能会被忽略而称为out of bag data,obb 可以被当做测试集数据。所以在随机森林中,有时不进行训练集和测试集的划分,而直接使用oob作为测试集。如果样本数和estimator本身不够大的情况,就不会oob。
在使用随机森林时,我们可以不划分测试集和训练集,只需要用袋外数据来测试我们的模型即可。 oob_score_来查看我们的在袋外数据上测试的结果:
#无需划分训练集和测试集 rfc = RandomForestClassifier(n_estimators=25,oob_score=True) rfc = rfc.fit(wine.data,wine.target) #重要属性oob_score_ rfc.oob_score_
不划分测试集和训练集,则需要使用参数oob_score=True
准确率如下:
3、重要的属性和接口
rfc=RandomForestClassifier(n_estimators=25) rfc=rfc.fit(Xtrain,Ytrain) rfc.score(Xtest,Ytest) rfc.feature_importances_
rfc.apply(Xtest) rfc.predict(Xtest) rfc.predict_proba(Xtest)
predict_proba
predict_proba返回每个测试样本对应的被分到每一类标签的概率。标签有几个分类就返回几个概率。如果是二分类,则该值大于0.5,则被分为1,否则为0。在sklearn下随机森林是平均每个样本对应的predict_proba返回的概率,得到一个平均概率,从而决定测试样本的分类。