决策树基础学习

信息熵:

信息熵是1948年美国数学家香农提出的概念,他是用来表示随机数据不确定性的度量
信息熵越大,也就意味着越不稳定,信息熵越小,说明数据是越稳定(越接近或者类似)。
信息熵的公式是:
决策树基础学习

信息熵的单位是比特(bit)就是我们在编程中用来计算数据大小的单位。

信息增益:

信息增益表示特征x使得类Y的不确定性减少的程度。因此信息增益越大,那么表示对不确定性减少得越多,也就越能更清晰的分类。特征A对训练数据集D的信息增益记作g(D,A) ,定义为集合D的信息煽H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即公式为:
决策树基础学习

根据信息增益的准则的特征选择方法是:对于训练数据集D,计算其每个特征的信息增益,并比较它们的信息增益,选择信息增益最大的特征
例子:
决策树基础学习

决策树算法选择:

ID3:
ID3算法采用的是信息增益来进行决策树的创建的。信息增益虽然效果不错,但是他是偏向选择分支多的属性,会导致过度拟合,因此一般不会采用此算法。
C4.5:
ID3公导致过度拟合,那么我们能想到的解决办法自然就是对分支过多的情况进行惩罚。于是我们有了信息增益比,或者说信息增益率,信息增益率:
gr=某特征的信息增益/某特征的信息熵
gr=[H(C)- H(c|x)]/H(X)
从上述公式我们可以看到,如果某特征分类特别多,那么会导致信息熵会非常大,从而信息增益也会变得比较大,因此最后得出的信息增益率会变小,这样就对他进行了有效抑制。
CART:
C4.5已经是比较好的构建决策树的算法了,但是他计算的时候需要不断的求对数(log) ,对算法的效率有一定的影响,因此在CART中采用了一个叫做基尼(Gini)系数的东西来进行分类。Gini 系数是一种与信息熵类似的做特征选择的方式,可以用来数据的不纯度。Gini系数的计算方式如下:
Gini§=1-(P12+P22+…)
其中P(n)代表的是第几个特征出现的概率。

预剪枝和后剪枝

树的层级和叶子节点不能过于复杂,如果过于复杂,那么容易导致过拟合现象(过拟合:在训练的时候得分很高,但是测试的时候得分很低)。而预剪枝和后剪枝手段,都是为了防止决策树太复杂的手段:

  • 预剪枝:
    预剪枝就是在决策树的建立过程中不断的调节,可以调节的条件有:
    1.数的深度:如果在决策树建立过程中,发现深度超过指定的值,那么就不再分了。
    2.吐子节点个数:同上。
    3.吐子节点样本数:如果某个叶子节点的个数已经低于指定的值,那么就不会再分了。
    4.值息增益量/Gini系数:计算信息增益量或者Gini系数,如果小于指定的值,那么也不会再分了。
    以上的参数,都需要在建模的过程中,不断的调节,来达到最优。
    预剪枝可以有效的降低过拟合现象,并且因为是在决策树建立的过程中进行调节,因此显著的减少了训练时间开销和测试时间的开销。另外因为预剪枝是通过限制一些建树的条件来实现的,这种方式容易导致(欠拟合:模型训练得不够好)的现象。

  • 后剪枝:
    后剪枝就是在决策树建立完成后再进行的,根据以下公式:
    C = ginisamples + a叶子节点个数
    C表示损失,C越大,表示损失越多,我们要选择损失小的。
    其中的a我们是可以调节的,如果a越大,那么叶子结点个数越多的,损失越大。a值越大,损失越大,要剪枝,a越小,损失越小,要保留。因此a值越大,那么偏向叶子节点少的。a越小,那么偏向叶子节点多的。后剪枝通常比预剪枝保留更多的分支,因此欠拟合风险比预剪枝要小,但是因为后剪枝是在树建立完成后再自底向上对所有非叶子节点进行逐一考察,因此训练时间开销比预剪枝要大得多。

预剪枝容易造成欠拟合,后剪枝训练时间开销大

