决策树与集成学习1-信息熵与手写决策树

文章目录

  • 1. 什么时信息熵
    • 决策树的概念
    • 信息熵与信息增益
    • 计算信息熵
  • 2.决策树极简案例
    • 加载和可视化
    • 采用二叉树进行分类
  • graphviz查看二叉树¶
    • 等高线显示分类结果

1. 什么时信息熵

决策树的概念

决策树思想非常朴素,类似程序设计中的if–else结构,最早的决策树就是利用这类结构分类数据。
决策树与集成学习1-信息熵与手写决策树_第1张图片
思考:最先筛选的条件意味着什么?阈值是否合理?

信息熵与信息增益

信息熵用来描述信源的不确定度,熵在信息论中代表随机变量不确定度的度量。熵越大,数据的不确定性越高。熵越小,数据的不确定性越低。
1.信息熵越小,则说明数据越稳定
2.决策树的分类依据:信息熵 (推荐)、基尼系数
3.同等了数量情况下,概率均等的数据,它的信息熵最大

计算信息熵

在这里插入图片描述
Entropy代表信息熵,i 表示数据总类别数,P(i) 表示类别 i 样本数量占所有样本的比例。

# {1/2 , 1/2} 采用二分法,猜二分类,在样本平均时信息熵为1
H = -(1 / 2 * np.log2(1 / 2) + 1 / 2 * np.log2(1 / 2))
print(H)
# 样本不平均时信息熵会减少
H = -(3/ 4 * np.log2(3 / 4) + 1 / 4 * np.log2(1 / 4))
print(H)
# {1/3,1/3,1/3} ==> 1.5849
H = -(1 / 3 * np.log2(1 / 3) + 1 / 3 * np.log2(1 / 3) + 1 / 3 * np.log2(1 / 3))
print(H)
# {1,0,0}  信息熵为0 则代表100%确定
H = -(1 * np.log2(1 / 1))
print(H)
# 32支球队在夺冠机会均等的情况下, 信息熵为5,也可以理解采用二分法,拆5次可以拆到冠军
H = - (1 / 32 * np.log2(1 / 32)) * 32

结论:分类的质量依赖信息熵,信息熵越小则说明分类的效果越好。当然理论上来说我们可以通过决策树进行无线划分,但是这样又会导致过拟合,因此我需要把握划分的度即可。

2.决策树极简案例

鸢尾花包含三个花的品种(Iris setosa(山鸢尾),Iris virginica(北美鸢尾),Iris versicolor(变色鸢尾))每个品种各50个样本,每个样本四个特征参数(萼片长度和宽度、花瓣长度和宽度)

加载和可视化

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

from sklearn import datasets

iris = datasets.load_iris()
# (150, 4) (150,)
print(iris['data'].shape, iris['target'].shape)
# 可视化方便,我们只保留两列特征
# iris.data[:,:2] 前面两个特征相对不容易区分
X = iris.data[:,2:]
# y是目标值 0,1,2
y = iris['target']
# print(X[y==0].shape,X[y==0][0],X[y==0,0])
plt.scatter(X[y == 0, 0], X[y == 0, 1])
# 采用目标值来筛选样本,吧样本的第0个和第1个特征值分别设置为散点图的x与y轴
plt.scatter(X[y == 1, 0], X[y == 1, 1])
plt.scatter(X[y == 2, 0], X[y == 2, 1])
plt.show()

决策树与集成学习1-信息熵与手写决策树_第2张图片

采用二叉树进行分类

 # 采用sklearn二叉树进行分类
from sklearn.tree import DecisionTreeClassifier,export_graphviz
# 决策树,max_depth 最高的深度,先设置2后面在调整,criterion:默认基尼系数, 建议采用交叉熵
dt_clf = DecisionTreeClassifier(max_depth=2, criterion='entropy',random_state=2)
# 此demo样本数量较少,而且只是为了演示二叉树原理因此未进行测试集与训练集划分
dt_clf.fit(X, y)
print(dt_clf.score(X,y)) # 0.96
# 输出dot文件,并且采用第三方库:graphviz把dot转化为png图片
export_graphviz(decision_tree=dt_clf,out_file="../data/iris.dot",feature_names=['A','B'])

graphviz查看二叉树¶

将graphviz安装目录下的bin文件夹添加到Path环境变量中, 官方的安装路径:https://graphviz.gitlab.io/_pages/Download/Download_windows.html

决策树与集成学习1-信息熵与手写决策树_第3张图片
进入windows命令行界面,输入 dot -version,然后按回车,如果显示graphviz的相关版本信息,则安装配置成功

C:\Users\Administrator>dot -version
dot - graphviz version 2.38.0 (20140413.2041)
libdir = "D:\graphviz\bin"
Activated plugin library: gvplugin_dot_layout.dll
Using layout: dot:dot_layout
-Tv  Set output format to 'v'
-ofile Write output to 'file'
通过命令把dot转化为png图片格式
C:\Users\Administrator>dot C:\Users\Administrator\Desktop\pypro\data\tree.dot -Tpng -o image.png

