决策树

2020-04-29  本文已影响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')

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')
上一篇下一篇

猜你喜欢

热点阅读