《实例》阐述算法,通俗易懂,助您对算法的理解达到一个新高度。包含但不限于:经典算法,机器学习,深度学习,LeetCode 题解,Kaggle 实战。期待您的到来!
01
—
回顾
近几天推送了以决策树为基础模型的,性能优秀,应用广泛的 XGBoost 集成算法。与之相似的,比 XGBoost 发明还早的 GBDT(梯度提升决策树),它们的共同点都是以决策树为基础模型,要想深刻的理解这两种重要的集成算法,如果能更好地理解决策树算法的实现,会有助于理解它们。
下面,我们用源码实现决策树的回归算法,提到决策树一般都会用分类来讲解,一般来说这样比较容易入门,但是决策树用于回归也是非常普遍的,尤其GBDT和XGBoost也会以回归决策树为基础模型,接下来先看下回归决策树的代码实现吧。
02
—
从代码说起,不说公式
先用易懂的文字阐述下决策树的回归算法的实现思路。比如,一个数据集有3个特征,对应的目标值不再是整数,0,1,2,3,这种分类值,而是0.1,0.23,1.4等这种小数值。那么,怎么用决策树的模型做回归呢?
首先,依次遍历每个特征,然后,遍历每个特征的取值,注意,特征的取值可能有很多种,根据定义的最佳分割点的方法,找出当前特征的最佳分割点,内层循环结束后即可找到当前特征的最佳分割点,等外层循环遍历结束时,找到所有特征中的最佳分割点。
import numpy as np
#求得mat的最后一列,也就是目标值的平均值
def regLeaf(mat):
return np.mean(mat[:,-1])
#定义误差计算方法:mat最后一列(目标值)的方差乘以个数
def regErr(mat):
return np.var(mat[:,-1]) * np.shape(mat[:,-1])[0]
#生成回归决策树,给出一个元参数:
# 第一个表示分割后误差下降的大小未超过此值,直接作为叶节点输出(带有目标值)
# 第二个参数表示某个节点内含有的节点个数,必须大于这个值,才会进一步分裂
def decisionTreeRegressor(dataSet,ops=(0.0001,3)):
feat,val = chooseBestSplit(dataSet,leafType,regErr,ops)
if feat==None:
return val
retTree={}
retTree['spIndex'] = feat
retTree['spValue'] = val
lSet,rSet = binSplitDataSet(dataSet,feat,val)
retTree['left'] = createTree(lSet,leafType,regErr,ops)
retTree['right'] = createTree(rSet,leafType,regErr,ops)
return retTree
#根据最佳索引和取值,将数据集分开
def binSplitDataSet(dataSet,bestIndex,bestValue):
mat0 = dataSet[np.array(dataSet)[:,bestIndex]<bestValue]
mat1 = dataSet[np.array(dataSet)[:,bestIndex]>=bestValue]
return mat0,mat1
#选择最佳切分属性及其对应的属性值
#所有的属性遍历后,如果误差减少不大,生成叶子节点
# 得到叶节点的条件有3个,标红色的代码
def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr,ops=(0.0001,3)):
tolS = ops[0]
tolN = ops[1]
#所有的样本对应的目标值都相等,则
if len(set(dataSet[:,-1].T.tolist())) ==1:
return None, leafType(dataSet)
m,n = np.shape(dataSet)
S = errType(dataSet)
bestS = np.inf
bestIndex = 0
bestValue = 0
for featIndex in range(n):
for splitVal in set(dataSet[:,featIndex]):
mat0,mat1 = binSplitDataSet(dataSet,featIndex,splitVal)
#这个条件约束了分割后的区间长度都不能小于tolN
if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0]<tolN):
continue
#求出分割后的两部分均方误差的和
newS = errType(mat0) + errType(mat1)
#如果newS更小,则让它成为bestS
if newS < bestS:
bestIndex = featIndex
bestValue = splitVal
bestS = newS
#说明误差下降的不大
if S - bestS < tolS:
return None,leafType(dataSet)
#根据最优特征和其对应的取值划分数据集
mat0,mat1 = binSplitDataSet(dataSet,bestIndex,bestValue)
#满足这种情况,只能是所有的样本点个数小于tolN
#此时只给出当前样本的均方误差
if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN):
return None, leafType(dataSet[:,bestIndex])
return bestIndex, bestValue
03
—
决策树回归分析
写好了以上代码,调用上面 decisionTreeRegressor,看看回归决策树的回归效果,为了展示方便,特意将满足分裂的条件加大,即内含节点个数大些。
当 ops[1] = 6时,即节点内含样本数大于6才做分裂,待回归的样本如下,
此时调用接口做回归,得到的决策树的示意图如下:
回归后的结果如下:
当 ops[1] = 5 时,即节点内含样本数大于5才做分裂,得到的决策树示意图和回归图如下,
以上就是用决策树做回归的整体代码实现思路和实现效果,最核心的还是选择特征和取值,在这里实际上是运用了最小均方差来选择。
明天该到GBDT的实现原理了,欢迎关注。
算法channel已推送的更多文章:
4 回归分析简介
8 机器学习之线性回归:OLS 无偏估计及相关性python分析
13 机器学习:谈谈决策树
14 机器学习:对决策树剪枝
17 机器学习:说说贝叶斯分类
本文分享自 程序员郭震zhenguo 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!