决策树与集成学习1-信息熵与手写决策树_第4张图片

等高线显示分类结果

# 采用等高线刻画出分类图,此部分与二叉树原理无关,感兴趣同事可以参考:np.meshgrid  np.c_ plt.contourf API
def plot_decistion_boundary(model, axis):
    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1] - axis[0])) * 100).reshape(-1, 1),
        np.linspace(axis[2], axis[3], int((axis[3] - axis[2])) * 100).reshape(-1, 1)
    )
    X_new = np.c_[x0.ravel(), x1.ravel()]
    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)
    custom_cmap = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9'])
    plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)

# 设置等高线的边界
plot_decistion_boundary(dt_clf, axis=[0.5, 7.5, 0, 3])

plt.scatter(X[y == 0, 0], X[y == 0, 1])
plt.scatter(X[y == 1, 0], X[y == 1, 1])
plt.scatter(X[y==2,0],X[y==2,1])
plt.show()

决策树与集成学习1-信息熵与手写决策树_第5张图片
#3. numpy手写决策树

"""
numpy手写决策树
--2023-03-29
可以把决策树的功能进行拆分,然后封装到不同的功能模块。

1.如何获取最优阈值

2.得到阈值如何对样本进行分隔

3.拆分样本后计算信息熵

在实现时按照逆序进行
"""
import numpy as np
# 编写求矩阵信息熵的函数
## 返回的信息熵越小,则说明分类效果越好
from collections import Counter
def entropy(y):
    """
    :param y:
    :return:
    """
    counter = Counter(y)
    res = 0.0
    for num in counter.values():
        p = num/len(y)
        res +=-p*np.log2(p)
    return res
# 采用阈值对特征列进行分割的函数
## 拆分阈值函数
## 采用bool值进行筛选
def split(x,y,d,v):
    '''
    :param x:
    :param y:
    :param d:特征维度
    :param v:阈值
    :return:
    '''
    bool_left = x[:,d]<v
    bool_right = x[:,d]>v
    return x[bool_left],x[bool_right],y[bool_left],y[bool_right]

#搜索最佳列的最佳阈值¶
## 先排序,然后采用二分法或者相邻两数的平均值作为阈值,本次采用后者方法
def try_split(X,y):
    #存储最低的信息熵
    best_entropy = np.inf
    best_d,best_v = -1,-1
    for d in range(X.shape[1]):
        # 进行排序,np.argsort()返回的是元素值从小到大排序后的索引值的数组
        sort_index = np.argsort(X[:,d])
        #内循环,找到维度的每一个特征值
        for num in range(1,len(X)):
            # 如果两个值相等,则阈值就等于他们平均值,这样没有意义
            if X[sort_index[num - 1], d] != X[sort_index[num], d]:
                v = (X[sort_index[num - 1], d] + X[sort_index[num], d]) / 2.0
                # 阈值永远取当前列,两个值的平均数 (2.0 可以保留小数)
                X_l, X_r, y_l, y_r = split(X, y, d, v)
                # 计算当前阈值的信息熵
                e = entropy(y_l) + entropy(y_r)
                if best_entropy > e:
                    best_entropy = e
                    best_d, best_v = d, v
    return best_entropy, best_d, best_v

# 手动测试鸢尾花数据集
from sklearn.datasets import load_iris
if __name__ == '__main__':
    iris = load_iris()
    X = iris.data[:, 2:]
    # y是目标值 0,1,2
    y = iris['target']
    # 第一次二叉树
    best_entropy, best_d, best_v = try_split(X, y)
    print("best_d=", best_d)
    print("best_v=", best_v)
    print("best_entropy=", best_entropy)

    # 把特征与目标值,然后把获得维度,和当前维度的阈值传入,可以得到信息熵
    X1_1, X1_r, y1_1, y1_r = split(X, y, best_d, best_v)
    print(entropy(y1_1))  # 0.0
    print(entropy(y1_r))  # 1.0

    # 第二次二叉树, 返回维度和维度的阈值
    best_entropy2, best_d2, best_v2 = try_split(X1_r, y1_r)
    print("best_d2=", best_d2)
    print("best_v2=", best_v2)
    print("best_entropy2=", best_entropy2)

    # 把特征与目标值,然后把获得维度,和当前维度的阈值传入,可以得到信息熵
    X2_1, X2_r, y2_1, y2_r = split(X1_r, y1_r, best_d2, best_v2)
    print(entropy(y2_1))
    entropy(y2_r)
    print(entropy(y2_r))

决策树与集成学习1-信息熵与手写决策树_第6张图片
从结果可以看出来结果与官方的决策树效果相同。

你可能感兴趣的:(机器学习,python,决策树,集成学习,机器学习)