实验三:CART回归决策树python实现(两个测试集)(二)|机器学习
2021/11/21 20:10:42
本文主要是介绍实验三:CART回归决策树python实现(两个测试集)(二)|机器学习,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录
- python实现
- 分步
- 源代码(全部)
- 测试集1(波士顿房价数据集)
- 测试集2(糖尿病数据集)
- 总结
python实现
分步
-
划分数据子集(左子树划分比指定值小的样本集合,右子树划分比指定值大的样本集合)
import numpy as np #获取数据子集,分类与回归的做法相同 #将数据集根据划分特征切分为两类 def split_dataset(data_x,data_y,fea_axis,fea_value): ''' input:data_x(ndarry):特征值 data_y(ndarry):标签值 fea_axis(int):进行划分的特征编号(列数) fea_value(int):进行划分的特征对应特征值 output:data_x[equal_Idx],data_y[equal_Idx](ndarry):特征值等于(大于等于)目标特征值的样本与标签 data_x[nequal_Idx],data_y[nequal_Idx](ndarry):特征值不等于(小于)目标特征的样本与标签 ''' if isinstance(fea_value,int) or isinstance(fea_value,float): #如果特征值为浮点数(连续特征值),那么进行连续值离散化 equal_Idx = np.where(data_x[:,fea_axis]<=fea_value) #找出特征值大于等于fea_alue的样本序号 nequal_Idx = np.where(data_x[:,fea_axis]>fea_value) #找出特征值小于fea_alue的样本序号 else: equal_Idx = np.where(data_x[:,fea_axis]==fea_value) #找出特征值等于fea_alue的样本序号 nequal_Idx = np.where(data_x[:,fea_axis]!=fea_value) #找出特征值不等于fea_alue的样本序号 return data_x[equal_Idx],data_y[equal_Idx],data_x[nequal_Idx],data_y[nequal_Idx]
-
叶子结点的均值计算
import numpy as np #叶子结点均值计算 def reg_leaf(data_y): ''' input:data_y(array):标签值 output:(float)均值 ''' return np.mean(data_y)
-
计算数据集总方差
#计算数据集的总方差 def reg_err(data_y): ''' input:data_y(array):标签值 output:(float):总方差 ''' return np.var(data_y)*len(data_y)
-
选取划分特征以及对应的特征值
def classify_get_best_fea(data_x,data_y,ops=(1,4)): ''' input:data_x(ndarry):特征值 data_y(array):标签值 ops(tuple):第一个数为决策树停止划分的最小精度,第二个数为决策树停止划分的最小划分数 output:best_fea_idx(int):最好划分特征的下标 best_fea_val(float):最好划分特征对应的特征值 ''' m,n = np.shape(data_x) final_s = ops[0] #停止的精度 final_n = ops[1] #停止的样本最小划分数 #只有一类样本时,输出叶子结点,以及它对应的均值 if len(np.unique(data_y))==1: return None,reg_leaf(data_y) #获取最优特征和特征值 total_err = reg_err(data_y) #总的误差 best_err = np.inf best_fea_idx = 0 best_fea_val = 0 for i in range(n): feas = np.unique(data_x[:,i]) for fea_val in feas: data_D1_x,data_D1_y,data_D2_x,data_D2_y = split_dataset(data_x,data_y,i,fea_val) #不满足最小划分集合,不进行计算 if data_D1_x.shape[0]<final_n or data_D2_x.shape[0]<final_n: continue con_err = reg_err(data_D1_y)+reg_err(data_D2_y) if con_err<best_err: best_err = con_err best_fea_idx = i best_fea_val = fea_val #预剪枝,求解的误差小于最小误差停止继续划分 if total_err-best_err<final_s: return None,reg_leaf(data_y) #一直无法进行划分,在这里进行处理 data_D1_x,data_D1_y,data_D2_x,data_D2_y = split_dataset(data_x,data_y,best_fea_idx,best_fea_val) if data_D1_x.shape[0]<final_n or data_D2_x.shape[0]<final_n: return None,reg_leaf(data_y) return best_fea_idx,best_fea_val
-
CART回归树的生成(递归生成)
def reg_create_tree(data_x,data_y,ops=(1,4)): fea_idx,fea_val = classify_get_best_fea(data_x,data_y,ops) if fea_idx == None: return fea_val #递归建立CART回归决策树 my_tree = {} my_tree['fea_idx'] = fea_idx my_tree['fea_val'] = fea_val data_D1_x,data_D1_y,data_D2_x,data_D2_y = split_dataset(data_x,data_y,fea_idx,fea_val) my_tree['left'] = reg_create_tree(data_D1_x,data_D1_y,ops) my_tree['right'] = reg_create_tree(data_D2_x,data_D2_y,ops) return my_tree
字典格式为:{’‘fea_idx’’:’‘当前最好划分特征下标’’,’‘fea_val’’:’‘对应特征值’’,’‘left’’:{…},“right”:{…}}。
-
预测函数
#测试操作 import re #预测一条测试数据结果 def classify(inputTree,testdata): ''' input:inputTree(dict):CART分类决策树 xlabel(list):特征属性列表 testdata(darry):一条测试数据特征值 output:classLabel(int):测试数据预测结果 ''' first_fea_idx = inputTree[list(inputTree.keys())[0]] #对应的特征下标 fea_val = inputTree[list(inputTree.keys())[1]] #对应特征的分割值 classLabel = 0.0 #定义变量classLabel,默认值为0 if testdata[first_fea_idx]>=fea_val: #进入右子树 if type(inputTree['right']).__name__ == 'dict': classLabel = classify(inputTree['right'],testdata) else: classLabel = inputTree['right'] else: #进入左子树 if type(inputTree['left']).__name__ == 'dict': classLabel = classify(inputTree['left'],testdata) else: classLabel = inputTree['left'] return round(classLabel,2) #预测所有测试数据结果 def classifytest(inputTree, testDataSet): ''' input:inputTree(dict):训练好的决策树 xlabel(list):特征值标签列表 testDataSet(ndarray):测试数据集 output:classLabelAll(list):测试集预测结果列表 ''' classLabelAll = []#创建空列表 for testVec in testDataSet:#遍历每条数据 classLabelAll.append(classify(inputTree, testVec))#将每条数据得到的特征标签添加到列表 return np.array(classLabelAll)
源代码(全部)
import numpy as np import re #获取数据子集,分类与回归的做法相同 #将数据集根据划分特征切分为两类 def split_dataset(data_x,data_y,fea_axis,fea_value): ''' input:data_x(ndarry):特征值 data_y(ndarry):标签值 fea_axis(int):进行划分的特征编号(列数) fea_value(int):进行划分的特征对应特征值 output:data_x[equal_Idx],data_y[equal_Idx](ndarry):特征值等于(大于等于)目标特征值的样本与标签 data_x[nequal_Idx],data_y[nequal_Idx](ndarry):特征值不等于(小于)目标特征的样本与标签 ''' if isinstance(fea_value,int) or isinstance(fea_value,float): #如果特征值为浮点数(连续特征值),那么进行连续值离散化 equal_Idx = np.where(data_x[:,fea_axis]<=fea_value) #找出特征值大于等于fea_alue的样本序号 nequal_Idx = np.where(data_x[:,fea_axis]>fea_value) #找出特征值小于fea_alue的样本序号 else: equal_Idx = np.where(data_x[:,fea_axis]==fea_value) #找出特征值等于fea_alue的样本序号 nequal_Idx = np.where(data_x[:,fea_axis]!=fea_value) #找出特征值不等于fea_alue的样本序号 return data_x[equal_Idx],data_y[equal_Idx],data_x[nequal_Idx],data_y[nequal_Idx] #叶子结点均值计算 def reg_leaf(data_y): ''' input:data_y(array):标签值 output:(float)均值 ''' return np.mean(data_y) #计算数据集的总方差 def reg_err(data_y): ''' input:data_y(array):标签值 output:(float):总方差 ''' return np.var(data_y)*len(data_y) def classify_get_best_fea(data_x,data_y,ops=(1,4)): ''' input:data_x(ndarry):特征值 data_y(array):标签值 ops(tuple):第一个数为决策树停止划分的最小精度,第二个数为决策树停止划分的最小划分数 output:best_fea_idx(int):最好划分特征的下标 best_fea_val(float):最好划分特征对应的特征值 ''' m,n = np.shape(data_x) final_s = ops[0] #停止的精度 final_n = ops[1] #停止的样本最小划分数 #只有一类样本时,输出叶子结点,以及它对应的均值 if len(np.unique(data_y))==1: return None,reg_leaf(data_y) #获取最优特征和特征值 total_err = reg_err(data_y) #总的误差 best_err = np.inf best_fea_idx = 0 best_fea_val = 0 for i in range(n): feas = np.unique(data_x[:,i]) for fea_val in feas: data_D1_x,data_D1_y,data_D2_x,data_D2_y = split_dataset(data_x,data_y,i,fea_val) #不满足最小划分集合,不进行计算 if data_D1_x.shape[0]<final_n or data_D2_x.shape[0]<final_n: continue con_err = reg_err(data_D1_y)+reg_err(data_D2_y) if con_err<best_err: best_err = con_err best_fea_idx = i best_fea_val = fea_val #预剪枝,求解的误差小于最小误差停止继续划分 if total_err-best_err<final_s: return None,reg_leaf(data_y) #一直无法进行划分,在这里进行处理 data_D1_x,data_D1_y,data_D2_x,data_D2_y = split_dataset(data_x,data_y,best_fea_idx,best_fea_val) if data_D1_x.shape[0]<final_n or data_D2_x.shape[0]<final_n: return None,reg_leaf(data_y) return best_fea_idx,best_fea_val def reg_create_tree(data_x,data_y,ops=(1,4)): ''' input:data_x(ndarry):特征值 data_y(array):标签值 ops(tuple):第一个数为决策树停止划分的最小精度,第二个数为决策树停止划分的最小划分数 output:my_tree(dict):生成的CART决策树字典 ''' fea_idx,fea_val = classify_get_best_fea(data_x,data_y,ops) if fea_idx == None: return fea_val #递归建立CART回归决策树 my_tree = {} my_tree['fea_idx'] = fea_idx my_tree['fea_val'] = fea_val data_D1_x,data_D1_y,data_D2_x,data_D2_y = split_dataset(data_x,data_y,fea_idx,fea_val) my_tree['left'] = reg_create_tree(data_D1_x,data_D1_y,ops) my_tree['right'] = reg_create_tree(data_D2_x,data_D2_y,ops) return my_tree #预测一条测试数据结果 def classify(inputTree,testdata): ''' input:inputTree(dict):CART分类决策树 xlabel(list):特征属性列表 testdata(darry):一条测试数据特征值 output:classLabel(int):测试数据预测结果 ''' first_fea_idx = inputTree[list(inputTree.keys())[0]] #对应的特征下标 fea_val = inputTree[list(inputTree.keys())[1]] #对应特征的分割值 classLabel = 0.0 #定义变量classLabel,默认值为0 if testdata[first_fea_idx]>=fea_val: #进入右子树 if type(inputTree['right']).__name__ == 'dict': classLabel = classify(inputTree['right'],testdata) else: classLabel = inputTree['right'] else: if type(inputTree['left']).__name__ == 'dict': classLabel = classify(inputTree['left'],testdata) else: classLabel = inputTree['left'] return round(classLabel,2) #预测所有测试数据结果 def classifytest(inputTree, testDataSet): ''' input:inputTree(dict):训练好的决策树 xlabel(list):特征值标签列表 testDataSet(ndarray):测试数据集 output:classLabelAll(list):测试集预测结果列表 ''' classLabelAll = []#创建空列表 for testVec in testDataSet:#遍历每条数据 classLabelAll.append(classify(inputTree, testVec))#将每条数据得到的特征标签添加到列表 return np.array(classLabelAll)
测试集1(波士顿房价数据集)
一共拥有十三个属性如下图所示:
导入数据集并训练CART回归树:
#波士顿房价数据集 from sklearn.datasets import load_boston boston = load_boston() data = boston.data target = boston.target # X = data[:200,:] # y = target[:200] x_train,x_test,y_train,y_test = train_test_split(X,y,test_size = 0.3,random_state = 666) #生成CART回归树 cartTree = reg_create_tree(x_train,y_train) print(cartTree)
训练得到的CART树如下图所示:
进行预测可以得到结果如下图所示:
classlist=classifytest(cartTree,x_test) print('预测数据',classlist) print('真实数据'.y_test) print("平均误差为:",abs(np.sum(classlist)-np.sum(y_test))/len(y_test))
测试集2(糖尿病数据集)
一共拥有十个属性如下图所示:
导入数据集并训练CART回归树:
#糖尿病数据集 from sklearn.datasets import load_diabetes diabetes = load_diabetes() data = diabetes.data target = diabetes.target X = data[:500,:] y = target[:500] x_train,x_test,y_train,y_test = train_test_split(X,y,test_size = 0.2,random_state = 666) #生成CART回归树 cartTree = reg_create_tree(x_train,y_train) print(cartTree)
训练得到的CART树如下图所示(500条数据):
进行预测可以得到结果如下图所示:
classlist=classifytest(cartTree,x_test) print('预测数据',classlist) print('真实数据',y_test) print("平均误差为:",abs(np.sum(classlist)-np.sum(y_test))/len(y_test))
总结
(1)使用CART回归树进行预测的数据集标签值都是连续的,当然也可以使用离散的标签值做分类问题,只不过这样做没有必要。对于各项特征对应的特征值可以是连续的也可以是离散的,不同特征之间的数量级也可以不同,因为划分时各特征之间是相互独立的。(对于神经网络来说则需要进行归一化处理)
(2)可以使用平均误差(误差之和的平均值)、均方误差(误差的平方和的平均值)对模型的精度进行评估。
(3)计算方法与CART分类树的基尼系数不同,CART回归树使用均方差的方法。
这篇关于实验三:CART回归决策树python实现(两个测试集)(二)|机器学习的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-21Python编程基础教程
- 2024-11-20Python编程基础与实践
- 2024-11-20Python编程基础与高级应用
- 2024-11-19Python 基础编程教程
- 2024-11-19Python基础入门教程
- 2024-11-17在FastAPI项目中添加一个生产级别的数据库——本地环境搭建指南
- 2024-11-16`PyMuPDF4LLM`:提取PDF数据的神器
- 2024-11-16四种数据科学Web界面框架快速对比:Rio、Reflex、Streamlit和Plotly Dash
- 2024-11-14获取参数学习:Python编程入门教程
- 2024-11-14Python编程基础入门