基于sklearn的线性回归模型实现多变量决策树

1 多变量决策树简介

  多变量决策树的每个非叶结点是对多个属性组合的判断。这里多个属性组合的方式可以是简单的线性组合,也可以是复杂组合,如每个非叶结点设置一个神经网络对多个属性的复杂组合进行判断。
  图1-1展示了一棵采用线性组合方式的多变量决策树。

在这里插入图片描述

图1-1 多变量决策树

2 实现思路

  使用sklearn提供的乳腺癌数据集,从根结点开始,考察每一个结点。当考察结点 n n n时,先用结点 n n n所拥有的数据集 D D D(根结点拥有全部训练数据)拟合出一个线性回归模型 l i n e a r linear linear(回归模型在这里实际上实现的分类功能,也可用其他模型,如逻辑回归)。
  再对数据集 D D D进行划分,将数据集 D D D l i n e a r linear linear的预测输出分类两类(正类和负类,在下面代码中体现为输出小于 0 0 0还是大于 0 0 0)。得到两个集合 D − D^- D D + D^+ D+
  考察集合 D − D^- D,使用 l i n e a r linear linear对其进行评价,若其精度大于等于事先设定的阈值或 D − D^- D为空,则将结点 n n n的左子结点设为叶子节点,类别标记为负类;若精度小于阈值,则将 D − D^- D复制到结点 n n n的左子结点,递归地考察左子结点。
  同理,考察集合 D + D^+ D+,使用 l i n e a r linear linear对其进行评价,若其精度大于等于事先设定的阈值或 D + D^+ D+为空,则将结点 n n n的右子结点设为叶子节点,类别标记为正类;若精度小于阈值,则将 D + D^+ D+复制到结点 n n n的右子结点,递归地考察右子结点。

3 代码中的函数说明

3.1 class TreeNode

class TreeNode(object):
    
    def __init__(self, model=None, C=None, left=None, right=None):
        self.model = model
        self.C = C
        self.left = left
        self.right = right

  定义结点结构,包含四个变量。 m o d e l model model是结点的线性模型; C C C为结点的类别标记,仅在叶子结点时有意义,对于非叶子节点, C C C N o n e None None l e f t left left是左孩子; r i g h t right right是右孩子。

3.2 trainLinear

def trainLinear(linear, x, y):
    #使用sklearn库的最小二乘估计训练一个线性模型
    linear.fit(x, y)
    return linear

  使用数据 x x x和标签 y y y训练一个线性模型 l i n e a r linear linear,使用sklearn的最小二乘法进行训练,返回训练好的模型。

3.3 binaryTrainSet

def binaryTrainSet(linear, x, y):
    #根据线性回归模型二分数据集
    #对样本x[i],其线性模型预测值若小于等于0,分到x0集合;若大于0,分到x1集合;相应的标签也划分的y0,y1集合
    x0 = []
    x1 = []
    y0 = []
    y1 = []
    p = linear.predict(x)
    for i in range(p.shape[0]):
        if p[i] <= 0:
            x0.append(x[i])
            y0.append(y[i])
        else:
            x1.append(x[i])
            y1.append(y[i])
    return np.array(x0), np.array(x1), np.array(y0), np.array(y1)

  按照线性模型 l i n e a r linear linear预测类别划分数据集。

3.4 score

def score(linear, x, y):
    #计算线性模型linear的精度
    right = 0
    p = linear.predict(x)
    for i in range(p.shape[0]):
        if p[i]<=0 and y[i]==-1 or p[i]>0 and y[i]==1:
            right += 1
    return right / x.shape[0]

  计算线性模型 l i n e a r linear linear在数据集 x x x上的精度,返回一个位于区间 [ 0 , 1 ] [0,1] [0,1]的浮点数。

3.5 treeGenerate

def treeGenerate(root, x, y, precision):
    #递归建造决策树
    root.model = LinearRegression()
    root.model = trainLinear(root.model, x, y)
    x0, x1, y0, y1 = binaryTrainSet(root.model, x, y)
    
    #构建当前结点左分支
    if len(x0)==0 or score(root.model, x0, y0)>= precision:
        #左分支训练集为空或当前结点的线性模型对左分支的训练样本精度达到了阈值要求(precision),将左分支构建为叶子节点
        root.left = TreeNode(C=-1)
    else:
        #左分支结点精度不够要求,还需进行划分
        root.left = TreeNode()
        treeGenerate(root.left, x0, y0, precision)
    
    #构建当前结点右分支
    if len(x1)==0 or score(root.model, x1, y1) >= precision:
        root.right = TreeNode(C=1)
    else:
        root.right = TreeNode()
        treeGenerate(root.right, x1, y1, precision)

  递归地构建多变量决策树,此函数为代码核心部分, r o o t root root为决策树根结点, x x x y y y是训练数据和标签, p r e c i s i o n precision precision是事前设定的阈值。

3.6 predict

