对称二叉树oblivious decision tree的简单实现python

2023-11-25 00:59

本文主要是介绍对称二叉树oblivious decision tree的简单实现python,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、详情

可参见论文《BDT: Gradient Boosted Decision Tables for High Accuracy and Scoring Efficiency》

1.对称树也叫做决策表,每一层使用相同的分裂条件。
在这里插入图片描述

2.决策表的紧凑表示,这种表示会导致非常小的内存占用,并使其对缓存相当友好。
在这里插入图片描述
3.损失函数
在这里插入图片描述
4.具体实现的时候,采样下面的结构表示决策表,可以加速计算Gain。
在这里插入图片描述
5.计算Gain
在这里插入图片描述
6.构建决策表
在这里插入图片描述

二、代码

本例子较为简单,只是实现了回归的Decision Tables,而且没有包括反拟合算法。

import pandas as pd
import numpy as np
import sklearn.datasets as datasets
from numpy import *
import copy as cp
import sklearn.metrics as metrics
from sklearn.model_selection import train_test_split#特征值和原本索引结构
class Sample_index(object):def __init__(self):self.featureIndex = []self.feature_values = []self.sample_index = []#决策表的类
class Decision_table(object):def __init__(self):self.features = []self.cuts = []self.predictions = []#为每个特征的特征值遍历样本索引
def visit_feature_value_sample_index(X_train):m, n = X_train.shapefeature_sample_index = Sample_index() #每个特征的特征值对应的样本索引for feaIndex in range(n):  # 遍历特征feature_sample_index.featureIndex.append(feaIndex)feature_values = np.sort(list(set(X_train[:, feaIndex])))[::-1].tolist() # 将特征值按照降序排列feature_sample_index.feature_values.append(feature_values)value_sample_index_list = []for value in feature_values:  # 遍历数据集,生成对于特征值的样本索引sample_index_list = []for j in np.where(X_train[:, feaIndex] == value):sample_index_list.append(j)value_sample_index_list.append(sample_index_list)feature_sample_index.sample_index.append(value_sample_index_list)return feature_sample_index#选择最好的分裂点
def choose_best_feature(y_train, depth, Sample_index, Partition_label, Count, Sum, bestGain):bestGain = bestGain #最大的熵增c = None #特征 x_j的最好划分特征值best_feature_index = None #最好划分的特征 x_j索引best_count = None #落入每个分区的样本数best_sum = None #落入每个分区的样本标签值之和best_partition_label = None #每个样本对应的分区索引sample_index = Sample_index#计算特征x_j在第d次划分时的收益for feature_index in sample_index.featureIndex:count = cp.deepcopy(Count)  # 存储分区 k 中的样本点数sum = cp.deepcopy(Sum)  # 存储分区k中样本点的标签的总和partition_label = cp.deepcopy(Partition_label)  # 记录每个样本对应的分区索引for value_index in range(len(sample_index.feature_values[feature_index])):  # 遍历特征if value_index != 0:for data_index in sample_index.sample_index[feature_index][value_index-1]:#遍历特征值下的样本集索引count[partition_label[data_index].astype(np.int32)] = count[partition_label[data_index].astype(np.int32)] -1sum[partition_label[data_index].astype(np.int32)] = sum[partition_label[data_index].astype(np.int32)] - y_train[data_index]count[partition_label[data_index].astype(np.int32) - 1] = count[partition_label[data_index].astype(np.int32) - 1] + 1sum[partition_label[data_index].astype(np.int32) - 1] = sum[partition_label[data_index].astype(np.int32) - 1] + y_train[data_index]partition_label[data_index] = partition_label[data_index] -1gain = 0for k in range(np.power(2, depth)):if count[k] != 0:gain = gain + (sum[k] * sum[k]) / count[k]if gain > bestGain:bestGain = gainc = list(sample_index.feature_values[feature_index])[value_index]best_feature_index = feature_indexbest_count = cp.deepcopy(count)best_sum = cp.deepcopy(sum)best_partition_label = cp.deepcopy(partition_label)return best_feature_index, c, bestGain, best_count, best_sum, best_partition_label#根据partition_label来统计count和sum的数量
def create_count_sum(partition_label, y_train, depth):partition_num = np.power(2, depth)count = np.zeros([partition_num])sum = np.zeros([partition_num])for i in range(partition_num):count[i] = np.sum(partition_label == i)for j in np.where(partition_label == i)[0]:sum[i] += y_train[j]return count, sum#计算分区的值=叶子节点的值
def get_leafs(count, sum):partition_num = len(sum)predictions = np.zeros([partition_num])for i in range(partition_num):if count[i] != 0:predictions[i] = sum[i] / count[i]return predictions.tolist()#建立决策表
def generate_decision_table(X_train, y_train, sample_index, depth = 2):m, n = X_train.shapecount = np.zeros([2])  # 存储分区 k 中的样本点数sum = np.zeros([2])  # 存储分区k中样本点的标签的总和sample_index = sample_indexGain = -inf  # 最大的熵增#对count,sum,partition_label进行初始化,对于第一次分裂,所有样本都在第1分区count[1] = msum[1] = y_train.sum()partition_label = np.ones([m])  # 记录每个样本对应的分区索引dt = Decision_table() #初始化决策表#贪婪的对决策表找到 其在拟合前 <= depth 个分裂点for t in range(depth):best_feature_index, best_value, bestGain, best_count, best_sum, best_partition_label = choose_best_feature(y_train, t+1, sample_index, partition_label, count, sum, Gain)if best_feature_index == None:breakfeature_index = cp.deepcopy(best_feature_index)value = cp.deepcopy(best_value)partition_label = cp.deepcopy(best_partition_label)count = cp.deepcopy(best_count)sum = cp.deepcopy(best_sum)Gain = bestGaindt.features.append(feature_index)dt.cuts.append(value)if t != depth-1:for i in range(len(partition_label)): #更新下一次分割的样本分区分布partition_label[i] = 2 * partition_label[i] + 1count, sum = create_count_sum(partition_label, y_train, t + 2)#backfiting 这部分的论文内容不太看得明白#叶子的值/每个分区的样本值dt.predictions = get_leafs(count, sum)return dt#用训练好的模型来预测测试集
def tree_table_predict(datasets, tree_table):m, n = datasets.shapedepth = len(tree_table.features)y_hat = np.zeros([m], dtype=int)j = 0for row in datasets:partition_label2 = np.zeros([depth], dtype=int)for i in range(depth):feature_index = int(tree_table.features[i])if float(row[feature_index]) <= tree_table.cuts[i]:partition_label2[i] = 1else:partition_label2[i] = 0#二进制转十进制partition_label2 = partition_label2.tolist()partition_label2 = ''.join(str(i) for i in partition_label2)partition_label10 = int(partition_label2, 2)y_hat[j] = tree_table.predictions[partition_label10]j += 1return y_hatif __name__ == '__main__':#准备数据boston = datasets.load_boston()x = boston['data']y = boston['target']feature_name = list(range(0, 13))#划分数据集X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2)#初始化每个特征值下的样本索引sample_index = visit_feature_value_sample_index(X_train)#建树tree_table = generate_decision_table(X_train, y_train, sample_index, depth=3)print("true_depth= ", len(tree_table.features))#预测y_hat = tree_table_predict(X_test, tree_table)# print("y_hat=", y_hat)#评估MAE = metrics.mean_absolute_error(y_test, y_hat)print("MAE= ", MAE)

这篇关于对称二叉树oblivious decision tree的简单实现python的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/422875

相关文章

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

mybatis执行insert返回id实现详解

《mybatis执行insert返回id实现详解》MyBatis插入操作默认返回受影响行数,需通过useGeneratedKeys+keyProperty或selectKey获取主键ID,确保主键为自... 目录 两种方式获取自增 ID:1. ​​useGeneratedKeys+keyProperty(推

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

Linux在线解压jar包的实现方式

《Linux在线解压jar包的实现方式》:本文主要介绍Linux在线解压jar包的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux在线解压jar包解压 jar包的步骤总结Linux在线解压jar包在 Centos 中解压 jar 包可以使用 u

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

Python包管理工具pip的升级指南

《Python包管理工具pip的升级指南》本文全面探讨Python包管理工具pip的升级策略,从基础升级方法到高级技巧,涵盖不同操作系统环境下的最佳实践,我们将深入分析pip的工作原理,介绍多种升级方... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核