import pandas as pd
from sklearn.tree import DecisionTreeClassifier,export_graphviz
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer  # 把字符串特征转化为稀疏矩阵
titanic=pd.read_csv('seaborn-data-master/titanic.csv')
titanic.head()
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
0 0 3 male 22.0 1 0 7.2500 S Third man True NaN Southampton no False
1 1 1 female 38.0 1 0 71.2833 C First woman False C Cherbourg yes False
2 1 3 female 26.0 0 0 7.9250 S Third woman False NaN Southampton yes True
3 1 1 female 35.0 1 0 53.1000 S First woman False C Southampton yes False
4 0 3 male 35.0 0 0 8.0500 S Third man True NaN Southampton no True
features=titanic[['pclass','sex','age']]
titanic.info()    # 特征中含有空值
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 15 columns):
survived       891 non-null int64
pclass         891 non-null int64
sex            891 non-null object
age            714 non-null float64
sibsp          891 non-null int64
parch          891 non-null int64
fare           891 non-null float64
embarked       889 non-null object
class          891 non-null object
who            891 non-null object
adult_male     891 non-null bool
deck           203 non-null object
embark_town    889 non-null object
alive          891 non-null object
alone          891 non-null bool
dtypes: bool(2), float64(2), int64(4), object(7)
memory usage: 92.3+ KB
# 处理缺失值,将缺失值用平均值代替
features['age'].fillna(features['age'].mean(),inplace=True) # inplace=True将替换的值代替给特征值,否则就只是返回值,原始的值没有替换成功
features.info()  # 替换成功
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 3 columns):
pclass    891 non-null int64
sex       891 non-null object
age       891 non-null float64
dtypes: float64(1), int64(1), object(1)
memory usage: 21.0+ KB


C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py:6130: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  self._update_inplace(new_data)
targets=titanic['survived']
# targets.head()
X_train,X_test,y_train,y_test=train_test_split(features,targets,test_size=0.25)

# 字典的特征抽取
vect=DictVectorizer()
# 字符串转化为列表字典  .to_dict(orient='records'),fit_transform()转化为稀疏矩阵
X_train=vect.fit_transform(X_train.to_dict(orient='records'))  
X_test=vect.fit_transform(X_test.to_dict(orient='records'))
print(vect.get_feature_names())

tree=DecisionTreeClassifier()
tree.fit(X_train,y_train)  #  由于特征是字符串类型,而非数据类型,因此需要进行字典特征抽取
tree.score(X_test,y_test)  #  0.8251121076233184

[‘age’, ‘pclass’, ‘sex=female’, ‘sex=male’]
0.8251121076233184

# 导出决策树 
export_graphviz(tree,'tree_classifier.dot',  # 自己命名的决策树分类器的名称,自定义.dot名称
                feature_names=['age', 'pclass', 'female', 'male'], # 可以看到特征名称
                class_names=['die','alive']  # 最终的类别
               
               )

导出决策树图的过程:
1.下载软件Grahviz软件,百度搜索,同时设置环境变量
2.打开cmd窗口,cd 导出.dot的文件地址,可以dir看文件目录,
3.写上 dot -Tpng tree_classifier.dot -o tree_classifier.png 命令,生成png图片,打开决策树图片地址即可看到

# 字典的特征抽取
from sklearn.feature_extraction import DictVectorizer
# 数据是列表,列表里面是字典类型  [{ },{ },{ }....]
fruits=[{'fruit':'苹果','price':2.5},{'fruit':'香蕉','price':1.5},{'fruit':'橘子','price':2.99}]
vect=DictVectorizer()
results=vect.fit_transform(fruits)  # 特征抽取之后转化为数据稀疏矩阵
print(vect.get_feature_names())
print(results.toarray())
['fruit=橘子', 'fruit=苹果', 'fruit=香蕉', 'price']
[[0.   1.   0.   2.5 ]
 [0.   0.   1.   1.5 ]
 [1.   0.   0.   2.99]]
上一篇:git 第一次上传本地代码到远程仓库,解决 ! [rejected] master -> master (non-fast-forward)错误


下一篇:Effective C++ 笔记 —— Item 24: Declare non-member functions when type conversions should apply to all