def predict(root, xs):
    #使用以root为根结点的决策树预测样本s
    if root.C is not None:
        #root为叶子结点
        return root.C
    else:
        if root.model.predict(np.expand_dims(xs, axis=0)) <= 0:
            return predict(root.left, xs)
        else:
            return predict(root.right, xs)

  使用构建完成的多变量决策树预测一个样本, r o o t root root为决策树根结点, x s xs xs为样本特征,是一个一维 n u m p y numpy numpy数组,返回样本类别。

3.7 evaluate

def evaluate(root, x, y):
    #计算以root为根结点的决策树在数据集x上的精度
    right = 0
    for i in range(x.shape[0]):
        if predict(root, x[i]) == y[i]:
            right += 1
    return right / x.shape[0]

  计算以 r o o t root root为根结点的多变量决策树在数据集 x x x上的精度, y y y是与样本特征 x x x所对应的标签。

4 完整代码

# -*- coding: utf-8 -*-
"""
Created on Tue Nov 24 17:13:46 2020

@author: qiqi
"""

import numpy as np
from sklearn import preprocessing
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer

class TreeNode(object):
    
    def __init__(self, model=None, C=None, left=None, right=None):
        self.model = model
        self.C = C
        self.left = left
        self.right = right

def trainLinear(linear, x, y):
    #使用sklearn库的最小二乘估计训练一个线性模型
    linear.fit(x, y)
    return linear

def binaryTrainSet(linear, x, y):
    #根据线性回归模型二分数据集
    #对样本x[i],其线性模型预测值若小于等于0,分到x0集合;若大于0,分到x1集合;相应的标签也划分的y0,y1集合
    x0 = []
    x1 = []
    y0 = []
    y1 = []
    p = linear.predict(x)
    for i in range(p.shape[0]):
        if p[i] <= 0:
            x0.append(x[i])
            y0.append(y[i])
        else:
            x1.append(x[i])
            y1.append(y[i])
    return np.array(x0), np.array(x1), np.array(y0), np.array(y1)

def score(linear, x, y):
    #计算线性模型linear的精度
    right = 0
    p = linear.predict(x)
    for i in range(p.shape[0]):
        if p[i]<=0 and y[i]==-1 or p[i]>0 and y[i]==1:
            right += 1
    return right / x.shape[0]
    
def treeGenerate(root, x, y, precision):
    #递归建造决策树
    root.model = LinearRegression()
    root.model = trainLinear(root.model, x, y)
    x0, x1, y0, y1 = binaryTrainSet(root.model, x, y)
    
    #构建当前结点左分支
    if len(x0)==0 or score(root.model, x0, y0)>= precision:
        #左分支训练集为空或当前结点的线性模型对左分支的训练样本精度达到了阈值要求(precision),将左分支构建为叶子节点
        root.left = TreeNode(C=-1)
    else:
        #左分支结点精度不够要求,还需进行划分
        root.left = TreeNode()
        treeGenerate(root.left, x0, y0, precision)
    
    #构建当前结点右分支
    if len(x1)==0 or score(root.model, x1, y1) >= precision:
        root.right = TreeNode(C=1)
    else:
        root.right = TreeNode()
        treeGenerate(root.right, x1, y1, precision)

def predict(root, xs):
    #使用以root为根结点的决策树预测样本s
    if root.C is not None:
        #root为叶子结点
        return root.C
    else:
        if root.model.predict(np.expand_dims(xs, axis=0)) <= 0:
            return predict(root.left, xs)
        else:
            return predict(root.right, xs)

def evaluate(root, x, y):
    #计算以root为根结点的决策树在数据集x上的精度
    right = 0
    for i in range(x.shape[0]):
        if predict(root, x[i]) == y[i]:
            right += 1
    return right / x.shape[0]

if __name__ == '__main__':
    #加载乳腺癌数据集
    cancer = load_breast_cancer()

    #参数random_state是指随机生成器,测试集占全部数据的33%
    X_train, X_test, y_train, y_test = train_test_split(cancer['data'],cancer['target'], test_size=0.33, random_state=42)
    
    #将y_train与y_test标签中的0全部改为-1
    y_train[y_train == 0] = -1
    y_test[y_test == 0] = -1

    #数据标准化
    X_train = preprocessing.scale(X_train)
    X_test = preprocessing.scale(X_test)
    
    #构建决策树
    root = TreeNode()
    #此处的阈值不能设的太大,由于数据本身就有一定客观存在的误差,无法做到100%精度,阈值设的太大容易爆栈
    treeGenerate(root, X_train, y_train, 0.96)
    
    #计算训练好的决策树在测试集上的精度
    scoreTrain = evaluate(root, X_train, y_train)
    scoreTest = evaluate(root, X_test, y_test)
    print('训练集精度为:', round(scoreTrain,4))
    print('测试集精度为:', round(scoreTest, 4))

5 结果

  最终生成的多变量决策树的训练集和测试集精度分别为 0.979 0.979 0.979 0.9628 0.9628 0.9628。实际上,由于乳腺癌数据集比较简单,生成的多变量决策树的深度很小,其所具有的强大数据拟合能力并没有完全发挥出来。

  • 11
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奇齐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值