Skip to main content

决策树

认识决策树

决策树思想的来源非常朴素,程序设计中的条件分支结构就是if-then结构,最早的决策树就是利用这类结构分割数据的一种分类学习方法

信息熵

信息熵:信息的基本作用就是消除人们对事物的不确定性。多数粒子组合之后,在它似像非像的形态上押上有价值的数码,具体地说,这就是一个在博弈对局中信息混乱的现象。

信息熵是信息论中用于度量信息量的一个概念。一个系统越是有序,信息熵就越低; 反之,一个系统越是混乱,信息熵就越高。所以,信息熵也可以说是系统有序化程度的一个度量。

H的专业术语称之为信息熵,单位为比特

H(X) = - \sum_{i=1}^n P(x_i)logP(x_i)

image

计算公式: H(x) = E[I(xi)] = E[ log(2,1/P(xi)) ] = -∑P(xi)log(2,P(xi)) (i=1,2,..n)

其中,x表示随机变量,与之相对应的是所有可能输出的集合,定义为符号集,随机变量的输出用x表示。P(x)表示输出概率函数。变量的不确定性越大,熵也就越大,把它搞清楚所需要的信息量也就越大.

信息增益

特征A对训练数据集D的信息增益g(D,A),定义为集合D的信息熵H(D)与特征A给定条件下D的信息条件熵H(D|A)之差,即公式为:

g(D,A) = - H(D) -H(D|A)

决策树API

  • class sklearn.tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None,random_state=None)
    • 决策树分类器
    • criterion:默认是’gini’系数,也可以选择信息增益的熵’entropy’
    • max_depth:树的深度大小
    • random_state:随机数种子
  • 其中会有些超参数:max_depth:树的深度大小
    • 其它超参数我们会结合随机森林讲解

保存树的结构到dot文件

  1. sklearn.tree.export_graphviz() 该函数能够导出DOT格式
tree.export_graphviz(estimator,out_file='tree.dot',feature_names=['',''])
  1. 工具:(能够将dot文件转换为pdf、png) 安装graphviz
ubuntu:sudo apt-get install graphviz Mac:brew install graphviz
  1. 运行命令
dot -Tpng tree.dot -o tree.png

代码

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, export_graphviz
"""
学习要点:信息熵 信息增益
"""


def show_tree(estimator, feature_name):
export_graphviz(estimator, out_file="../tree.dot", feature_names=feature_name) # 生成树文件, 可以用图像识别软件来画树
return None


def decision_tree_test():
iris = datasets.load_iris()
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)

estimator = DecisionTreeClassifier(criterion="entropy")
estimator.fit(x_train, y_train)
show_tree(estimator, iris.feature_names)

y_predict = estimator.predict(x_test)
print("预测值为:", y_predict, "\n真实值为:", y_test, "\n比较结果为:", y_test == y_predict)
score = estimator.score(x_test, y_test)
print("准确率为: ", score)
return None


if __name__ == '__main__':
decision_tree_test()

结果

预测值为: [0 2 1 2 1 1 1 1 1 0 2 1 2 2 0 2 1 1 1 1 0 2 0 1 2 0 1 2 2 1 0 0 1 1 1 0 0
0]
真实值为: [0 2 1 2 1 1 1 2 1 0 2 1 2 2 0 2 1 1 2 1 0 2 0 1 2 0 2 2 2 2 0 0 1 1 1 0 0
0]
比较结果为: [ True True True True True True True False True True True True
True True True True True True False True True True True True
True True False True True False True True True True True True
True True]
准确率为: 0.8947368421052632

决策树总结

  • 优点:
    • 简单的理解和解释,树木可视化。
  • 缺点:
    • 决策树学习者可以创建不能很好地推广数据的过于复杂的树,这被称为过拟合。
  • 改进:
    - 减枝cart算法(决策树API当中已经实现,随机森林参数调优有相关介绍)
    - 随机森林

    注:企业重要决策,由于决策树很好的分析能力,在决策过程应用较多, 可以选择特征

泰坦尼克号的例子
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn.feature_extraction import DictVectorizer
import numpy as np


def load_data():
data = pd.read_csv("titanic.csv")
titanic = data.copy()

# # 方法一: 过滤掉空的值的数据组, 准确率高点
# data_used = titanic[["pclass", "age", "sex", "survived"]]
# real_data = pd.DataFrame(columns=["pclass", "age", "sex", "survived"])
# for row in data_used.values:
# if not np.isnan(row[1]):
# real_data = real_data.append([{'pclass': row[0], 'age': row[1],
# 'sex': row[2], 'survived': row[3]}],
# ignore_index=True)
# x = real_data[["pclass", "age", "sex"]].to_dict(orient="records")
# y = real_data["survived"]

# 方法二: 对空数据设置个非0值
x = titanic[["pclass", "age", "sex"]] # 只提取这一些特征
y = titanic["survived"] # 目标值
x["age"].fillna(x["age"].mean(), inplace=True)
x = x.to_dict(orient="records")

x_train, x_test, y_train, y_test = train_test_split(x, y.astype('int'), random_state=22)
return x_train, x_test, y_train, y_test


def show_tree(estimator, feature_name):
export_graphviz(estimator, out_file="titanic_tree.dot", feature_names=feature_name)
return None


def titanic_test():
x_train, x_test, y_train, y_test = load_data()

transfer = DictVectorizer()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

estimator = DecisionTreeClassifier(criterion="entropy", max_depth=12)
estimator.fit(x_train, y_train)
show_tree(estimator, transfer.get_feature_names())

y_predict = estimator.predict(x_test)
print("预测值为:", y_predict, "\n真实值为:", y_test, "\n比较结果为:", y_test == y_predict)
score = estimator.score(x_test, y_test)
print("准确率为: ", score)
return None


if __name__ == '__main__':
titanic_test()