谷歌、百度或许搜到了很多关于决策树的文章(回归又可以分类的)。好吧,不喜欢看那些公式的朋友请看这里:
这就是一个决策树,一颗可以根据策略将数据集分成类别的树。。。。。。(这个解释是low点哈)
附上一个简单实例的代码实现:
from sklearn.datasets import load_iris,load_breast_cancer
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
import pydotplus
iris = load_iris( )
clf = DecisionTreeClassifier( )
clf_iris = clf.fit(iris.data,iris.target)
dot_Data = export_graphviz(clf_iris,out_file=None)
graph_iris = pydotplus.graph_from_dot_data(dot_Data)
graph_iris.write_pdf("./load_iris.pdf")
结果如下:
决策树比较官方的解释是:决策树是广泛用于分类和回归任务的模型。本质上,它从一层层的if/else问题中进行学习,并得出结论。决策树有两个优点:一是得到的模型很容易可视化,非专家也很容易理解(至少对于较小的树而言)。二是算法完全不受数据缩放的影响。由于每个特征被单独处理,而且数据的划分也不依赖于缩放,因此决策树算法不需要特征预处理,比如归一化或标准化。特别是特征的尺度完全不一样时或者二元特征和连续特征同时存在时,决策树的效果很好。决策树的主要缺点在于,即使做了预剪枝,它也经常会过拟合,泛化性能很差。因此,在大多数应用中,往往使用集成方法来替代单棵决策树。下面解释过拟合和预剪枝。
过拟合:通俗的理解就是生成的决策树(模型)对训练数据集的依赖性很高,当这样一个完全针对某一训练集而生成的模型面对训练数据时的准确度是完全可以达到100%的,但是如果面对其他测试集可能错误率也会很高,比如下图:
上面的模型确实可以非常完美的将圆形和三角形完全的分开(模型其实就是那些直线),但是这种模型很显然是对训练数据依赖性很高的。再看另外一幅图片。
很显然这个模型并没有把所有的数据完美的区分开,但是对于其它测试数据而言,错误率可能要比第一个模型要小很多了,也就是说第二个模型泛化能力更好。
那么我们怎们能更好的让模型的泛化能力更强呢?答案是预剪枝。预剪枝的限制条件可能包括限制树的最大深度、限制叶结点的最大数目, 或者规定一个结点中数据点的最小数目来防止继续划分等,这些在DecisionTreeClassifier的参数中就可以选择。下面就是介绍DecisionTreeClassifier参数喽~
在sklearn的官网中有给出,如下:
class sklearn.tree.DecisionTreeClassifier(criterion='gini', splitter='best', max_depth=None, min_samples_split=2,min_samples_leaf =1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None,class_weight=None, presort=False)
特征选择标准criterion:string类型,可以使用"gini"或者"entropy",前者代表基尼系数,后者代表信息增益。一般说使用默认的基尼系数"gini"就可以了,即CART算法。除非你更喜欢类似ID3, C4.5的最优特征选择方法。
特征划分点选择标准splitter:string类型,可以使用"best"或者"random"。前者在特征的所有划分点中找出最优的划分点。后者是随机的在部分划分点中找局部最优的划分点。默认的"best"适合样本量不大的时候,而如果样本数据量非常大,此时决策树构建推荐"random"
划分时考虑的最大特征数max_features:int,float,string or None。可以使用很多种类型的值,默认是"None"意味着划分时考虑所有的特征数;如果是"log2"意味着划分时最多考虑log2N个特征;如果是"sqrt"或者"auto"意味着划分时最多考虑N^(1/2)个特征。如果是整数,代表考虑的特征绝对数。如果是浮点数,代表考虑特征百分比,即考虑(百分比xN)取整后的特征数。其中N为样本总特征数。一般来说,如果样本特征数不多,比如小于50,我们用默认的"None"就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
1.如果是int,在每次分类是都要考虑max_features个特征。
2.如果是float,那么max_features是一个百分率并且分类时需要考虑的特征数是int(max_features*n_features,其中n_features是训练完成时发特征数)。
3.如果是auto,max_features=auto(n_features)
4.如果是sqrt,max_features=sqrt(n_features)
5.如果是log2,max_features=log2(n_features)
6.如果是None,max_features=n_features
决策树最大深max_depth:int or None。决策树的最大深度,默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值50-100之间。
内部节点再划分所需最小样本数min_samples_spli:int,float。这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分。 默认是2.如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。我之前的一个项目例子,有大概10万样本,建立决策树时,可以选择min_samples_split=10。
叶子节点最少样本数min_samples_leaf:int,float。这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是1,可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。之前的10万样本项目使用min_samples_leaf的值为5。
叶子节点最小的样本权重和min_weight_fraction_lea:float。这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。 默认是0,就是不考虑权重问题。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值。
最大叶子节点数max_leaf_nodes:int,None。通过限制最大叶子节点数,可以防止过拟合,默认是"None”,即不限制最大的叶子节点数。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。
类别权重class_weight:dict,list of dicts,"Banlanced" or None。指定样本各类别的的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策树过于偏向这些类别。这里可以自己指定各个样本的权重,或者用“balanced”,如果使用“balanced”,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认的"None"
节点划分最小不纯度min_impurity_split:这个值限制了决策树的增长,如果某节点的不纯度(基尼系数,信息增益,均方差,绝对差)小于这个阈值,则该节点不再生成子节点,即为叶子节点 。
数据是否预排序presort:这个值是布尔值,默认是False不排序。一般来说,如果样本量少或者限制了一个深度很小的决策树,设置为true可以让划分点选择更加快,决策树建立的更加快。如果样本量太大的话,反而没有什么好处。问题是样本量少的时候,我速度本来就不慢。所以这个值不处理就可以了。
除了这些参数要注意以外,其他在调参时的注意点有:
1)当样本少数量但是样本特征非常多的时候,决策树很容易过拟合,一般来说,样本数比特征数多一些会比较容易建立健壮的模型
2)如果样本数量少但是样本特征非常多,在拟合决策树模型前,推荐先做维度规约,比如主成分分析(PCA),特征选择(Losso)或者独立成分分析(ICA)。这样特征的维度会大大减小。再来拟合决策树模型效果会好。
3)推荐多用决策树的可视化,同时先限制决策树的深度,这样可以先观察下生成的决策树里数据的初步拟合情况,然后再决定是否要增加深度。
4)在训练模型先,注意观察样本的类别情况(主要指分类树),如果类别分布非常不均匀,就要考虑用class_weight来限制模型过于偏向样本多的类别。
5)决策树的数组使用的是numpy的float32类型,如果训练数据不是这样的格式,算法会先做copy再运行。
6)如果输入的样本矩阵是稀疏的,推荐在拟合前调用csc_matrix稀疏化,在预测前调用csr_matrix稀疏化。
下面以乳腺癌数据集写一个简单的实例并每个特征的重要程度以及模型打印成pdf:
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris,load_breast_cancer
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
import numpy as np
import matplotlib.pyplot as plt
import pydotplus
import graphviz
iris = load_iris()
cancer = load_breast_cancer()
clf = DecisionTreeClassifier(max_depth=7)
clf_iris = clf.fit(iris.data,iris.target)
clf_cancer = clf.fit(cancer.data,cancer.target)
#print("cancer.keys(): \n{}".format(cancer.keys()))
#print(cancer.target)
#print("{}".format({n:v for n,v in zip(cancer.target_names,np.bincount(cancer.target))}))
x_train,x_test,y_train,y_test = train_test_split(cancer.data,cancer.target,test_size=0.3,random_state=1)
clf_DT = clf.fit(x_train,y_train)
print("{:.3f}".format(clf_DT.score(x_train,y_train)))
print("{:.3f}".format(clf_DT.score(x_test,y_test)))
export_graphviz(clf_DT,out_file="./DT.dot",class_names=['malignant','benign'],feature_names=cancer.feature_names,impurity=False,filled=True)
print("{}".format(clf_DT.feature_importances_))
print(cancer.data.shape[0])
def polt_feature_importances_cancer(model):
feature_count = cancer.data.shape[1]
plt.barh(range(feature_count),model.feature_importances_,align='center')
plt.yticks(np.arange(feature_count),cancer.feature_names)
plt.xlabel("Feature importance")
plt.ylabel("Feature")
plt.show()
polt_feature_importances_cancer(clf_DT)
结果如下:
可以看出来第22个特征worst perimeter的划分能力最强,模型中第一个用到的也是x[22]。