决策树

作者: 似海深蓝 | 来源:发表于2020-04-29 19:08 被阅读0次

    1. sklearn 实现决策树

    1.1 语法与参数

    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, min_impurity_decrease=0.0, min_impurity_split=None, class_weight=None, presort='deprecated', ccp_alpha=0.0)
    参数说明:

    
    - criterion: 不纯度计算指标 {“gini”, “entropy”},
    
    - splitter: {“best”, “random”}, default=”best” 节点切分方法,默认是选择最优特征进行切分.
    
    - max_depth: 树能达到的最大深度,防止模型太深,控制模型复杂度
    
    - min_samples_split: int or float, default=2  抑制模型分裂
    
        一个节点想要向下进行切分,当前样本个数必须要大于这个参数值.
        例如设置为10,当这个节点中如果有9个样本,则这个节点只能作为叶节点.
    
    - min_samples_leaf:  int or float, default=1  抑制模型分裂
    
        最小叶节点样本个数,如果上层节点分裂之后,分裂出来后的叶节点当中样本个数不足这儿参数值,则本次分裂不能进行.
    
    - max_features : int, float or {“auto”, “sqrt”, “log2”}, default=None
    
        最大特征,在寻找最优分裂点的时候,要考虑的特征个数
    
        If int, 考虑特征个数,举例有100个特征, 填写20,就是每次分裂的时候,只计算20个特征.
    
        If float, 百分比 0-1的浮点数. 100个特征, 填写0.3,那就是计算30个特征.
    
        If “auto”, then max_features=sqrt(n_features). 根号个特征.100个特征就是计算10个特征
    
        If “sqrt”, then max_features=sqrt(n_features). 同上
    
        If “log2”, then max_features=log2(n_features). 计算log2个特征,64个特征,6个.
    
        If None, then max_features=n_features. 所有特征
        
    
    - random_state: 随机数种子
    
    - max_leaf_nodes:  抑制模型分裂,最大叶节点个数,最多能够分裂出多少个叶节点. 
    
    - min_impurity_decrease: 分裂中的最小不纯度下降的值. 
    
        如果一次分裂过程中,Gain的下降不能超过这个值,那么就不能进行本次分裂. 
    
    - class_weight: 类别权重设置,(类别不均衡数据集的问题)
    

    属性:

    
    - classes_ : 分类标签,没用
    
    - feature_importances_: 特征重要性.
    

    方法:

    - get_depth(self) : 树的深度
    
    - get_n_leaves(self): 叶节点的个数
    
    
    

    2. 泰坦尼克数据集应用决策树

    导包 --> 导入数据 --> 数据探索 --> 数据预处理 --> 切分X,y --> 构建模型 --> 评价

    2.1 读入数据

    import pandas as pd
    import numpy as np
    import matplotlib.pylab as plt
    
    train = pd.read_csv('titanic/train.csv')
    test = pd.read_csv('titanic/test.csv')
    answer = pd.read_csv('titanic/gender_submission.csv')
    
    • PassengerId: 乘客ID,没用
    • Pclass: 票等级
    • Name: 姓名,没用
    • Sex: 性别
    • Age: 年龄
    • SibSp: 乘客同在船上的兄弟姐妹/配偶的个数(整数值)
    • Parch:乘客同在船上的乘客父母/孩子的个数(整数值)
    • Ticket:票号(字符串) 没用
    • Fare:乘客所持票的价格(浮点数,0-500不等)
    • Cabin:乘客所在船舱(有缺失)
    • Embark:乘客登船港口:S、C、Q(有缺失)


      train数据

    2.2 数据探索

    # 各个客舱人数
    train['Pclass'].value_counts()
    
    各客舱人数
    # 各类票价均值
    train.groupby(by = 'Pclass').mean()['Fare']
    
    各类票价均值
    # 性别比例
    train['Sex'].value_counts()
    
    plt.style.use('seaborn') # 改变绘图风格
    # Series里面有封装自带的画图功能
    train.Sex.value_counts().plot(kind='barh')
    
    性别比例
    # 男女获救比例
    train.groupby('Sex').mean()
    
    男女获救比例
    # 年龄分布
    train['Age'].plot(kind = 'hist')
    
    # 将年龄离散化然后看获救比例(10岁一级)
    age_cut = pd.cut(train['Age'],bins = [0,10,20,30,40,50,60,70,80])
    train['age_cut'] = age_cut
    
    # 存活下来的Survived标签都是1,所以直接分类累加聚合就是比例,0累加还是0
    print("平均生存率: {:.3f}\n".format(train['Survived'].mean()))
    print("各仓位等级存活率:\n{}\n".format(train.groupby(by = 'Pclass')['Survived'].mean()))
    print("各年龄段生存率如下: \n{}".format(train.groupby(by = 'age_cut').mean()['Survived']))
    
    存活率
    # 构造函数,查看所有特征与生存率
    def survive(feature):
        #return train.groupby(by=feature).mean()['Survived']
        Survived = train.groupby(by = feature)['Survived'].mean()
        print(feature + "存活率:\n{}".format(Survived))
        Survived.plot(kind = 'pie')
        plt.show()
        print('-'*40)
    
    for i in ['Pclass','Sex','SibSp','Parch','Embarked']:
        survive(i)
    
    函数得到的存活率

    2.3 数据预处理

    1. 删除无效特征

    2. 填充空值

    3. 特征编码

    2.3.1 删除无效特征

    # inplace  = True 直接在原表改,省去赋值
    train.drop(columns=['PassengerId','Name','Cabin','Ticket'],inplace=True)
    train.pop('age_cut') # 直接删
    
    test.drop(columns=['PassengerId','Name','Cabin','Ticket'],inplace=True)
    

    2.3.2 填充空值

    train.info()
    
    数据总览
    # 将年龄空值填充中位数
    train.Age.fillna(train.Age.median(),inplace=True)
    
    # 登录港口空值填充众数
    train.Embarked.fillna('S',inplace=True)
    
    # 测试集填充,测试集也用训练集数据填充,参考KNN归一化
    test.Age.fillna(28,inplace=True)
    test.Embarked.fillna('S',inplace=True)
    

    2.3.3 特征编码

    # 对性别进行编码 0:男 1:女
    train['Sex'] = (train.Sex == 'female').astype('int')
    
    # 对仓位进行编码
    train['Embarked'] = train.Embarked.map({'S':0,'C':1,'Q':2})
    
    test['Sex'] = (test.Sex == 'female').astype('int')
    
    # 对仓位进行编码
    test['Embarked'] = test.Embarked.map({'S':0,'C':1,'Q':2})
    
    test.Fare.fillna(train.Fare.mean(),inplace=True)
    

    2.4 拆分X,y

    train_y = train.pop('Survived')
    train_X = train.copy() #拷贝
    
    test_X = test.copy()# 提取X
    test_y = submission.Survived #提取y
    
    train_X

    2.5 决策树建模

    导包 --> 实例化 --> fit --> 评估
    from sklearn.tree import DecisionTreeClassifier
    
    dtc = DecisionTreeClassifier(random_state = 666)
    dtc.fit(train_X,train_y)
    dtc.score(train_X,train_y)  # 训练精度 0.9797
    dtc.score(test_X,test_y) # 测试精度 0.8086 过拟合了
    

    3. 过拟合

    上边的结果明显过拟合:训练集的准确率,远远高于测试集的准确率

    • 拟合: 模型对数据的学习过程,模型去适配数据

    • 噪声: 代表了我们数据中存在的一些和普适性的规律不一样的信息.

    数据信息两类(规律, 噪声):举例: 大部分年龄大的男性都死亡了,但是有几个活下来了,这几个就不符合常规的规律,就是数据集中的异常数据,或者说是噪声.

    如果模型的学习能力太强,就不但会学习到数据中的规律,还会学习到数据中的噪声.

    这个时候模型表现: 对训练集预测非常准确,但是对测试集表现就会很差,这种情况下,我们就称为模型过拟合了.

    • 欠拟合:模型的学习能力太差了,连训练集中的规律都没学会.

    • 表现: 无论是训练集还是测试集,它的表现都很差.

    解决方案:网格搜索 调参(降低训练精度,提高测试精度)

    3.1 语法

    GridSearchCV: 交叉验证网格搜索

    class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, n_jobs=None, iid='deprecated', refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score=nan, return_train_score=False)

    参数说明:

    - estimator: 模型
    
    - param_grid : 参数字典
    
    - scoring : 模型评估指标,默认准确率
    
    - n_jobs: CPU个数
    
    - cv: 交叉验证折数
    
    - verbose: 日志
    

    属性:

    - best_estimator_ : estimator  在网格搜索过程中,找到的最好的分类器.
    
    - best_score_: 最好的分类器,对应的交叉验证分数
    
    - best_params_: 最好的分类器对应的参数
    

    3.2 对泰坦尼克模型使用

    from sklearn.model_selection import GridSearchCV
    
    # 实例化
    # 参数分成两部分: 1.你要调参的,就不用设置  2.你不打算调的,就可以设置
    dtc = DecisionTreeClassifier( random_state=666)
    # max_depth=None, 非常重要
    # min_samples_split=2, min_samples_leaf=1, 最小叶节点分裂个数,可选
    # max_leaf_nodes=None, 有一定作用
    # min_impurity_decrease=0.0 有一定作用,范围不好确定
    

    决策树参数说明:

    
    - criterion: 不纯度计算指标 {“gini”, “entropy”},
    
    - splitter: {“best”, “random”}, default=”best” 节点切分方法,默认是选择最优特征进行切分.
    
    - max_depth: 树能达到的最大深度,防止模型太深,控制模型复杂度
    
    - min_samples_split: int or float, default=2  抑制模型分裂
    
        一个节点想要向下进行切分,当前样本个数必须要大于这个参数值.
        例如设置为10,当这个节点中如果有9个样本,则这个节点只能作为叶节点.
    
    - min_samples_leaf:  int or float, default=1  抑制模型分裂
    
        最小叶节点样本个数,如果上层节点分裂之后,分裂出来后的叶节点当中样本个数不足这儿参数值,则本次分裂不能进行.
    
    - max_features : int, float or {“auto”, “sqrt”, “log2”}, default=None
    
        最大特征,在寻找最优分裂点的时候,要考虑的特征个数
    
        If int, 考虑特征个数,举例有100个特征, 填写20,就是每次分裂的时候,只计算20个特征.
    
        If float, 百分比 0-1的浮点数. 100个特征, 填写0.3,那就是计算30个特征.
    
        If “auto”, then max_features=sqrt(n_features). 根号个特征.100个特征就是计算10个特征
    
        If “sqrt”, then max_features=sqrt(n_features). 同上
    
        If “log2”, then max_features=log2(n_features). 计算log2个特征,64个特征,6个.
    
        If None, then max_features=n_features. 所有特征
        
    
    - random_state: 随机数种子
    
    - max_leaf_nodes:  抑制模型分裂,最大叶节点个数,最多能够分裂出多少个叶节点. 
    
    - min_impurity_decrease: 分裂中的最小不纯度下降的值. 
    
        如果一次分裂过程中,Gain的下降不能超过这个值,那么就不能进行本次分裂. 
    
    - class_weight: 类别权重设置,(类别不均衡数据集的问题)
    

    参数调优:

    # 设置调参字典
    # 设置一个调参字典
    d = {"ccp_alpha":np.arange(0.0,0.8,0.1),
        'criterion':["gini",'entropy'],
        "max_depth":[2,3,4,5,6,7],
        "min_samples_split":range(2,10), #最小叶节点样本个数
         "max_leaf_nodes":range(4,20), #最大叶节点个数 
         #"min_impurity_decrease":np.arange(0.01,0.11,0.01) #分裂中的最小不纯度下降的值
        }
    
    # 实例化网格搜索
    grid = GridSearchCV(dtc,param_grid =d ,n_jobs=-1,cv=5,  verbose=2 )
    
    # 训练
    grid.fit(X,y)
    
    # 搜索到的最优交叉验证分数 : 0.8238026489234824
    grid.best_score_
    # 搜索到的参数
    grid.best_params_
    # 结果
    {'criterion': 'gini',
     'max_depth': 6,
     'max_leaf_nodes': 15,
     'min_samples_split': 2}
    
    # 分类器
    best_model = grid.best_estimator_
    
    # 看一下搜索到的这个结果,在测试集上面表现如何?
    best_model.score(X_test,y_test)
    
    # feature_importances_: 特征重要性.
    best_model.feature_importances_
    #结果
    array([0.1935308 , 0.56999101, 0.09826444, 0.04071957, 0.00751746,
           0.08082954, 0.00914718])
    #相对应的特征
    X.columns
    #输出:
    Index(['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked'], dtype='object')
    

    相关文章

      网友评论

          本文标题:决策树

          本文链接:https://www.haomeiwen.com/subject/hmbnwhtx.html