七 机器学习之Adaboost代码实现

658 阅读3分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

一 简介

单层决策树(decision stump)也称决策树桩,是一种简单的决策树。第2期我们已经讲过决策树的相关原理了, 接下来我们一起来构建一个单层决策树,它仅仅基于单个特征来做决策。由于这棵树只有一次分裂过程,因此它实 际上就是一个树桩。

二 构建简单数据集

我们先构建一个简单数据集来确保我们写出的函数能够正常运行。

import numpy as np
import pandas as pd
#获得特征矩阵和标签矩阵
def get_Mat(path):
    dataSet = pd.read_table(path,header = None)
    xMat = np.mat(dataSet.iloc[:,:-1].values)
    yMat = np.mat(dataSet.iloc[:,-1].values).T
    return xMat,yMat
    
xMat,yMat = get_Mat('simpdata.txt')
xMat

image.png

yMat

image.png

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['simhei']#显示中文
%matplotlib inline
#数据集可视化函数
def showPlot(xMat,yMat):
    x=np.array(xMat[:,0])
    y=np.array(xMat[:,1])
    label = np.array(yMat)
    plt.scatter(x,y,c=label)
    plt.title('单层决策树测试数据')
    plt.show()
showPlot(xMat,yMat)

image.png

三. 构建单层决策树

我们会建立两个函数来实现我们的单层决策树: 第一个函数用来测试是否有某个值小于或者大于我们正在测试的阈值。 第二个函数稍微复杂一些,会在一个加权数据集中循环,并找到具有最低错误率的单层决策树 伪代码如下:

  • 将最小错误率minE设为+∞
  • 对数据集中每一个特征(第1层循环):
  • 对每个步长(第2层循环):
  • 对每个不等号(第3层循环):
  • 建立一颗单层决策树并利用加权数据集对它进行预测
  • 如果错误率低于minE,则将当前单层决策树设为最佳单层决策树
  • 返回最佳单层决策树
def Classify0(xMat,i,Q,S):
    re = np.ones((xMat.shape[0],1))                       #初始化re为1
    if S == 'lt':
        re[xMat[:,i] <= Q] = -1                           #如果小于阈值,则赋值为-1
    else:
        re[xMat[:,i] > Q] = -1                            #如果大于阈值,则赋值为-1
    return re
def get_Stump(xMat,yMat,D):
    m,n = xMat.shape                                #m为样本个数,n为特征数             
    Steps = 10                                      #初始化一个步数
    bestStump = {}                                  #用字典形式来储存树桩信息
    bestClas = np.mat(np.zeros((m,1)))              #初始化分类结果为1
    minE = np.inf                                   #最小误差初始化为正无穷大
    for i in range(n):                              #遍历所有特征
        Min = xMat[:,i].min()                       #找到特征中最小值
        Max = xMat[:,i].max()                       #找到特征中最大值
        stepSize = (Max - Min) / Steps              #计算步长
        for j in range(-1, int(Steps)+1):                                     
            for S in ['lt', 'gt']:                  #大于和小于的情况,均遍历。lt:less than,gt:greater than
                Q = (Min + j * stepSize)            #计算阈值
                re = Classify0(xMat, i, Q, S)       #计算分类结果
                err = np.mat(np.ones((m,1)))        #初始化误差矩阵
                err[re == yMat] = 0                 #分类正确的,赋值为0
                eca = D.T * err                     #计算误差
                #print(f'切分特征: {i}, 阈值:{np.round(Q,2)}, 标志:{S}, 权重误差:{np.round(eca,3)}')
                if eca < minE:                      #找到误差最小的分类方式
                    minE = eca
                    bestClas = re.copy()
                    bestStump['特征列'] = i
                    bestStump['阈值'] = Q
                    bestStump['标志'] = S
    return bestStump,minE,bestClas
m=xMat.shape[0]
D = np.mat(np.ones((m, 1)) / m)  #初始化样本权重(每个样本权重相等)
get_Stump(xMat,yMat,D)

image.png