决策树
概述
▒ 树模型
▨ 从根节点一步一步走到叶子节点 ( 决策 )html
▨ 全部数据都会落在叶子节点, 既能够作分类也能够作回归node
▒ 树的组成
▨ 根节点 - 第一个选择点git
▨ 非叶子节点与分支 - 中间过程算法
▨ 叶子节点 - 最终的决策结果windows
▒ 节点
▨ 节点至关于在数据中进行切一刀 ( 切分两部分 - 左右子树 )数组
▨ 节点越多越好吗? - dom
▒ 决策树的训练和测试
▨ 训练阶段 - 从给定的训练集构造一棵树 ( 从根节开始选择特征, 如何进行特征切分 )工具
▨ 测试阶段 - 根据构造出来的树模型从上到下走一遍gitlab
▨ 难点 - 测试阶段较为容易, 而训练阶段并不简单测试
▒ 如何切分特征 ( 选择节点 )
▨ 问题 - 一个数据集中可能存在多个特征的时候, 选择那个节点特征做为根节点进行分支, 以及其余特征分支的选择顺序都是问题
▨ 目标 - 须要经过一种衡量标准, 来计算不一样特征进行分支选择后的分类状况, 找出最好的那个当作根节点, 以此类推
决策树算法 - 信息增益
▒ 衡量标准 - 熵
▨ 熵 - 表示随机变量的不肯定性的度量 ( 简单来讲就是混乱程度 )
当 p = 0 或者 p = 1 的时候, H(p) = 0, 随机变量彻底没有不肯定性
当 p = 0.5 时, H(p) = 1 此时,随机变量的不肯定性最大
▨ 公式 -
▨ 栗子 - a = [1,1,1,2,1,2,1,1,1] , b = [1,5,6,7,5,1,6,9,8,4,5] a 的熵更底, 由于 a 的类别较少, 相对 b 就更稳定一些
▨ 信息增益 - 表示特征 X 使 Y 的不肯定性减小的程度 (分类后的专注性, 但愿分类后的结果同类在一块儿)
▒ 示例
▨ 数据 - 14 天打球状况
▨ 特征 - 4 种天气因素
▨目标 - 构建决策树
▨ 根节点选择
14天的记录中, 有 9 天打球, 5 天没打球, 熵为
演示 - outlook 特征 - 天气
suuny 的几率是 5/14 , 熵 是 0.971
overcast 的几率是 4/14 , 熵 是 0
rainy 的几率是 5/14 , 熵 是 0.971
熵值计算 : 5/14*0.971 + 4/14*0 + 5/14*0.971 = 0.693
信息增益 : 系统的 熵值从原始的 0.940 降低到了 0.693 , 增益为 0.247
以此类推动行处理, 选出根节点而后再从剩余的特征中选择次根节点往下到仅剩最后一个特征,
▒ 总结
▨ 弊端
如 id 这样的惟一标识特征列, 会让熵值计算为 0 被视为最大信息增益 ,
可是 id 仅仅是编号标识对信息的模型无任何影响实则无效项
▨ 解决
信息增益率 - 解决信息增益问题, 考虑自身熵
GINI 系数 - ( 和熵的衡量标准相似, 计算方式不一样 )
特殊处理
▒ 连续值处理
本质上就上 离散化
对序列遍历而后寻找离散点进行二分
▒ 剪枝策略
▨ 为毛
决策树拟合风险过大, 理论上能够彻底分开数据, 让每一个叶子节点都只有一个命中数据
训练集中的数据这样完美命中, 可是在测试集中可能会出现不适配等各类异常状况
▨ 策略
预剪枝 - 边简历决策树边进行剪枝操做 ( 更实用 )
后剪枝 - 当创建完决策树后进行剪枝操做
▨ 预剪枝
限制 深度, 叶子节点个数, 叶子节点样本数, 信息增益量等
▨ 后剪枝
经过必定的衡量标准 - 叶子越多, 损失 (C(T)) 越大
代码实现
▒ 模块引入
%matplotlib inline import matplotlib.pyplot as plt import pandas as pd
▒ 数据集准备
▨ 下载
数据集经过 sklearn 模块内置的 房价预测数据集
from sklearn.datasets.california_housing import fetch_california_housing housing = fetch_california_housing() print(housing.DESCR)
▨ 结构
▒ 模型生成
▨ 实例化模型
实例化树模型 , 指定最大深度, .fit 构造决策树, 传入参数分别表示 x 和 y 值
from sklearn import tree dtr = tree.DecisionTreeRegressor(max_depth = 2) dtr.fit(housing.data[:, [6, 7]], housing.target)
◈ criterion 评估标准 - gini / entropy
指定 gini 系数或者熵值做为评估标准
◈ splitter 特征选择 - best / random
前者是在全部特征中找最好的切分点 后者是在部分特征中(数据量大的时候) 通常都默认是 best
◈ max_features 特征数 - None / log2 / sqrt / n (数字)
特征小于50的时候 (通常使用全部 - None , 即默认)
◈ max_depth 最大深度 - n (数字)
数据少或者特征少的时候能够无论这个值,若是模型样本量多,特征也多的状况下,能够尝试限制下
◈ min_samples_split 最大叶子节点容量 - n (数字)
某节点的样本数少于此参数,则不继续再尝试选择最优特征来进行划分, 样本量不大时无需设置
更适用于大规模的数据集避免过拟合
◈ min_samples_leaf 最小叶子节点容量 - n (数字)
某叶子节点数目小于样本数,则会和兄弟节点一块儿被剪枝,样本量小无需此参数
◈ min_weight_fraction_leaf
限制了叶子节点全部样本权重和的最小值,若是小于这个值,则会和兄弟节点一块儿被剪枝默认是0
若是咱们有较多样本有缺失值,或者分类树样本的分布类别误差很大,就可引入样本权重
◈ max_leaf_nodes
经过限制最大叶子节点数,能够防止过拟合,默认是"None”,即不限制最大的叶子节点数。
若是加了限制,算法会创建在最大叶子节点数内最优的决策树
特征很少时不考虑此参数,可是若是特征分红多的话,能够加以限制具体的值能够经过交叉验证获得。
◈ class_weight
指定样本各种别的的权重,主要是为了防止训练集某些类别的样本过多致使训练的决策树过于偏向这些类别。
这里能够本身指定各个样本的权重若是使用“balanced”,则算法会本身计算权重,样本量少的类别所对应的样本权重会高。
◈ min_impurity_split
限制决策树的增加,若是某节点的不纯度(基尼系数,信息增益,均方差,绝对差)小于这个阈值则该节点再也不生成子节点。即为叶子节点 。
◈ n_estimators:
要创建树的个数
▒ 可视化处理
▨ 下载可视化工具 graphviz 下载地址
▨ 配置环境变量, 能够手动指定, 也能够代码实现
import os os.environ["PATH"] += os.pathsep + 'C:/Program Files (x86)/Graphviz2.38/bin/'
▨ 指定 配置参数, 其余几个参数就不须要改动了
dot_data = \ tree.export_graphviz( dtr, # 实例化的决策树 out_file = None, feature_names = housing.feature_names[6:8], # 要用到的特征 filled = True, impurity = False, rounded = True )
▨ 安装 dot 可视化工具模块 - pydotplus pip install pydotplus
▨ 可视化生成, 颜色能够随意改动, 其余不动就好了
import pydotplus graph = pydotplus.graph_from_dot_data(dot_data) graph.get_nodes()[7].set_fillcolor("#FFF2DD") from IPython.display import Image Image(graph.create_png())
▨ 视状况能够进行保存等操做, 保存为 png 格式更加清晰一些
graph.write_png("dtr_white_background.png")
▒ 测试数据集, 参数选择
▨ 切分数据集
train_test_split 的参数传入 x , y 以及 test_size 表示测试集比例大小, random_state 指定一个值做为seed标识方便用于往后方便复现,
from sklearn.model_selection import train_test_split data_train, data_test, target_train, target_test = \ train_test_split(housing.data, housing.target, test_size = 0.1, random_state = 42) dtr = tree.DecisionTreeRegressor(random_state = 42) dtr.fit(data_train, target_train) dtr.score(data_test, target_test) # 0.637355881715626
▨ 选择参数
参数的选择是没法一上来就能够肯定最优参数的, 并且参数比较多, 怎么选择组合就是个问题了
所以须要进行必定程度的组合, 本质上就是参数集之间的交叉组合的遍历比对, GridSearchCV 的原理就是于此进行的封装
传入参数, 算法 ( 算法实例 ) , 参数候选项 ( 可字典形式 ), 交叉验证次数 ( cv , 切分段数 )
from sklearn.ensemble import RandomForestRegressor rfr = RandomForestRegressor(random_state = 42) rfr.fit(data_train, target_train) rfr.score(data_test, target_test) # 0.7910601348350835
from sklearn.model_selection import GridSearchCV tree_param_grid = { 'min_samples_split': list((3,6,9)),'n_estimators':list((10,50,100))} grid = GridSearchCV(RandomForestRegressor(),param_grid=tree_param_grid, cv=5) grid.fit(data_train, target_train) grid.cv_results_, grid.best_params_, grid.best_score_
比对结果, 测试得出 3, 100 为这组参数的最佳组合, 实际中会有更多的参数,这里仅仅选取了两组参数组进行比对
({'mean_fit_time': array([0.86073136, 4.28014984, 8.4557868 , 0.78763537, 3.94817624, 7.93624506, 0.75090647, 3.77697754, 7.65297484]), 'std_fit_time': array([0.05199331, 0.05060905, 0.08284658, 0.02222307, 0.04220675, 0.11099333, 0.0248957 , 0.05866979, 0.12467865]), 'mean_score_time': array([0.01007967, 0.05109978, 0.09502277, 0.00928087, 0.03622227, 0.07206926, 0.00758247, 0.03662882, 0.07186236]), 'std_score_time': array([0.00038016, 0.00981283, 0.011958 , 0.00261602, 0.00086917, 0.00067269, 0.00037106, 0.0076475 , 0.01476559]), 'param_min_samples_split': masked_array(data=[3, 3, 3, 6, 6, 6, 9, 9, 9], mask=[False, False, False, False, False, False, False, False, False], fill_value='?', dtype=object), 'param_n_estimators': masked_array(data=[10, 50, 100, 10, 50, 100, 10, 50, 100], mask=[False, False, False, False, False, False, False, False, False], fill_value='?', dtype=object), 'params': [{'min_samples_split': 3, 'n_estimators': 10}, {'min_samples_split': 3, 'n_estimators': 50}, {'min_samples_split': 3, 'n_estimators': 100}, {'min_samples_split': 6, 'n_estimators': 10}, {'min_samples_split': 6, 'n_estimators': 50}, {'min_samples_split': 6, 'n_estimators': 100}, {'min_samples_split': 9, 'n_estimators': 10}, {'min_samples_split': 9, 'n_estimators': 50}, {'min_samples_split': 9, 'n_estimators': 100}], 'split0_test_score': array([0.78845443, 0.81237387, 0.81156962, 0.79533209, 0.80854898, 0.80978258, 0.78914336, 0.80923727, 0.80858502]), 'split1_test_score': array([0.77014582, 0.79941449, 0.80094417, 0.78184821, 0.79978092, 0.79862554, 0.78052651, 0.7982624 , 0.79905119]), 'split2_test_score': array([0.78529369, 0.79965572, 0.80365713, 0.79374636, 0.80051057, 0.80568461, 0.78434117, 0.80059003, 0.80257161]), 'split3_test_score': array([0.79563203, 0.8098409 , 0.80998308, 0.79636012, 0.80891923, 0.8114358 , 0.79592629, 0.80754011, 0.81196788]), 'split4_test_score': array([0.781435 , 0.80752598, 0.8088186 , 0.78937079, 0.80655187, 0.80661464, 0.79724106, 0.80598448, 0.80706041]), 'mean_test_score': array([0.78419242, 0.80576255, 0.80699476, 0.79133173, 0.80486251, 0.80642881, 0.78943566, 0.80432312, 0.80584737]), 'std_test_score': array([0.00842779, 0.00531127, 0.00402334, 0.00530843, 0.00394113, 0.00442255, 0.00645683, 0.00419352, 0.00454625]), 'rank_test_score': array([9, 4, 1, 7, 5, 2, 8, 6, 3])}, {'min_samples_split': 3, 'n_estimators': 100}, 0.8069947626655254)