什么是决策树
决策树属于经典的十大数据挖掘算法之一,是通过类似于流程图的数形结构,其规则就是iIF…THEN…的思想.,可以用于数值型因变量的预测或离散型因变量的分类,该算法简单直观,通俗易懂,不需要研究者掌握任何领域的知识或者复杂的数学逻辑,而且算法的输出结果具有很强的解释性,通常情况下决策术用作分类器会有很好的预测准确率,目前越来越多的行业,将此算法用于实际问题的解决。
决策树组成
这就是一个典型的决策树,其呈现字顶向下生长的过程,通过树形结构可以将数据中的隐藏的规律,直观的表现出来,图中深色的椭圆表示树的根节点检测的为椭圆表示树的中间节点,方框表示数的叶子节点,对于所有非叶子节点来说都是用于条件判断,叶节点则表示最终储存的分类结果。
- 根节点:没有进边,有出边。包含最初的,针对特征的提问。
- 中间节点:既有进边也有出边,进边只有一条,出边可以有很多条。都是针对特征的提问。
- 叶子节点:有进边,没有出边,每个叶子节点都是一个类别标签。
- 子节点和父节点:在两个相连的节点中,更接近根节点的是父节点,另一个是子节点。
节点的确定方法
那么对于所有的非叶子节点的字段的选择,可以直接决定我们分类结果的好和坏,那么如何使这些非叶子节点分类使结果更好和效率更高,也就是我们所说的纯净度,对于纯净度的衡量,我们有三个衡量指标信息增益,信息增益率和基尼系数。
-
对于信息增益来说,就是在我们分类的过程中,会对每一种分类条件的结果都会进行信息增益量的的计算。然后通过信息增益的比较取出最大的信息增益对应的分类条件。也就是说对于信息增益值最大的量就是我们寻找的最佳分类条件。关于信息增益值是怎么计算得出的,这里就不做过多的讲解,因为它需要基于大量的数学计算和概率知识。)输入”entropy“,使用信息熵(Entropy) -
在计算信息增益的过程中,可能会受到数据集类别效果不同的值过多,所以会造成信息增益的计算结果将会更大,但是有时候并不能够真正体现我们数据集的分类效果,所以这里引入信息增益率来对于信息增益值进行一定程度的惩罚,简单的理解就是将信息增益值除以信息量。 -
决策树中的信息增益率和信息增益指标实现根节点和中间节点的选择,只能针对离散型随机变量进行分类,对于连续性的因变量就束手无策,为了能够让决策数预测连续性的因变量,所以就引入了基尼系数指标进行字段选择特征。输入”gini“,使用基尼系数(Gini Impurity)
比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是在实际使用中,信息熵和基尼系数的效果基本相同。信息熵的计算比基尼系数缓慢一些,因为基尼系数的计算不涉及对数。另外,因为信息熵对不纯度更加敏感,所以信息熵作为指标时,决策树的生长会更加“精细”,因此对于高维数据或者噪音很多的数据,信息熵很容易过拟合,基尼系数在这种情况下效果往往比较好。
决策树基本流程
他会循环次过程,直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长。但是在建模的过程中可能会由于这种高精度的训练,使得模型在训练基础上有很高的预测精度,但是在测试集上效果并不够理想,为了解决过拟合的问题,通常会对于决策树进行剪枝操作。 对于决策树的剪枝操作有三种:误差降低剪枝法,悲观剪枝法,代价复杂度剪枝法,但是在这里我们只涉及sklearn中,给我们提供的限制决策树生长的参数。
决策树的常用参数
DecisionTreeClassifier(criterion="gini"
,random_state=None
,splitter="best"
,max_depth=None
,min_samples_leaf=1
,min_samples_split=2
,max_features=None
,min_impurity_decrease=0
,class_weight=None
)
代码实现决策树之分类树
import pandas as pd
from sklearn import tree
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_wine
import graphviz
wine=load_wine()
datatarget=pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1)
xtrain,xtest,ytrain,ytest=train_test_split(wine.data
,wine.target
,test_size=0.3
)
clf=tree.DecisionTreeClassifier(criterion="gini")
clf=clf.fit(xtrain,ytrain)
clf.score(xtest,ytest)
cross_val_score(clf
,wine.data
,wine.target
,cv=10
).mean()
dot=tree.export_graphviz(clf
,filled=True
,rounded=True)
graph=graphviz.Source(dot)
clf.feature_importances_
clf.apply(Xtest)
clf.predict(Xtest)
决策树不同max_depth的学习曲线
from sklearn import tree
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_wine
import matplotlib.pyplot as plt、
wine=load_wine()
xtrain,xtest,ytrain,ytest=train_test_split(wine.data,wine.target,test_size=0.3)
trainscore=[]
testscore=[]
for i in range(10):
clf=tree.DecisionTreeClassifier(criterion="gini"
,random_state=0
,max_depth=i+1
,min_samples_split=5
,max_features=5
).fit(xtrain,ytrain)
once1=clf.score(xtrain,ytrain)
once2=cross_val_score(clf,wine.data,wine.target,cv=10).mean()
trainscore.append(once1)
testscore.append(once2)
plt.plot(range(1,11),trainscore,color="red",label="train")
plt.plot(range(1,11),testscore,color="blue",label="test")
plt.xticks(range(1,11))
plt.legend()
plt.show()
result: 一般情况下,随着max_depth的升高训练集和测试集得分就相对越高,但是由于红酒数据集的数据量比较少,并没有特别明显的体现出来。但是我们依旧可以看出:在最大深度为4的时候到达了测试级的效果巅峰。
网格搜索在分类树上的应用
我们发现对于这个模型的参数比较多,如果我们想要得到一个相对来说分数比较高的效果比较好的模型的话,我们需要对于每一个参数都要进行不断的循环遍历,最后才能够得出最佳答案。但是这对于我们人为的实现来说比较困难,所以我们有了这样一个工具:网格搜索可以自动实现最佳效果的各种参数的确定。(但是比较费时间)
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_wine
from sklearn.model_selection import GridSearchCV
wine = load_wine()
xtrain, xtest, ytrain, ytest = train_test_split(wine.data, wine.target, test_size=0.3)
clf = DecisionTreeClassifier(random_state=0)
parameters = {"criterion": ["gini", "entropy"]
, "splitter": ["best", "random"]
, "max_depth": [*range(1, 10)]
}
GS = GridSearchCV(clf, cv=10, param_grid=parameters)
gs = GS.fit(xtrain, ytrain)
best_choice = gs.best_params_
print(best_choice)
best_score = gs.best_score_
print(best_score)
回归树中不同max_depth拟合正弦函数数据
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
rng = np.random.RandomState(0)
X = np.sort(5 * rng.rand(80, 1), axis=0)
y = np.sin(X).ravel()
y[::5] += 3 * (0.5 - rng.rand(16))
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)
plt.figure()
plt.scatter(X, y, s=20, edgecolor="black",
c="red", label="data")
plt.plot(X_test, y_1, color="blue",
label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="green", label="max_depth=5", linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()
结果: 从图像可以看出对于不同深度的节点来说,有优点和缺点。对于max_depth=5的时候,一般情况下很贴近原数据结果,但是对于一些特殊的噪声来说,也会非常贴近噪声,所以在个别的点的地方会和真实数据相差比较大,也就是过拟合现象(对于训练数据集能够很好地判断出出,但是对于测试数据集来说结果并不理想)。对于max_depth=2的时候,虽然不能够特别贴近大量的数据集,但是在处理一些噪声的时候,往往能够很好的避免。
分类树在合成数据的表现
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
X, y = make_classification(n_samples=100,
n_features=2,
n_redundant=0,
n_informative=2,
random_state=1,
n_clusters_per_class=1
)
rng = np.random.RandomState(2)
X += 2 * rng.uniform(size=X.shape)
linearly_separable = (X, y)
moons=make_moons(noise=0.3, random_state=0)
circles=make_circles(noise=0.2, factor=0.5, random_state=1)
datasets = [moons,circles,linearly_separable]
figure = plt.figure(figsize=(6, 9))
i=1
for ds_index, ds in enumerate(datasets):
X, y = ds
X = StandardScaler().fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.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
array1,array2 = np.meshgrid(np.arange(x1_min, x1_max, 0.2), np.arange(x2_min, x2_max, 0.2))
cm_bright = ListedColormap(['#FF0000', '#0000FF'])
ax = plt.subplot(len(datasets), 2, i)
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.4, 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).fit(X_train, y_train)
score = clf.score(X_test, y_test)
Z = clf.predict(np.c_[array1.ravel(), array2.ravel()])
Z = Z.reshape(array1.shape)
cm = plt.cm.RdBu
ax.contourf(array1
, array2
, Z
, cmap=cm
, alpha=0.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.4)
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()
从这里可以看出决策树,对于月亮型数据和二分类数据有比较好的分类效果,但是对于环形的数据的分类效果就不是那么理想。
什么是随机森林
随机森林属于集成算法,森林从字面理解就是由多颗决策树构成的集合,而且这些子树都是经过充分生长的CART树,随机则表示构成多颗随机树是随机生成的,生成过程采用的是bossstrap抽样法,该算法有两大优点,一是运行速度快,二是预测准确率高,被称为最好用的算法之一。
随机森林的原理
该算法的核心思想就是采用多棵决策树的投票机制,完成分类或预测问题的解决。对于分类的问题,将多个数的判断结果用做投票,根据根据少数服从多数的原则,最终确定样本所属的类型,对于预测性的问题,将多棵树的回归结果进行平均,最终确定样本的预测。
将随机森林的建模过程,形象地描绘出来就是这样: 流程:
- 利用booststrap抽样法,从原始数据集中生成K个数据集,并且每一个数据集都含有N个观测和P个自变量。
- 针对每一个数据集构造一个CART决策树,在构造数的过程中,并没有将所有自变量用作节点字段的选择而是随机选择P个字段(特征)
- 让每一颗决策树尽可能的充分生长,使得树中的每一个节点,尽可能的纯净,即随机森林中的每一颗子树都不需要剪枝。
- 针对K个CART树的随机森林,对于分类问题利用投票法将最高的的票的类别用于最后判断结果,对于回归问题利用均值法,将其作为预测样本的最终结果。
随机森林常用参数
用分类的随机森林举例
RandomForestClassifier(n_estimators=10
,criterion="gini"
,max_depth=None
,min_samples_split=2
,min_samples_leaf=1
,max_features="auto"
,bootstrap=True
,oob_score=False
,random_state=None
,calss_weight
)
注:一般n_estimators越大,模型的效果往往越好。但是相应的,任何模型都有决策边界
n_estimators达到一定的程度之后,随机森林的精确性往往不在上升或开始波动
并且n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越长
随机森林应用示例
from sklearn.datasets import load_wine
from sklearn.ensemble import RandomForestClassifier
wine=load_wine()
xtrain,xtest,ytrain,ytest=train_test_split(wine.data ,wine.target,test_size=0.3)
rfc=RandomForestClassifier(random_state=0
,n_estimators=10
,bootstrap=True
,oob_score=True
).fit(xtrain,ytrain)
rfc.score(xtest,ytest)
rfc.oob_score_
rfc.predict_proba(wine.data)
rfc.estimators_
rfc.estimators_[1].random_state
参数n_estimators对随机森林的影响
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
from sklearn.datasets import load_wine
from sklearn.ensemble import RandomForestClassifier
wine=load_wine()
score=[]
for i in range(100):
rfc=RandomForestClassifier(random_state=0
,n_estimators=i+1
,bootstrap=True
,oob_score=False
)
once=cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
score.append(once)
plt.plot(range(1,101),score)
plt.xlabel("n_estimators")
plt.show()
print("best srore = ",max(score),"\nbest n_estimators = ",score.index(max(score))+1)
输出:
best srore = 0.9833333333333334
best n_estimators = 12
决策树和随机森林效果
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
from sklearn.datasets import load_wine
from sklearn.ensemble import RandomForestClassifier
wine=load_wine()
score1=[]
score2=[]
for i in range(10):
rfc=RandomForestClassifier(n_estimators=12)
once1=cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
score1.append(once1)
clf=DecisionTreeClassifier()
once2=cross_val_score(clf,wine.data,wine.target,cv=10).mean()
score2.append(once2)
plt.plot(range(1,11),score1,label="Forest")
plt.plot(range(1,11),score2,label="singe tree")
plt.legend()
plt.show()
从图像中可以直观的看出:多个决策树组成的随机森林集成算法的模型效果要明显优于单个决策树的效果。
实例用随机森林对乳腺癌数据的调参
n_estimators
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
cancer = load_breast_cancer()
scores=[]
for i in range(1,201,10):
rfc = RandomForestClassifier(n_estimators=i, random_state=0).fit(cancer.data,cancer.target)
score = cross_val_score(rfc,cancer.data,cancer.target,cv=10).mean()
scores.append(score)
print(max(scores),(scores.index(max(scores))*10)+1)
plt.figure(figsize=[20,5])
plt.plot(range(1,201,10),scores)
plt.show()
0.9649122807017545 111
max_depth
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
cancer = load_breast_cancer()
scores=[]
for i in range(1,20,2):
rfc = RandomForestClassifier(n_estimators=111,max_depth=i, random_state=0)
score = cross_val_score(rfc,cancer.data,cancer.target,cv=10).mean()
scores.append(score)
print(max(scores),(scores.index(max(scores))*2)+1)
plt.figure(figsize=[20,5])
plt.plot(range(1,20,2),scores)
plt.show()
0.9649122807017545 11
gini改为entropy
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
cancer = load_breast_cancer()
scores=[]
for i in range(1,20,2):
rfc = RandomForestClassifier(n_estimators=111,criterion="entropy",max_depth=i, random_state=0)
score = cross_val_score(rfc,cancer.data,cancer.target,cv=10).mean()
scores.append(score)
print(max(scores),(scores.index(max(scores))*2)+1)
plt.figure(figsize=[20,5])
plt.plot(range(1,20,2),scores)
plt.show()
0.9666666666666666 7
gini和entropy结果图片:
|