基于C++的决策树C4.5机器学习算法(不调包)

目前玩机器学习的小伙伴,上来就是使用现有的sklearn机器学习包,写两行代码,调调参数就能跑起来,看似方便,实则有时不利于个人能力发展,要知道现在公司需要的算法工程师,不仅仅只是会调参(这种工作,入门几个月的人就可以干了),而是要深入底层,能优化代码,能自己搭。

本文章适合以下几类人:

1)初学者,了解机器学习的实现过程

2)想提升自己的代码能力

第一步:原理

     决策树可以被简单的看成是一些if 和else,其优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。其缺点:可能会产生过度匹配问题。决策树相关详细理论的博客,网上有很多,我就不重复啰嗦了

第二步:代码实现

#include <vector>
#include <set>
#include <map>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <math.h>using namespace std;/*******树的构造*******/
struct TreeNode {string            m_sAttribute;//节点名字int               m_iDeciNum;  //yes 数int               m_iUnDecinum; //no 数vector<TreeNode*> m_vChildren;
};TreeNode* CreateTreeNode(string value)
{TreeNode* pNode = new TreeNode();pNode->m_sAttribute = value;return pNode;
}bool FindNode(TreeNode* pRoot, std::string& item)
{if (pRoot->m_sAttribute == item)return true;bool found = false;vector<TreeNode*>::iterator i = pRoot->m_vChildren.begin();while (!found && i < pRoot->m_vChildren.end()){found = FindNode(*i, item);++i;}return found;
}void ConnectTreeNodes(TreeNode* pParent, TreeNode* pChild)
{if (pParent != NULL){pParent->m_vChildren.push_back(pChild);}
}void PrintTreeNode(TreeNode* pNode)
{if (pNode != NULL){printf("value of this node is: %d.\n", pNode->m_sAttribute);printf("its children is as the following:\n");std::vector<TreeNode*>::iterator i = pNode->m_vChildren.begin();while (i < pNode->m_vChildren.end()){if (*i != NULL)printf("%s\t", (*i)->m_sAttribute);++i;}printf("\n");}else{printf("this node is null.\n");}printf("\n");
}void PrintTree(TreeNode* pRoot)
{PrintTreeNode(pRoot);if (pRoot != NULL){std::vector<TreeNode*>::iterator i = pRoot->m_vChildren.begin();while (i < pRoot->m_vChildren.end()){PrintTree(*i);++i;}}
}void DestroyTree(TreeNode* pRoot)
{if (pRoot != NULL){std::vector<TreeNode*>::iterator i = pRoot->m_vChildren.begin();while (i < pRoot->m_vChildren.end()){DestroyTree(*i);++i;}delete pRoot;}
}
/*******树的构造*******/class DecisionTree {
private:struct attrItem{std::vector<int>  itemNum;  //itemNum[0] = itemLine.size()//itemNum[1] = decision numset<int>		  itemLine; //可用行};//重点struct attributes{string attriName; //属性名字vector<double> statResult;map<string, attrItem*> attriItem;//存放子目录的信息};vector<attributes*> statTree;int attriNum;vector<vector<string>> infos;map<string, int> attr_clum;//作用不大public:DecisionTree() {attriNum = 0;}vector<vector<string>>& getInfos(){return infos;}vector<attributes*>& getStatTree(){return statTree;}int pretreatment(string filename, set<int>& readLineNum, vector<int>& readClumNum);int statister(vector<vector<string>>& infos, vector<attributes*>& statTree,set<int>& readLine, vector<int>& readClumNum);int compuDecisiNote(vector<attributes*>& statTree, int deciNum, int lineNum, vector<int>& readClumNum);double info_D(int deciNum, int sum);void resetStatTree(vector<attributes*>& statTree, vector<int>& readClumNum);double Info_attr(map<string, attrItem*>& attriItem, double& splitInfo, int lineNum);void CreatTree(TreeNode* &treeHead, vector<attributes*>& statTree, vector<vector<string>>& infos,set<int>& readLine, vector<int>& readClumNum, int deep);
};/*
* @function CreatTree 预处理函数,负责读入数据,并生成信息矩阵和属性标记
* @param: filename 文件名
* @param: readLineNum 可使用行set
* @param: readClumNum 可用属性vector 0可用 1不可用
* @return int 返回函数执行状态
*/int DecisionTree::pretreatment(string filename, set<int>& readLineNum, vector<int>& readClumNum)
{}/*
* @function Info_attr info_D 总信息量
* @param: deciNum 有效信息数
* @param: sum 总信息量
* @return double 总信息量比例
*/
double DecisionTree::info_D(int deciNum, int sum)
{double pi = (double)deciNum / (double)sum;double result = 0.0;if ((1.0 - pi) < 0.000001 || (pi - 0.0) < 0.000001){return result;}result = pi * (log(pi) / log((double)2)) + (1 - pi)*(log(1 - pi) / log((double)2));return -result;
}/*
* @function Info_attr 总信息量
* @param: deciNum 有效信息数
* @param: sum 总信息量
* @return double
*/
double DecisionTree::Info_attr(map<string, attrItem*>& attriItem, double& splitInfo, int lineNum)
{double result = 0.0;for (map<string, attrItem*>::iterator item = attriItem.begin();item != attriItem.end();++item){double pi = (double)(item->second->itemNum[0]) / (double)lineNum;splitInfo += pi * (log(pi) / log((double)2));double sub_attr = info_D(item->second->itemNum[1], item->second->itemNum[0]);result += pi * sub_attr;}splitInfo = -splitInfo;return result;
}/*
* @function compuDecisiNote 计算C4.5
* @param: statTree 为状态树,此树动态更新,但是由于是DFS对数据更新,所以不必每次新建状态树
* @param: deciNum Yes的数据量
* @param: lineNum 计算set的行数
* @param: readClumNum 用于计算的set
* @return int 信息量最大的属性号
*/
int DecisionTree::compuDecisiNote(vector<attributes*>& statTree, int deciNum, int lineNum, vector<int>& readClumNum)
{double max_temp = 0;int max_attribute = 0;//总的yes行的信息量double infoD = info_D(deciNum, lineNum);for (int i = 0; i < attriNum - 1; i++){if (readClumNum[i] == 0){double splitInfo = 0.0;//infodouble info_temp = Info_attr(statTree[i]->attriItem, splitInfo, lineNum);statTree[i]->statResult.push_back(info_temp);//gaindouble gain_temp = infoD - info_temp;statTree[i]->statResult.push_back(gain_temp);//split_infostatTree[i]->statResult.push_back(splitInfo);//gain_infodouble temp = gain_temp / splitInfo;statTree[i]->statResult.push_back(temp);//得到最大值*/if (temp > max_temp){max_temp = temp;max_attribute = i;}}}return max_attribute;
}/*
* @function resetStatTree 清理状态树
* @param: statTree 状态树
* @param: readClumNum 需要清理的属性set
* @return void
*/void DecisionTree::resetStatTree(vector<attributes*>& statTree, vector<int>& readClumNum)
{for (int i = 0; i < readClumNum.size() - 1; i++){if (readClumNum[i] == 0){map<string, attrItem*>::iterator it_end = statTree[i]->attriItem.end();for (map<string, attrItem*>::iterator it = statTree[i]->attriItem.begin();it != it_end; it++){delete it->second;}statTree[i]->attriItem.clear();statTree[i]->statResult.clear();}}
}int main(int argc, char* argv[]) {string filename = "tree.txt";DecisionTree dt;int attr_node = 0;TreeNode* treeHead = nullptr;set<int> readLineNum;vector<int> readClumNum;int deep = 0;if (dt.pretreatment(filename, readLineNum, readClumNum) == 0){dt.CreatTree(treeHead, dt.getStatTree(), dt.getInfos(), readLineNum, readClumNum, deep);}return 0;
}

第三步:运行过程

IDE编译软件用vs2010以上版本,运行结果

10ca49f0ced0fb33295195f078c03e56.png

第四步:项目源码下载:

整套算法系列:深度学习与机器学习_AI洲抿嘴的薯片的博客-CSDN博客

项目源码下载地址:关注文末【AI街潜水的八角】,回复【决策树机器学习算法】即可下载

整套项目源码内容包含

程序里面包括决策树C4.5机器学习算法,接近上千行代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/466486.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mac解决 zsh: command not found: ll

Mac解决 zsh: command not found: ll 文章目录 Mac解决 zsh: command not found: ll解决方法 解决方法 1.打开bash_profile 配置文件vim ~/.bash_profile2.在文件中添加配置&#xff1a;alias llls -alF键盘按下 I 键进入编辑模式3. alias llls -alF添加完配置后&#xff0c;按…

VBA10-处理Excel的动态数据区域

end获取数据边界 1、基本语法 1-1、示例&#xff1a; 2、配合row和column使用 2-1、示例1 2-2、示例2 此时&#xff0c;不管这个有数值的区域&#xff0c;怎么增加边界&#xff0c;对应的统计数据也会跟着变的&#xff01;

无人车之路径规划篇

无人车的路径规划是指在一定的环境模型基础上&#xff0c;给定无人车起始点和目标点后&#xff0c;按照性能指标规划出一条无碰撞、能安全到达目标点的有效路径。 一、路径规划的重要性 路径规划对于无人车的安全、高效运行至关重要。它不仅能够提高交通效率&#xff0c;减少交…

【前端基础】CSS基础

目标&#xff1a;掌握 CSS 属性基本写法&#xff0c;能够使用文字相关属性美化文章页。 01-CSS初体验 层叠样式表 (Cascading Style Sheets&#xff0c;缩写为 CSS&#xff09;&#xff0c;是一种 样式表 语言&#xff0c;用来描述 HTML 文档的呈现&#xff08;美化内容&#…

一种高度集成的数字化管理平台:城市管理综合执法系统(源码)

什么是城市管理综合执法系统&#xff1f; 城市管理综合执法系统是一种高度集成的数字化管理平台&#xff0c;它旨在通过整合信息技术资源&#xff0c;实现对城市环境、秩序、设施等多方面的综合管理和高效执法。 城市管理综合执法系统通常包含以下几个核心要素和功能&#xff…

【Python】强大的正则表达式工具:re模块详解与应用

强大的正则表达式工具&#xff1a;re模块详解与应用 在编程和数据处理中&#xff0c;字符串的处理是不可避免的一项任务。无论是从文本中提取信息、验证数据格式&#xff0c;还是进行复杂的替换操作&#xff0c;正则表达式&#xff08;Regular Expression&#xff0c;简称Rege…

计算机毕业设计Python+图神经网络手机推荐系统 手机价格预测 手机可视化 手机数据分析 手机爬虫 Django Flask Spark 知识图谱

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

03.DDD六边形架构

学习视频来源&#xff1a;DDD独家秘籍视频合集 https://space.bilibili.com/24690212/channel/collectiondetail?sid1940048&ctype0 文章目录 什么是依赖DDD四层架构六边形架构代码实现 想要详细了解六边形架构&#xff0c;可以看我之前的一篇文章。是对六边形架构原文的翻…

前端开发实现自定义勾选/自定义样式,可复选,可取消勾选

基于后端返回数组实现多选、复选 以下代码基于vue2&#xff0c;如果有需要React/Vue3或者其他框架代码的&#xff0c;可以通过国内直连GPT4o进行代码转换&#xff0c;转换正确率99% 前端代码如下(直接拷贝到你的vue代码即可)&#xff1a; <!-- CustomCheckboxList.vue --&g…

新型智慧城市顶层设计方案(118页word)

文档介绍&#xff1a; 新型智慧城市顶层设计方案是一种全局性、前瞻性的规划&#xff0c;旨在通过整合城市各类资源&#xff0c;运用新一代信息技术&#xff0c;推动城市治理、民生服务、产业发展等领域的全面升级&#xff0c;以实现城市的可持续发展和居民生活质量的提升。该…

nginx-proxy-manager实现反向代理+自动化证书(实战)

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 &#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 cnginx-proxy-manager实现反向代理自动化证书 nginx-proxy-manager是什么搭建nginx-proxy-manage…

定时器入门:Air780E定时器基础与进阶

今天我们学习的是Air780E定时器基础与进阶&#xff0c;让大家更深入的了解定时器。 一、定时器(timer)的概述 在Air780E模组搭载的LuatOS系统中&#xff0c;定时器&#xff08;timer&#xff09;是一项基础且关键的服务。它允许开发者在特定的时间点或周期性地执行代码段&…

C语言复习第7章 自定义类型(结构体+位段+枚举+联合体)

目录 一、结构体1.1 内置类型和自定义类型1.2 结构体的概念1.3 结构体基本的声明1.4 区分两种创建结构体变量的方式1.5 结构体变量的定义和初始化1.6 区分一下typdef和变量列表1.7 匿名结构体类型1.8 访问结构体成员1.9 修改字符数组成员变量的时候 要用strcpy1.10 结构体的传参…

Twitter(X)2024最新注册教程

Twitter 现名为X&#xff0c;因为图标是一只小鸟的形象&#xff0c;大家也叫它小蓝鸟&#xff08;埃隆马斯克于 2023 年对该平台进行了品牌重塑&#xff09;&#xff0c;目前仍然是全球最受欢迎的社交媒体和微博平台之一&#xff0c;全球活跃用户量大概在4.5亿。尤其是欧美国家…

[单例模式]

[设计模式] 设计模式是软件工程中的一种常见做法, 它可以理解为"模板", 是针对一些常见的特定场景, 给出的一些比较好的固定的解决方案. 不同语言适用的设计模式是不一样的. 这里我们接下来要谈到的是java中典型的设计模式. 而且由于设计模式比较适合有一定编程经…

[mysql]DDL,DML综合案例,

综合案例 题目如下 目录 综合案例 ​编辑 ​编辑 # 1、创#1建数据库test01_library # 2、创建表 books&#xff0c;表结构如下&#xff1a; # 3、向books表中插入记录库存 # 4、将小说类型(novel)的书的价格都增加5。 # 5、将名称为EmmaT的书的价格改为40&#xff0c;并将…

day-81 打家劫舍 II

思路 与LCR 089. 打家劫舍相比&#xff0c;本题所有房屋围成了一圈&#xff0c;那么第一间房子和最后一间房子不能同时打劫&#xff0c;那么就可以分为两种情况&#xff1a;1.选第一间房打劫&#xff1b;2.选最后一间房打劫 解题过程 然后依次计算出以上两种情况的最大金额&am…

秃姐学AI系列之:GRU——门控循环单元 | LSTM——长短期记忆网络

RNN存在的问题 因为RNN模型的BPTT反向传导的链式求导&#xff0c;导致需要反复乘以一个也就是说会出现指数级别的问题&#xff1a; 梯度爆炸&#xff1a;如果的话&#xff0c;那么连乘的结果可能会快速增长&#xff0c;导致梯度爆炸梯度消失&#xff1a;如果的话&#xff0c;…

OpenHarmony 入门——ArkUI 自定义组件间的父子双向同步状态装饰器@Link语法(四)

文章大纲 引言一、组件间状态装饰器Link 父子双向同步1、使用规则2、支持的观察变化的场景和ArkUI 刷新UI3、Link变量值初始化和更新机制3.1、初始渲染&#xff1a;执行父组件的build()函数后将创建子组件的新实例。3.2、Link的数据源的更新&#xff1a;即父组件中状态变量更新…

机器学习与数据挖掘_使用梯度下降法训练线性回归模型

目录 实验内容 实验步骤 1. 导入必要的库 2. 加载数据并绘制散点图 3. 设置模型的超参数 4. 实现梯度下降算法 5. 打印训练后的参数和损失值 6. 绘制损失函数随迭代次数的变化图 7. 绘制线性回归拟合曲线 8. 基于训练好的模型进行新样本预测 实验代码 实验结果 实验…