数学建模教学:常用算法 --- CART-分类回归树算法

前言

本人计算机研二,专业带队数学建模,长期更新建模教学,有需要的同学欢迎讨论~

本篇文章,本系列学长讲解一部分数学建模常用算法,会陆续更新每个算法的详细实现和使用教程

CART - Classification and Regression Trees

分类与回归树,是二叉树,可以用于分类,也可以用于回归问题,最先由 Breiman 等提出。

分类树的输出是样本的类别, 回归树的输出是一个实数。

CART算法有两步

决策树生成和剪枝。

决策树生成:

递归地构建二叉决策树的过程,基于训练数据集生成决策树,生成的决策树要尽量大;

自上而下从根开始建立节点,在每个节点处要选择一个最好的属性来分裂,使得子节点中的训练集尽量的纯。

不同的算法使用不同的指标来定义"最好":

分类问题,可以选择GINI,双化或有序双化;
回归问题,可以使用最小二乘偏差(LSD)或最小绝对偏差(LAD)。

决策树剪枝:

用验证数据集对已生成的树进行剪枝并选择最优子树,这时损失函数最小作为剪枝的标准。

这里用代价复杂度剪枝 Cost-Complexity Pruning(CCP)

回归树的生成

数学建模教学:常用算法 --- CART-分类回归树算法_第1张图片
数学建模教学:常用算法 --- CART-分类回归树算法_第2张图片

分类树的生成

数学建模教学:常用算法 --- CART-分类回归树算法_第3张图片
在这里插入图片描述

代码实现

# -*- coding: utf-8 -*-
"""
 @File    : cart.py
 @Software: PyCharm
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 最小二乘损失
def err(dataSet):
    #return sum((dataSet[:,-1]- dataSet[:,-1].mean())**2) # 最原始的写法
    return np.var(dataSet[:,-1])*dataSet.shape[0]  #均方差*数据总条数

#划分数据集,按出入的数据列fea,数据值value将数据划分为两部分
def splitDataSet(dataSet, fea, value):
    dataSet1=dataSet[dataSet[:,fea]<=value]
    dataSet2=dataSet[dataSet[:,fea]>value]
    return dataSet1,dataSet2
    
# 选择最好的特征划分数据集,min_sample每次划分后每部分最少的数据条数,epsilon误差下降阈值,值越小划分的决策树越深
def chooseBestFeature(dataSet,min_sample=4,epsilon=0.5):
    features=dataSet.shape[1]-1   # x特征列数量
    sErr=err(dataSet) # 整个数据集的损失
    minErr=np.inf
    bestColumn = 0 # 划分最优列
    bestValue = 0  # 划分最优的值
    nowErr=0       # 当前平方误差
    if len(np.unique(dataSet[:,-1].T.tolist())) == 1: # 数据全是一类的情况下 返回
        return None, np.mean(dataSet[:,-1])
    for fea in range(0,features): # 按x特征列循环
        for row in range(0,dataSet.shape[0]): # 遍历每行数据,寻找最优划分
            dataSet1,dataSet2=splitDataSet(dataSet, fea,dataSet[row,fea]) # 获得切分后的数据
            if len(dataSet1) < min_sample or len(dataSet2) < min_sample:  # 按行遍历时总会有一些划分得到的集合不满足最小数据条数约束,跳过此类划分
                continue
            nowErr=err(dataSet1)+err(dataSet2) # 计算当前划分的平方误差
            #print('fea:',fea,'row:',row,'datavalue',dataSet[row,fea],'nowErr',nowErr)
            if nowErr<minErr: # 判断获得最优切分值
                minErr=nowErr
                bestColumn=fea
                bestValue=dataSet[row,fea]
        #print('fea',fea,'minErr',minErr,'bestColumn',bestColumn,'bestValue',bestValue)
    if (sErr - minErr) < epsilon: # 当前误差下降较小时,返回
        return None, np.mean(dataSet[:,-1])
    # 当前最优划分集合
    dataSet1,dataSet2=splitDataSet(dataSet, bestColumn,bestValue)
    if len(dataSet1) < min_sample or len(dataSet2) < min_sample: # 如果划分的数据集很小,返回
        return None, np.mean(dataSet[:,-1])
    return bestColumn,bestValue
    
def createTree(dataSet):
    """
    输入:训练数据集D,特征集A,阈值ε
    输出:决策树T
    """
    bestColumn,bestValue=chooseBestFeature(dataSet)
    if bestColumn == None:  # 所有列均遍历完毕,返回
        return bestValue
    retTree = {}  # 决策树 
    retTree['spCol'] = bestColumn # 最优分割列
    retTree['spVal'] = bestValue  # 最优分割值
    lSet, rSet = splitDataSet(dataSet, bestColumn,bestValue) # 按当前最优分割列级值划分为左右2枝
    retTree['left'] = createTree(lSet)  # 迭代继续划分左枝
    retTree['right'] = createTree(rSet) # 迭代继续划分右枝
    return retTree

if __name__ == '__main__':
    # 使用sin函数随机产生x,y数据
    X_data_raw = np.linspace(-3, 3, 50)
    np.random.shuffle(X_data_raw)  # 随机打乱数据
    y_data = np.sin(X_data_raw)    # 产生数据y
    x = np.transpose([X_data_raw]) # 将x进行转换
    y = y_data + 0.1 * np.random.randn(y_data.shape[0]) # 产生数据y,增加随机噪声
    dataSet=np.column_stack((x,y.reshape((-1,1))))      # 将x与y进行合并
    
#    data=pd.read_table('D:/python_data/ex0.txt',header=None)
#    dataSet=data.values
    
    mytree=createTree(dataSet) 
    print('mytree\n',mytree)


最后

数学建模精选资料共享,研究生学长数模指导,建模比赛思路分享,关注我不迷路!

建模指导,比赛协助,有问必答,欢迎打扰

你可能感兴趣的:(算法,分类,回归)