服务器之家

服务器之家 > 正文

python机器学习实战之树回归详解

时间:2020-12-27 00:23     来源/作者:大牙湾

本文实例为大家分享了树回归的具体代码,供大家参考,具体内容如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#-*- coding:utf-8 -*-
#!/usr/bin/python
'''''
回归树  连续值回归预测 的 回归树
'''
# 测试代码
# import regTrees as RT RT.RtTreeTest() RT.RtTreeTest('ex0.txt') RT.RtTreeTest('ex2.txt')
# import regTrees as RT RT.RtTreeTest('ex2.txt',ops=(10000,4))
# import regTrees as RT RT.pruneTest()
# 模型树 测试
# import regTrees as RT RT.modeTreeTest(ops=(1,10)
# 模型回归树和普通回归树 效果比较 计算相关系数 
# import regTrees as RT RT.MRTvsSRT()
from numpy import *
 
 
# Tab 键值分隔的数据 提取成 列表数据集 成浮点型数据
def loadDataSet(fileName):   #  
  dataMat = []        # 目标数据集 列表
  fr = open(fileName)
  for line in fr.readlines():
    curLine = line.strip().split('\t')
    fltLine = map(float,curLine) #转换成浮点型数据
    dataMat.append(fltLine)
  return dataMat
 
# 按特征值 的数据集二元切分  特征(列)  对应的值
# 某一列的值大于value值的一行样本全部放在一个矩阵里,其余放在另一个矩阵里
def binSplitDataSet(dataSet, feature, value):
  mat0 = dataSet[nonzero(dataSet[:,feature] > value)[0],:][0] # 数组过滤
  mat1 = dataSet[nonzero(dataSet[:,feature] <= value)[0],:][0]
  return mat0,mat1
 
# 常量叶子节点
def regLeaf(dataSet):# 最后一列为标签 为数的叶子节点
  return mean(dataSet[:,-1])# 目标变量的均值
# 方差
def regErr(dataSet):
  return var(dataSet[:,-1]) * shape(dataSet)[0]# 目标变量的平方误差 * 样本个数(行数)的得到总方差
 
# 选择最优的 分裂属性和对应的大小
def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):
  tolS = ops[0] # 允许的误差下降值
  tolN = ops[1] # 切分的最少样本数量
  if len(set(dataSet[:,-1].T.tolist()[0])) == 1: # 特征剩余数量为1 则返回
    return None, leafType(dataSet)       #### 返回 1 #### 
  m,n = shape(dataSet) # 当前数据集大小 形状
  S = errType(dataSet) # 当前数据集误差 均方误差
  bestS = inf; bestIndex = 0; bestValue = 0
  for featIndex in range(n-1):# 遍历 可分裂特征
    for splitVal in set(dataSet[:,featIndex]):# 遍历对应 特性的 属性值
      mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal)# 进行二元分割
      if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN): continue #样本数量 小于设定值,则不切分
      newS = errType(mat0) + errType(mat1)# 二元分割后的 均方差
      if newS < bestS: # 弱比分裂前小 则保留这个分类
        bestIndex = featIndex
        bestValue = splitVal
        bestS = newS
  if (S - bestS) < tolS: # 弱分裂后 比 分裂前样本方差 减小的不多 也不进行切分
    return None, leafType(dataSet)       #### 返回 2 #### 
  mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue)
  if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN): #样本数量 小于设定值,则不切分
    return None, leafType(dataSet)       #### 返回 3 #### 
  return bestIndex,bestValue # 返回最佳的 分裂属性 和 对应的值
 
