MATLAB实现基本决策树(未剪枝)

决策树

决策树——西瓜书课后作业4.3改进版0.2

之前参考了一部分的代码,发现出错了,修改了错误,并且提出了一种存储方法,这种存储感觉还不是最好的,不过由于国庆前时间有限,而且课后作业要求不是非常严格,能够有一种可行的并且还有道理的就好了,当初是这么想的。
如果有更好的方法,请务必换成更好的。
本文参考的部分代码链接
https://blog.csdn.net/macunshi/article/details/80785585

改进

原先的结果出错了,一是与实际的分类不符合,二是没有保存计算结果,相当于没有做这个工作。修改了三个地方,可以正常使用了。

划分错误:
比如在纹理清晰的部分里面,对于子树密度的判断中,选择>=0.2655是错误的,应当选择密度小于0.381的作为分类,因为对于纹理清晰的子树中,直接按照0和1划分,可以得到最小的增益0,这样在计算最佳增益的时候,减掉0,才是最大的,所以不应按照0.2655划分。

在这里插入图片描述
在这里插入图片描述
按照0.2655划分的熵是
ENT(D) - (6/7log2(6/7) + 1/7log2(1/7)) - (1/1log2(1/1) + 0/0log2(0/1)) =
ENT(D) - a < ENT(D)

按照0.381划分的熵是
ENT(D) - (6/6log2(6/6) + 0/6log2(0/6)) - (2/2log2(2/2) + 0/2log2(0/2))
= ENT(D)

根据选择算法,那肯定是选择0.381划分,这个从直观上也好理解

划分错误原因:
原因1:
MATLAB计算0*log2(0)的结果并非是书上的0,而是NaN
原因2:
最为致命,在所有的算对了之后,在选择最佳增益的部分里面由于没有保存,密度的最佳划分值0.381被下一个属性——含糖率的最佳划分值0.2655给覆盖了,所以才造成计算失误。

改进:
改进1、2:
修改了上面的错误
改进3:
上面的代码实际上没有保存任何有用的信息,即代码运行完成,需要人为查看每次disp()的结果才能够知道树的结构,相当于没有创立这个树。同时当一个新的数据来的时候,没有办法判断.所以存储了树进一个cell里面,保存了结果

改进1:

%计算信息熵
function [entropy]= calculate_entropy(data)
  [m,n] = size(data);
  label_value = data(:,n);
  label = unique(label_value);


  if (size((label),1) > 1)                 % 加入了这一步的判断


      label_number = zeros(length(label),1);
	  %原先是2的
      %label_number(:,1) = label';
      for i= 1:length(label)
          label_number(i,1) = sum(label_value == label(i));
      end
      %计算每个类别有多少个样本,比如蜷缩里面有8个样本,蜷缩对应的值是0
      label_number (:,1) = label_number(:,1) ./ m;
      entropy = 0;
      entropy = sum(-label_number(:,1).*log2 (label_number(:,1)));

  else
      entropy = 0;
  end
end

改进2:

%选择最佳特征
function [best_feature,midle_data]= choose_bestfeature(data,data1) 
  [m,n] = size(data);
  Root_entropy = calculate_entropy(data);
  midle_data = 0; best_gain = 0; best_feature = 0;
% 对于每一列特征
  for j=1:n-1
      feature_value = unique(data(:,j));
      new_entropy = 0;
      for i=1:length(feature_value)
          subdata=splitdata(data,j,feature_value(i,1));
          [m_s,n_s]=size(subdata);
          prob=m_s./m;
          new_entropy = new_entropy + prob * calculate_entropy(subdata);
      end
      inf_gain=Root_entropy - new_entropy;
      if inf_gain > best_gain
        best_gain = inf_gain;
        best_feature = j;
      end
   end
   %if size(data1,2)>=2
   %似乎可以不需要这个判断条件

%将middle_data给传了出来,否则会被覆盖掉的

      for i=1:size(data1,2)-1
          [C_best_gain ,midle_data1]=C_value_bestgain(data1,i);
          if C_best_gain > best_gain
             midle_data = midle_data1;
             best_gain =  C_best_gain;
             best_feature = i+6;
         end
      end
   %end
 
end

改进3:

node = cell(8,6);
global number ;
number = 0;
node = make_tree1(node,Discrete_value,Continue_value,list,father,count,zu,Father);

node1 = traverse_tree(node);
disp('最终结果:')
disp(node1)

number;

%造数加存储树
function [node,list,father,count,Father] = make_tree1(node,data,data1,list,father,count,zu,Father)
%data、data1表示离散和连续的数据,list是最后的结果存储
	global number;
    number = number + 1;
    node{number,1} = number;
%     N = 1 + count*3;  
    [m,n] = size(data);
    [m1,n1] = size(data1);
    node{number,2} = Father;
    %什么时候推出递归呢?
    %1当所有的训练数据用完了
    %2当所有的标签都相同的时候就退出
    label = data(:,n);
	%same_class_num = length(find(data(:,n) ==  label(1,1)));
	%退出递归条件
     
	if size(unique(label),1) == 1||( n == 1 && n1 == 1)
        node{number,3} = '非父结点';
        node{number,4} = '叶子';
        node{number,5} = '无子节点';        
        node{number,6} = label(1);
        return;
    end    
    
    node{number,4} = '结点';   
    node{number,5} = 'Not_yet';    
    node{number,6} = '继续';

	[best_feature,midle_data]= choose_bestfeature(data,data1);
    Father = best_feature;
    node{number,3} = best_feature;

    if best_feature<=6
        C2D_value=ones(size(data1,1),1);
        featvalue = unique(data(:,best_feature));
        featvalue_num = length(featvalue);
        for i=1:featvalue_num
            [subdata,subdata1] = splitData1(data,data1,best_feature,featvalue(i,1),C2D_value);
            [node,list,father,count] = make_tree1(node,subdata,subdata1,list,father,count,zu,Father);
           
        end 
    else %best_feature>6
        C2D_value=C2Dtranlate(data1,best_feature-6,midle_data);
        featvalue = unique(C2D_value);
        featvalue_num = length(featvalue);
        for i=1:featvalue_num
            [subdata,subdata1] = splitData1(data,data1,best_feature,featvalue(i,1),C2D_value);
            [node,list,father,count] = make_tree1(node,subdata,subdata1,list,father,count,zu,Father);
        end
    end
end

%对于已经建立好的树遍历一遍,把子节点信息填入cell中
function [node] = traverse_tree(node)
    for i = 1:size(node,1)
        if(strcmp(node{i,5},'Not_yet'))
            naotaitao = cell(1,4);
            naotaitao{1,1} = '各个节点的序号是:';
            num = 0;
            for j = 1:size(node,1)
                if(node{j,2} == node{i,3})
                    num = num + 1;
                    naotaitao{1,num} = j ;
                    
                end
            end
            node{i,5} = naotaitao;
        end
    end
end

最终结果

在这里插入图片描述
在这里插入图片描述

欢迎指正,因为这个是和同学一起讨论的,同时还有很多不足,无论程序的还是这个文档的,或者很多没有必要的地方。改完下来,就是感觉大二学的那些数据结构之类的知识又回来了部分,还是练的太少。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值