回归 - 决策树

1.概述

CART, Classification And Regression Tree, 分类与回归树. 该模型由Breiman等人在1984年提出.
该模型中决策树是二叉树, 每个内部节点对应一个二元判断, 判断为 ‘真’, 走左子树, 否则走右子树.

1.2 GBDT

GBDT, Gradient Boosting Decision tree. 梯度提升决策树.
使用提升树的集成学习boosting思想, 使用梯度下降的优化方法, 以CART树做模型.
见参考[1].

2. 思想

类似于分类决策树中, 通过信息熵度量分布的随机情况. 回归树中, 用方差总和(即方差*该集合中样本数) 来度量.

  • 公式

    argminj,s[xiR1(j,s)(yiy¯)2+xiR2(j,s)(yiy¯)2](1) (1) arg ⁡ min j , s [ ∑ x i ∈ R 1 ( j , s ) ( y i − y ¯ ) 2 + ∑ x i ∈ R 2 ( j , s ) ( y i − y ¯ ) 2 ]

    其中 s,js,R1,R2sj s ∈ 特 征 集 合 , j ∈ s 特 征 下 的 取 值 集 合 , R 1 , R 2 为 切 分 特 征 s 与 切 分 值 j 切 分 后 的 两 个 子 样 本 集 .

  • 伪代码

for 特征i in 特征集合:
    for 特征取值j in 特征i的取值集合:
        在 特征i 维度依据 取值j 将集合划分成两部分A与B
        计算切分后的误差x
        if( 该轮误差 <上轮误差):
            split_feature=特征i
            split_value=取值j

依据split_feature,split_value划分集合得到A B,得到左右子树,再递归地使用上述步骤建立完整的树.

3.代码

"""
回归决策树
主要方法为chooseBestSplit(), 依靠它递归地创建二叉树.
该代码体现了大致思想, 实际中还需要 
tolN=切分的最小样本数, tolS=允许的最小误差下降值 
来决定该次划分是产生叶子节点还是递归划分下去.
"""
import numpy as np
import pandas as pd

df=pd.read_csv('D:/code-study/py/diy/regression_problem_training_set.csv')
X = df.loc[:, ['feature1','feature2']]
y= np.ravel(df.loc[:, ['label']])

def chooseBestSplit(X,y):
    '''
    选择最佳split_feature和split_value
    :param X:
    :param y:
    :return: split_feature,split_value
    '''
    min_total_error=float('inf')
    # 双层for循环
    for feature in X.columns:
        series_of_feature=X[feature]
        for value in set(series_of_feature):
            X1,y1,X2,y2=split_by_feature_and_value(X,y,feature,value)
            total_error=calc_error(y1)+calc_error(y2)
            if(total_errorreturn split_feature,split_value


def split_by_feature_and_value(X,y,split_feature,split_value):
    '''
    依照split_feature,split_value, 切分数据集
    :param X:
    :param y:
    :return: 切分后的 X1,y1,X2,y2
    '''
    tmp=X.copy()
    tmp['label']=y
    tmp1=tmp[tmp[split_feature]>split_value]
    tmp2=tmp[tmp[split_feature]<=split_value]
    X1=tmp1.drop('label',1) # 在axis=1的维度上扔掉'label'列
    y1=tmp1['label']

    X2=tmp2.drop('label',1)
    y2=tmp2['label']

    return X1,y1,X2,y2


def calc_error(y):
    '''
    :param y:
    :return: 方差*元素个数
    '''
    return np.var(y)*len(y);

print(chooseBestSplit(X,y))

改代码参考自 <<机器学习实战>>, [美] Peter Harrington, P164.

参考

  1. my blog, 集成学习-GBDT

你可能感兴趣的:(回归)