# 创建回归树 numpy数组数据集 叶子函数  误差函数  用户设置参数(最小样本数量 以及最小误差下降间隔)
def createTree(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):
 # 找到最佳的待切分特征和对应 的值
  feat, val = chooseBestSplit(dataSet, leafType, errType, ops)#
 # 停止条件 该节点不能再分,该节点为叶子节点
  if feat == None: return val 
  retTree = {}
  retTree['spInd'] = feat #特征
  retTree['spVal'] = val #值
 # 执行二元切分 
  lSet, rSet = binSplitDataSet(dataSet, feat, val)# 二元切分 左树 右树
 # 创建左树
  retTree['left'] = createTree(lSet, leafType, errType, ops)  # 左树 最终返回子叶子节点 的属性值
 # 创建右树
  retTree['right'] = createTree(rSet, leafType, errType, ops) # 右树
  return retTree 
 
# 未进行后剪枝的回归树测试 
def RtTreeTest(filename='ex00.txt',ops=(1,4)):
  MyDat = loadDataSet(filename) # ex00.txt y = w*x 两维  ex0.txt y = w*x+b 三维
  MyMat = mat(MyDat)
  print createTree(MyMat,ops=ops)
# 判断是不是树 (按字典形式存储)
def isTree(obj):
  return (type(obj).__name__=='dict')
 
# 返回树的平均值 塌陷处理
def getMean(tree):
  if isTree(tree['right']): 
  tree['right'] = getMean(tree['right'])
  if isTree(tree['left']): 
  tree['left'] = getMean(tree['left'])
  return (tree['left']+tree['right'])/2.0 # 两个叶子节点的 平均值
 
# 后剪枝  待剪枝的树  剪枝所需的测试数据
def prune(tree, testData):
  if shape(testData)[0] == 0
  return getMean(tree) #没有测试数据 返回
  if (isTree(tree['right']) or isTree(tree['left'])): # 如果回归树的左右两边是树
    lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])#对测试数据 进行切分
  if isTree(tree['left']): 
  tree['left'] = prune(tree['left'], lSet)  # 对左树进行剪枝
  if isTree(tree['right']): 
  tree['right'] = prune(tree['right'], rSet)# 对右树进行剪枝
  if not isTree(tree['left']) and not isTree(tree['right']):#两边都是叶子
    lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])#对测试数据 进行切分
    errorNoMerge = sum(power(lSet[:,-1] - tree['left'],2)) +\
      sum(power(rSet[:,-1] - tree['right'],2)) # 对两边叶子合并前计算 误差 
    treeMean = (tree['left']+tree['right'])/2.0 # 合并后的 叶子 均值
    errorMerge = sum(power(testData[:,-1] - treeMean,2))# 合并后 的误差
    if errorMerge < errorNoMerge: # 合并后的误差小于合并前的误差
      print "merging"      # 说明合并后的树 误差更小
      return treeMean      # 返回两个叶子 的均值 作为 合并后的叶子节点
    else: return tree
  else: return tree
   
