本文传送机
在回归的这篇文章中提供一一些强大的方法,但这些方法创建的模型需要你和所有的样本点(局部加强线性回归LWLR除外)。当数据拥有众多特征并且特征之间的关系十分复杂时,构建全局模型的想法就显得太难了。而且实际中很多问题都是非线性的,不可能使用全局限性模型来拟合任何数据。
一种可行的方法是数据集切分成很多份易建模的数据,然后利用线性回归技术来建模。如果首次切分之后仍然难以拟合线性模型就继续切分。在这种切分方式下,树构建和回归法就相当有用。
复杂数据的局部性建模
CART时十分著名且广泛记载的树构建算法,它使用二元切分来处理连续性变量。对CART稍作修改就可以处理回归问题。用于分类任务中的CART使用香农熵来度量集合的无组织程度。如果选用其他方法来代替香农熵,就可以使用树构建算法来完成回归。
树回归的一般方法
- 收集数据:采用任意方法收集数据
- 准备数据:需要数值型的数据,标称型数据应该映射成二值型数据
- 分析数据:绘出数据的二维可视化显示结果,以字典方式生成树
- 训练算法:大部分时间都花费在叶节点树模型的构建上
- 测试算法:使用测试数据上的
值来分析模型的效果
- 使用算法:使用训练出的树做预测,预测结果还可以用来做很多事情
连续和离散型特征的树的构建
这里将构建两种树:第一种是回归树(regression tree),其每个叶节点包含单个值;第二种是模型树(model tree),其叶节点包含一个线性方程。
函数create_tree()的伪代码:
- 找到最佳的待切分特征:
- 如果该节点不能再分,将该节点存为叶节点
- 执行二元切分
- 在右子树调用create_tree()方法
- 在左子树调用create_tree()方法
代码:
import numpy as np
def load_data_set(file_name):
data_array = []
file = open(file_name)
for line in file.readlines():
current_line = line.strip().split('\t')
float_line = map(float, current_line)
data_array.append(float_line)
return data_array
def binary_split_data_set(data_set, feature, value):
mat0 = data_set[np.nonzero(data_set[:, feature] > value)[0], :][0]
mat1 = data_set[np.nonzero(data_set[:, feature] <= value)[0], :][0]
return mat0, mat1
def create_tree(data_set, leaf_type=regress_leaf, error_type=regress_error, ops=(1, 4)):
feature, value = choose_best_split(data_set, leaf_type, error_type, ops)
if feature== None:
return value
return_tree = {}
return_tree['split_feature'] = feature
return_tree['split_value'] = value
left_set, right_set = binary_split_data_set(data_set, feature, value)
return_tree['left'] = create_tree(left_set, leaf_type, error_type, ops)
return_tree['right'] = create_tree(right_set, leaf_type, error_type, ops)
return return_tree
将CART算法用于回归
未成功构建以分段常熟为叶节点的树,需要度量出数据的一致性。那么如何计算连续性数值的混乱度呢?事实上,在数据集上计算混乱度非常简单,首先计算出所有数据的均值,然后计算每条数据的值到达均值的差值。为了对正负差值同等看待,一般使用平方值来代替上述差值。(即计算数据集的总方差)
构建树
为使上面代码中的create_tree()能够运行,首先要做的是实现choose_best_split()函数。给定某个误差计算方法,该函数会找到数据集上最佳的二元切分方式。另外,该函数还需要确定什么时候停止切分,一旦停止切分会生成一个叶节点。因此,choose_best_split()函数只需完成两件事:用最佳方式切分数据集和生成相应的叶节点。
代码:
import numpy as np
def load_data_set(file_name):
data_array = []
file = open(file_name)
for line in file.readlines():
current_line = line.strip().split('\t')
float_line = list(map(float, current_line))
data_array.append(float_line)
return np.array(data_array)
def binary_split_data_set(data_set, feature, value):
mat0 = data_set[np.nonzero(data_set[:, feature] > value)[0], :]
mat1 = data_set[np.nonzero(data_set[:, feature] <= value)[0], :]
return mat0, mat1
def regress_leaf(data_set):
return np.mean(data_set[:, -1])
def regress_error(data_set):
return np.var(data_set[:, -1]) * np.shape(data_set)[0]
def choose_best_split(data_set, leaf_type=regress_leaf, error_type=regress_error, ops=(1, 4)):
tolerate_error = ops[0]
tolerate_number = ops[1]
if len(set(data_set[:, -1])) == 1:
return None, leaf_type(data_set)
m, n = np.shape(data_set)
error = error_type(data_set)
best_error = np.inf
best_index = 0
best_value = 0
for feature_index in range(n-1):
for split_value in set(data_set[:, feature_index]):
mat0, mat1 = binary_split_data_set(data_set, feature_index, split_value)
if np.shape(mat0)[0] < tolerate_number or np.shape(mat1)[0] < tolerate_number:
continue
new_error = error_type(mat0)+ error_type(mat1)
if new_error < best_error:
best_error = new_error
best_index = feature_index
best_value = split_value
if error - best_error < tolerate_error:
return None, leaf_type(data_set)
mat0, mat1 = binary_split_data_set(data_set, best_index, best_value)
if np.shape(mat0)[0] < tolerate_number or np.shape(mat1)[0] < tolerate_number:
return None, leaf_type(data_set)
return best_index, best_value
def create_tree(data_set, leaf_type=regress_leaf, error_type=regress_error, ops=(1, 4)):
feature, value = choose_best_split(data_set, leaf_type, error_type, ops)
if feature== None:
return value
return_tree = {}
return_tree['split_feature'] = feature
return_tree['split_value'] = value
left_set, right_set = binary_split_data_set(data_set, feature, value)
return_tree['left'] = create_tree(left_set, leaf_type, error_type, ops)
return_tree['right'] = create_tree(right_set, leaf_type, error_type, ops)
return return_tree
if __name__ == '__main__':
data_set = load_data_set('ex0.txt')
tree = create_tree(data_set)
print(tree)
结果:
{'split_feature': 1, 'split_value': 0.39435, 'left': {'split_feature': 1, 'split_value': 0.582002, 'left': {'split_feature': 1, 'split_value': 0.797583, 'left': 3.9871632, 'right': 2.9836209534883724}, 'right': 1.980035071428571}, 'right': {'split_feature': 1, 'split_value': 0.197834, 'left': 1.0289583666666666, 'right': -0.023838155555555553}}
CONTACT INFORMATON
E-mail: birdguan@seu.edu.cn
QQ: 46611253