修改第8章文档和修改第9章文档和代码

This commit is contained in:
chenyyx
2017-09-21 09:40:36 +08:00
parent 4e2847a944
commit 99e048a895
3 changed files with 257 additions and 37 deletions

View File

@@ -99,7 +99,7 @@ def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1, 4)):
# 如果结果集(最后一列为1个变量),就返回退出
# .T 对数据集进行转置
# .tolist()[0] 转化为数组并取第0列
if len(set(dataSet[:, -1].T.tolist()[0])) == 1: # 如果集合size为1不用继续划分。
if len(set(dataSet[:, -1].T.tolist()[0])) == 1: # 如果集合size为1也就是说全部的数据都是同一个类别,不用继续划分。
# exit cond 1
return None, leafType(dataSet)
# 计算行列值
@@ -111,7 +111,7 @@ def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1, 4)):
bestS, bestIndex, bestValue = inf, 0, 0
# 循环处理每一列对应的feature值
for featIndex in range(n-1): # 对于每个特征
# [0]表示这一列的[所有行],不要[0]就是一个array[[所有行]]
# [0]表示这一列的[所有行],不要[0]就是一个array[[所有行]]下面的一行表示的是将某一列全部的数据转换为行然后设置为list形式
for splitVal in set(dataSet[:, featIndex].T.tolist()[0]):
# 对该列进行分组然后组内的成员的val值进行 二元切分
mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal)
@@ -170,11 +170,28 @@ def createTree(dataSet, leafType=regLeaf, errType=regErr, ops=(1, 4)):
# 判断节点是否是一个字典
def isTree(obj):
"""
Desc:
测试输入变量是否是一棵树,即是否是一个字典
Args:
obj -- 输入变量
Returns:
返回布尔类型的结果。如果 obj 是一个字典返回true否则返回 false
"""
return (type(obj).__name__ == 'dict')
# 计算左右枝丫的均值
def getMean(tree):
"""
Desc:
从上往下遍历树直到叶节点为止,如果找到两个叶节点则计算它们的平均值。
对 tree 进行塌陷处理,即返回树平均值。
Args:
tree -- 输入的树
Returns:
返回 tree 节点的平均值
"""
if isTree(tree['right']):
tree['right'] = getMean(tree['right'])
if isTree(tree['left']):
@@ -184,6 +201,15 @@ def getMean(tree):
# 检查是否适合合并分枝
def prune(tree, testData):
"""
Desc:
从上而下找到叶节点,用测试数据集来判断将这些叶节点合并是否能降低测试误差
Args:
tree -- 待剪枝的树
testData -- 剪枝所需要的测试数据 testData
Returns:
tree -- 剪枝完成的树
"""
# 判断是否测试数据集没有数据如果没有就直接返回tree本身的均值
if shape(testData)[0] == 0:
return getMean(tree)
@@ -198,7 +224,9 @@ def prune(tree, testData):
if isTree(tree['right']):
tree['right'] = prune(tree['right'], rSet)
# 如果左右两边同时都不是dict字典那么分割测试数据集。
# 上面的一系列操作本质上就是将测试数据集按照训练完成的树拆分好,对应的值放到对应的节点
# 如果左右两边同时都不是dict字典也就是左右两边都是叶节点而不是子树了那么分割测试数据集。
# 1. 如果正确
# * 那么计算一下总方差 和 该结果集的本身不分枝的总方差比较
# * 如果 合并的总方差 < 不合并的总方差,那么就进行合并
@@ -222,12 +250,28 @@ def prune(tree, testData):
# 得到模型的ws系数f(x) = x0 + x1*featrue1+ x3*featrue2 ...
# create linear model and return coeficients
def modelLeaf(dataSet):
"""
Desc:
当数据不再需要切分的时候,生成叶节点的模型。
Args:
dataSet -- 输入数据集
Returns:
调用 linearSolve 函数,返回得到的 回归系数ws
"""
ws, X, Y = linearSolve(dataSet)
return ws
# 计算线性模型的误差值
def modelErr(dataSet):
"""
Desc:
在给定数据集上计算误差。
Args:
dataSet -- 输入数据集
Returns:
调用 linearSolve 函数,返回 yHat 和 Y 之间的平方误差。
"""
ws, X, Y = linearSolve(dataSet)
yHat = X * ws
# print corrcoef(yHat, Y, rowvar=0)
@@ -236,6 +280,16 @@ def modelErr(dataSet):
# helper function used in two places
def linearSolve(dataSet):
"""
Desc:
将数据集格式化成目标变量Y和自变量X执行简单的线性回归得到ws
Args:
dataSet -- 输入数据
Returns:
ws -- 执行线性回归的回归系数
X -- 格式化自变量X
Y -- 格式化目标变量Y
"""
m, n = shape(dataSet)
# 产生一个关于1的矩阵
X = mat(ones((m, n)))
@@ -255,12 +309,33 @@ def linearSolve(dataSet):
# 回归树测试案例
# 为了和 modelTreeEval() 保持一致,保留两个输入参数
def regTreeEval(model, inDat):
"""
Desc:
对 回归树 进行预测
Args:
model -- 指定模型,可选值为 回归树模型 或者 模型树模型,这里为回归树
inDat -- 输入的测试数据
Returns:
float(model) -- 将输入的模型数据转换为 浮点数 返回
"""
return float(model)
# 模型树测试案例
# 对输入数据进行格式化处理在原数据矩阵上增加第0列元素的值都是1
# 也就是增加偏移值,和我们之前的简单线性回归是一个套路,增加一个偏移量
def modelTreeEval(model, inDat):
"""
Desc:
对 模型树 进行预测
Args:
model -- 输入模型,可选值为 回归树模型 或者 模型树模型,这里为模型树模型
inDat -- 输入的测试数据
Returns:
float(X * model) -- 将测试数据乘以 回归系数 得到一个预测值 ,转化为 浮点数 返回
"""
n = shape(inDat)[1]
X = mat(ones((1, n+1)))
X[:, 1: n+1] = inDat
@@ -269,7 +344,21 @@ def modelTreeEval(model, inDat):
# 计算预测的结果
# 在给定树结构的情况下,对于单个数据点,该函数会给出一个预测值。
# modelEval是对叶节点进行预测的函数引用指定树的类型以便在叶节点上调用合适的模型。
# 此函数自顶向下遍历整棵树,直到命中叶节点为止,一旦到达叶节点,它就会在输入数据上
# 调用modelEval()函数该函数的默认值为regTreeEval()
def treeForeCast(tree, inData, modelEval=regTreeEval):
"""
Desc:
对特定模型的树进行预测,可以是 回归树 也可以是 模型树
Args:
tree -- 已经训练好的树的模型
inData -- 输入的测试数据
modelEval -- 预测的树的模型类型,可选值为 regTreeEval回归树 或 modelTreeEval模型树默认为回归树
Returns:
返回预测值
"""
if not isTree(tree):
return modelEval(tree, inData)
if inData[tree['spInd']] <= tree['spVal']:
@@ -286,20 +375,32 @@ def treeForeCast(tree, inData, modelEval=regTreeEval):
# 预测结果
def createForeCast(tree, testData, modelEval=regTreeEval):
"""
Desc:
调用 treeForeCast ,对特定模型的树进行预测,可以是 回归树 也可以是 模型树
Args:
tree -- 已经训练好的树的模型
inData -- 输入的测试数据
modelEval -- 预测的树的模型类型,可选值为 regTreeEval回归树 或 modelTreeEval模型树默认为回归树
Returns:
返回预测值矩阵
"""
m = len(testData)
yHat = mat(zeros((m, 1)))
# print yHat
for i in range(m):
yHat[i, 0] = treeForeCast(tree, mat(testData[i]), modelEval)
# print "yHat==>", yHat[i, 0]
return yHat
if __name__ == "__main__":
# # 测试数据集
# testMat = mat(eye(4))
# print testMat
# print type(testMat)
# mat0, mat1 = binSplitDataSet(testMat, 1, 0.5)
# print mat0, '\n-----------\n', mat1
# 测试数据集
testMat = mat(eye(4))
print testMat
print type(testMat)
mat0, mat1 = binSplitDataSet(testMat, 1, 0.5)
print mat0, '\n-----------\n', mat1
# # 回归树
# myDat = loadDataSet('input/9.RegTrees/data1.txt')
@@ -330,26 +431,29 @@ if __name__ == "__main__":
# myTree = createTree(myMat, modelLeaf, modelErr)
# print myTree
# # 回归树 VS 模型树 VS 线性回归
trainMat = mat(loadDataSet('input/9.RegTrees/bikeSpeedVsIq_train.txt'))
testMat = mat(loadDataSet('input/9.RegTrees/bikeSpeedVsIq_test.txt'))
# # 回归树
# # # 回归树 VS 模型树 VS 线性回归
# trainMat = mat(loadDataSet('input/9.RegTrees/bikeSpeedVsIq_train.txt'))
# testMat = mat(loadDataSet('input/9.RegTrees/bikeSpeedVsIq_test.txt'))
# # # 回归树
# myTree1 = createTree(trainMat, ops=(1, 20))
# print myTree1
# yHat1 = createForeCast(myTree1, testMat[:, 0])
# print "--------------\n"
# # print yHat1
# # print "ssss==>", testMat[:, 1]
# print "回归树:", corrcoef(yHat1, testMat[:, 1],rowvar=0)[0, 1]
# 模型树
myTree2 = createTree(trainMat, modelLeaf, modelErr, ops=(1, 20))
yHat2 = createForeCast(myTree2, testMat[:, 0], modelTreeEval)
print myTree2
print "模型树:", corrcoef(yHat2, testMat[:, 1],rowvar=0)[0, 1]
# # 模型树
# myTree2 = createTree(trainMat, modelLeaf, modelErr, ops=(1, 20))
# yHat2 = createForeCast(myTree2, testMat[:, 0], modelTreeEval)
# print myTree2
# print "模型树:", corrcoef(yHat2, testMat[:, 1],rowvar=0)[0, 1]
# 线性回归
ws, X, Y = linearSolve(trainMat)
print ws
m = len(testMat[:, 0])
yHat3 = mat(zeros((m, 1)))
for i in range(shape(testMat)[0]):
yHat3[i] = testMat[i, 0]*ws[1, 0] + ws[0, 0]
print "线性回归:", corrcoef(yHat3, testMat[:, 1],rowvar=0)[0, 1]
# # 线性回归
# ws, X, Y = linearSolve(trainMat)
# print ws
# m = len(testMat[:, 0])
# yHat3 = mat(zeros((m, 1)))
# for i in range(shape(testMat)[0]):
# yHat3[i] = testMat[i, 0]*ws[1, 0] + ws[0, 0]
# print "线性回归:", corrcoef(yHat3, testMat[:, 1],rowvar=0)[0, 1]