决策树生成涉及到两个问题:如何选择最优特征属性进行分裂,以及停止分裂的条件是什么
1、树回归比线性回归强大在哪儿?
①线性回归创建的模型需要拟合所有的样本点(局部加权线性回归外)。当数据的特征众多、特征关系复杂时,构建全局模型难以实现;
②实际问题不可能都是线性的,不可能用全句线性模型来拟合任何数据;
③可以将数据切分成为易建模的多份数据,然后再利用线性回归技术来进行建模。如果首次切分后仍然难以拟合线性模型,就继续进行切分。在这种情况下,树结构和回归法就相当有用
2、树回归的优缺点:
①优点:可以对复杂和非线性的数据进行建模;
②缺点:结果不易理解;
③适用数据类型:数值型和标称型数据
3、与ID3等相比,CART中二元切分的特点
①ID3选取当前最佳特征来切分数据,并且按照该特征的所有取值来进行切分,切分速度过于迅速;
②ID3不能直接处理连续型特征,只有事先将连续型转换为离散型,才能在ID3中使用,但这种转换肯定会破坏连续型变量的内在性质,CART中的二元切分方式易于对树构建过程进行调整以处理连续型特征;
③二元切分节省了树的构建时间
4、CART回归树生成
假设
X
和
考虑如何生成回归树。
一个回归树应该对应着输入空间(即特征空间)的一个划分以及在划分的单元上的输出值。假设已经将输入空间划分为M个单元 R1,R2,...,RM ,并且在每一个单元 Rm 上有一个固定的输出值 cm , 于是回归树模型可以表示为
当输入空间的划分确定时,可以用 f(x)=∑xi∈Rm(yi−f(xi))2 来表示回归树对于训练数据的预测误差, 用平方误差最小的准则来求解每个单元上的最优输出值,单元 Rm 上的 cm 最优值 cm^ 是 Rm 上所有输入实例 xi 对应的输出 yi 的均值。
怎样对输入空间进行划分?
选择第j个变量 x(j)和他的取值 s ,作为切分变量和切分点,并定两个区域
然后寻找最优切分变量j和最优且分点s,具体地,求解
对固定输入变量j可以找到最优且分点s.
遍历所有输入变量,找到最优的切分变量j,构成(j,s),依次将输入空间划分为两个区域。接着对每个区域重复上述划分过程,直到满足停止条件。这样就生成了一颗回归树
5、对混乱程度的理解
为成功构建以分段常熟为叶结点的树,需要度量出数据的一致性。使用树进行分类时,会在给定节点上计算数据的混乱度。如何计算连续值的混乱度?
①首先计算所有数据的均值;
②然后计算每条数据的值到均指的差值;
③一般使用绝对值或者平方值来代替上述差值,此种做法类似于统计学中的方差计算,唯一不同的是,方差是平方误差的均值,而此处为平方误差的总值(总误差)。
*混乱程度!不是错误…*
6、回归树实例
7、代码实现
①加载数据;
②依据某个特征A,此特征A的某个取值a进行数据集的切分,返回根据此规则切分后,分别生成的两个数据集mat0,mat1;
③遍历当前数据集中所有的特征、所有的特征取值后,选取使得混乱程度最小的A与a,混乱程度的计算方法即为上述相较于mean的总误差;
④返回条件:
1)当前目标变量集合(当前数据集)中标签唯一,那么就不需要进行切分,直接返回;
2)切分后效果提升不大,创建叶节点然后直接返回;
3)对切分后子集的大小进行检测,如果某个子集的大小小于定义的某值,直接返回;
4)如果上述提前终止的条件全都不符合,那么就返回切分特征和特征值
①对数据进行加载
def loadDataSet(file):
dataSet = []
f = open(file)
for line in f.readlines():
cur_line = line.strip().split('\t')
flt_line = map(float,cur_line)
dataMat.append(flt_line)
return dataSet
返回[[],[],[],…,[]]
②将传入的dataSet进行切分(按A、a遍历一遍),返回两个matrix,分别为 yi 大于或小于等于定义的value
def binSplit(dataSet,feature,value):
mat0 = dataSet[np.nonzero(dataSet[:,feature] > value)[0],:]
mat1 = dataSet[np.nonzero(dataSet[:,feature] <= value)[0],:]
return mat0,mat1
③检测一下上一步输出的mat0,mat1是否满足提前终止的条件,如果满足,返回;如果不满足,则继续进行下一步操作
计算根据A、a划分后的混乱程度,为mat0与mat1混乱程度的加和,此处直接使用方差*dataSet中数据总量,得到总方差
def chaos(dataSet):
return np.var(dataSet[:,-1]) * np.shape(dataSet)[0]
然后对当前得到的总方差与历史最小方差进行比较,如果当前chaos表现更优,则更新历史chaos、当前feature索引、当前feature取值
遍历后,得到bestIndex,bextValue,再将其带回binSplit中,获得mat0,mat1
返回
def chooseBestSplit(dataSet,leafType=regLeaf,chaos=chaos,ops=(1,4)):
tolS = ops[0];tolN = ops[1]
if len(set(dataSet[:,-1].T.tolist()[0])) == 1:
return None,leafType(dataSet)
m,n = np.shape(dataSet)
S = chaos(dataSet)
beatS = np.inf;bestIndex = 0;bestValue = 0;
for fea_index in range(n-1):
for val in set((dataSet[:,fea_index].T.A.tolist())[0]):
mat0,mat1 = binSplit(dataSet,fea_index,val)
if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN):continue
newS = chaos(mat0) + chaos(mat1)
if newS < beatS:
bestIndex = fea_index
bestValue = val
beatS = newS
if (S - beatS) < tolS:
return None,leafType(dataSet)
mat0,mat1 = binSplit(dataSet,bestIndex,bestValue)
if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN):
return None,leafType(dataSet)
print 'end***'
return bestIndex,bestValue
这儿是不是不能上传代码…机器学习实战那本书上的代码运行有问题,对其做了修改,代码和数据应该在在资源页……