决策树

决策树是广泛用于分类和回归任务的模型。

  • 它从一层层的if/else问题(尽可能少的问题)中进行学习,并得出结论

1、构造决策树

  • 1)two_moons数据集
    • 这是个二分类数据集(每个类别50个数据点),样本点在坐标图中的分布像两个半月牙,因此叫做two_moons

  • 2)学习决策树,就是学习一系列的if/else问题(这些问题被叫做测试),使得能够以最快速度得到正确答案
    • 测试的形式有
      • 二元特征(是/否):“是否有是翅膀?”
      • 连续数据的测试形式:“特征i的值是否大于a?”

  • 3)构造决策树,算法搜遍所有可能的测试,找出对目标变量来说信息量最大的那一个。
    • 信息量?熵增理论
    • 构造决策树就是不断地搜寻最优测试,在特征空间上能最大程度上对数据实现划分,直到划分后的每个区域(决策树的每个叶节点)只包含单一目标值
      • 如果书中的某个叶节点所包含数据点的目标值都相同,则该叶节点是纯的。(纯叶节点太多容易过拟合)

  • 4)对新数据点进行预测
    • 查看这个点位于特征空间划分的哪个区域,然后将该区域的多数目标值作为预测结果

2、控制决策树的复杂度

1)为什么要控制决策树的复杂度?

  • 防止过拟合。

  • 构造决策树直到所有叶结点都是纯的叶结点,这会导致模型非常复杂,并且对训练数据高度过拟合。

    • 纯叶结点的存在说明这棵树在训练集上的精度是 100%。有的决策边界过于关注远离同类别其他点的单个异常点。

2)防止过拟合有两种常见的策略:

  • 预剪枝(pre-pruning),及早停止树的生长

  • 后剪枝(post-pruning)或剪枝(pruning),先构造树,但随后删除或折叠信息量很少的结点

  • 剪枝条件:限制树的最大深度、叶节点的最大数目、规定一个节点中数据点的最小数目

  • scikit-learn 只实现了预剪枝,没有实现后剪枝。


3)scikit-learn 的决策树在 DecisionTreeRegressor 类和 DecisionTreeClassifier 类中实现。

  • DecisionTreeClassifier 类

    from sklearn.tree import DecisionTreeClassifier
    from sklearn.datasets import load_breast_cancer
    from sklearn.model_selection import train_test_split
    #加载数据
    cancer = load_breast_cancer()
    #分离数据,stratify作用为以分层方式分割数据,保持测试集与整个数据集里cancer.target的数据分类比例一致
    #随机数种子为42
    X_train, X_test, y_train, y_test = train_test_split(
        cancer.data, cancer.target, stratify=cancer.target, random_state=42)
    #调用函数
    tree = DecisionTreeClassifier(random_state=0)
    #训练模型
    tree.fit(X_train, y_train)
    print("Accuracy on training set: {:.3f}".format(tree.score(X_train, y_train)))
    print("Accuracy on test set: {:.3f}".format(tree.score(X_test, y_test)))
    
  • 输出

    Accuracy on training set: 1.000
    Accuracy on test set: 0.937
    
  • DecisionTreeRegressor 类

    price = load_boston()
    X1_train, X1_test, y1_train, y1_test = train_test_split(price.data,price.target,random_state = 42)
    DTR = DecisionTreeRegressor().fit(X1_train,y1_train)
    print("DTR taining score:{}".format(DTR.score(X1_train,y1_train)))
    print("DTR test score:{}".format(DTR.score(X1_test,y1_test)))
    
  • 输出

    DTR taining score:1.0
    DTR test score:0.8113048906750595
    
  • 📣

    • 训练集上的精度是 100%,
      • 这是因为叶结点都是纯的,树的深度很大,足以完美地记住训练数据的所有标签。
      • 如果我们不进行剪枝,树的深度和复杂度都可以变得特别大,容易过拟合,对新数据的泛化性能不佳。
    • 剪枝可以通过参数max_depth,max_features,max_leaf_nodes来实现比如,DTC = DecisionTreeClassifier(max_depth = 5)

3、分析决策树

在分析决策树前,需要安装一下grahviz,而且不能用pip直接安装,需要配置环境

  • 按照上网搜的教程:给小白准备的graphviz图文安装教程(2021最新)

  • 接着,我们就可以使用tree.export_graphviz将树可视化

    from sklearn.tree import export_graphviz
    import graphviz
    export_graphviz(DTR,out_file="DTR.dot",feature_names=price.feature_names,impurity=False,filled=True)
    with open("DTR.dot") as f:
        g = f.read()
    graphviz.Source(g)
    
  • 看看结果~

4、树的特征重要度

由上面的图片可以发现,查看整个树可能非常费劲,图太大啦...

  • 因此利用一些有用的属性来总结树的工作原理
    • 其中最常用的是特征重要性(feature importance),它为每个特征对树的决策的重要性进行排序。

      def plot_feature_importance_cancer(model):
      	#.shape[1]表示矩阵的第二维的长度,在这里就是特征的长度
          n_features = cancer.data.shape[1]
          plt.barh(range(n_features), model.feature_importances_, align='center')
          #前者代表y坐标轴的各个刻度,后者代表各个刻度位置的显示的lable
          plt.yticks(np.arange(n_features), cancer.feature_names)
          plt.xlabel("Feature importance")
          plt.ylabel("Feature")
          plt.show()
      

📣

从图中我们可以看到,特征worst radius是最重要的特征。

  • 即第一层划分已经将两个类别区分得很好。
    • 但是,如果某个特征的 feature_importance_ 很小,并不能说明这个特征没有提供任何信息。这只能说明该特征没有被树选中,可能是因为另一个特征也包含了同样的信息。
  • 与线性模型的系数不同,特征重要性始终为正数,也不能说明该特征对应哪个类别。
    • 特征重要性告诉我们“worst radius”(最大半径)特征很重要,但并没有告诉我们半径大表示样本是良性还是恶性。
    • 事实上,在特征和类别之间可能没有这样简单的关系。

5、优点、缺点和参数

  • 优点:一是得到的模型很容易可视化,非专家也很容易理解(至少对于较小的树而言);二是算法完全不受数据缩放的影响,不需要特征预处理。

  • 缺点:即使做了预剪枝,它也经常会过拟合,泛化性能很差。因此,在大多数应用中,往往使用下面介绍的集成方法来替代单棵决策树。

  • 参数:控制决策树模型复杂度的参数是预剪枝参数,它在树完全展开之前停止树的构造。通常来说,选择一种预剪枝策略(设置 max_depth 、 max_leaf_nodes 或 min_samples_leaf )足以防止过拟合。

6、参考文献

《Python机器学习基础教程》P54-P62

posted @ 2022-04-21 20:38  朝南烟  阅读(258)  评论(0编辑  收藏  举报
body { color: #000; background-color: #e6e6e6; font-family: "Helvetica Neue",Helvetica,Verdana,Arial,sans-serif; font-size: 12px; min-height: 101%; background: url(https://images.cnblogs.com/cnblogs_com/caolanying/1841633/o_2009041…ly1geq8oc9owbj21hc0u0th5.jpg) fixed; } #home { margin: 0 auto; opacity: 0.8; width: 65%; min-width: 1080px; background-color: #fff; padding: 30px; margin-top: 50px; margin-bottom: 50px; box-shadow: 0 2px 6px rgba(100, 100, 100, 0.3); }