def pruneTest():
  MyDat = loadDataSet('ex2.txt'
  MyMat = mat(MyDat)
  MyTree = createTree(MyMat,ops=(0,1))  # 为了得到 最大的树 误差设置为0 个数设置为1 即不进行预剪枝
  MyDatTest = loadDataSet('ex2test.txt')
  MyMatTest = mat(MyDatTest)
  print prune(MyTree,MyMatTest)
 
 
######叶子节点为线性模型的模型树#########
# 线性模型
def linearSolve(dataSet):  
  m,n = shape(dataSet) # 数据集大小
  X = mat(ones((m,n))) # 自变量
  Y = mat(ones((m,1))) # 目标变量 
  X[:,1:n] = dataSet[:,0:n-1]# 样本数据集合
  Y = dataSet[:,-1]     # 标签
  # 线性模型 求解
  xTx = X.T*X        
  if linalg.det(xTx) == 0.0:
    raise NameError('行列式值为零,不能计算逆矩阵,可适当增加ops的第二个值')
  ws = xTx.I * (X.T * Y)
  return ws,X,Y
 
# 模型叶子节点
def modelLeaf(dataSet): 
  ws,X,Y = linearSolve(dataSet)
  return ws
 
# 计算模型误差
def modelErr(dataSet):
  ws,X,Y = linearSolve(dataSet)
  yHat = X * ws
  return sum(power(Y - yHat,2))
 
# 模型树测试
def modeTreeTest(filename='ex2.txt',ops=(1,4)):
  MyDat = loadDataSet(filename)
  MyMat = mat(MyDat)
  print createTree(MyMat,leafType=modelLeaf, errType=modelErr,ops=ops)#带入线性模型 和相应 的误差计算函数
 
 
# 模型效果计较
# 线性叶子节点 预测计算函数 直接返回 树叶子节点 值
def regTreeEval(model, inDat):
  return float(model)
 
def modelTreeEval(model, inDat):
  n = shape(inDat)[1]
  X = mat(ones((1,n+1)))# 增加一列
  X[:,1:n+1]=inDat
  return float(X*model) # 返回 值乘以 线性回归系数
 
# 树预测函数
def treeForeCast(tree, inData, modelEval=regTreeEval):
  if not isTree(tree): 
  return modelEval(tree, inData) # 返回 叶子节点 预测值
  if inData[tree['spInd']] > tree['spVal']:   # 左树
    if isTree(tree['left']): 
    return treeForeCast(tree['left'], inData, modelEval)# 还是树 则递归调用
    else
    return modelEval(tree['left'], inData) # 计算叶子节点的值 并返回
  else:
    if isTree(tree['right']):         # 右树
    return treeForeCast(tree['right'], inData, modelEval)
    else
    return modelEval(tree['right'], inData)# 计算叶子节点的值 并返回
 
# 得到预测值    
def createForeCast(tree, testData, modelEval=regTreeEval):
  m=len(testData)
  yHat = mat(zeros((m,1)))#预测标签
  for i in range(m):
    yHat[i,0] = treeForeCast(tree, mat(testData[i]), modelEval)
  return yHat
 
# 常量回归树和线性模型回归树的预测结果比较
def MRTvsSRT():
  TestMat = mat(loadDataSet('bikeSpeedVsIq_test.txt'))
  TrainMat = mat(loadDataSet('bikeSpeedVsIq_train.txt'))
# 普通回归树 预测结果
  # 得到普通回归树树
  StaTree = createTree(TrainMat, ops=(1,20))
  # 得到预测结果
  StaYHat = createForeCast(StaTree, TestMat[:,0], regTreeEval)# 第一列为 自变量
  # 预测结果和真实标签的相关系数
  StaCorr = corrcoef(StaYHat, TestMat[:,1], rowvar=0)[0,1] # NumPy 库函数 
# 模型回归树 预测结果
  # 得到模型回归树
  ModeTree = createTree(TrainMat,leafType=modelLeaf, errType=modelErr, ops=(1,20))
  # 得到预测结果
  ModeYHat = createForeCast(ModeTree, TestMat[:,0], modelTreeEval) 
  # 预测结果和真实标签的相关系数
  ModeCorr = corrcoef(ModeYHat, TestMat[:,1], rowvar=0)[0,1] # NumPy 库函数  
  print "普通回归树 预测结果的相关系数R2: %f" %(StaCorr)                       
  print "模型回归树 预测结果的相关系数R2: %f" %(ModeCorr)
  if ModeCorr>StaCorr:
  print "模型回归树效果优于普通回归树"
  else:
  print "回归回归树效果优于模型普通树"

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://blog.csdn.net/xiaoxiaowenqiang/article/details/77119364

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
Intellij idea2020永久破解,亲测可用!!!
Intellij idea2020永久破解,亲测可用!!! 2020-07-29
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享 2020-04-07
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
电视剧《琉璃》全集在线观看 琉璃美人煞1-59集免费观看地址
电视剧《琉璃》全集在线观看 琉璃美人煞1-59集免费观看地址 2020-08-12
返回顶部