决策树
- 决策树算法是机器学习中的一个基础算法,该算法有着诸多的优点。在python中实现决策树,现阶段都已经集成中到了机器学习库sklearn中,没有必要去一行一行的代码实现,可以直接调用。
- 但是为了更高的理解决策树算法,决定动手自己实践来实现决策树。
而决策数的判断条件,就是根据样本集前后的纯度差异,挑选出最佳的特征,使得分类前后,样本的纯度达到最大化的提升。 - 因此,在实现决策树之前,十分有必要,了解纯度算法的实现。
- 当然,自己码的决策树模型在MATALB上进行了实现,空闲时,会进行整理,并同内置的决策树训练函数作对比,再发出。而在python上,目前只实现了纯度算法
纯度
- 在决策树中,计算样本的纯度,一般而言有三种方法,分别为信息熵、信息熵增益以及基尼系数。在本篇中,主要实现了以基尼系数为基础的纯度计算。
- 无论是计算信息熵还是计算基尼系数,都存在一个难点,那就是需要知道样本的概率分布。对于离散型的样本,其概率分布,十分好求。但样本若是连续型的,则难点就在于此。
- 为了解决这一难题,通用的解法是,采用二分法bi-partition对连续特征进行离散化处理。
二分bi-partition
该方法的思路是,首先对某特征的M个样本进行以小到大的顺序排序,之后选取M-1个划分点,他们分别是每两个样本的中点。接着根据划分点对连续变量离散化,计算其概率分布,再根据概率分布计算基尼系数。对于M-1个划分点,就有M-1个概率分布,则有M-1个基尼系数,挑选出最小的基尼系数所对应的划分点,则为最佳划分点。(基尼系数越小,表示样本越纯净)
Python实现
为此随机设计了一组有13个样本的值为[0,1,5,4,3,4,5,6,8,7,9,0],它们依次对应的标签为[1,1,1,1,2,2,2,2,3,3,3,3]。
import numpy as np
def Impurity(X,Label,ClassNum = 3):
Len = np.size(X)
sX = np.sort(X)
Tha = np.zeros(Len-1)
gi = np.zeros(Len-1)
for i in range(Len-1):
Th = (sX[i] + sX[i+1])/2
Tha[i] = Th
idx1 = np.where(X < Th)
idx2 = np.where(X >= Th)
p = np.zeros([2,ClassNum])
g = np.zeros([1,2])
ww = np.zeros([2,1])
for Ti in range(2):
if Ti == 1:
idxTP = idx1
else:
idxTP = idx2
Lab = Label[idxTP]
for cs in np.arange(1,ClassNum+1):
if np.size(idxTP) == 0:
p[Ti,cs-1] = 0
else:
p[Ti,cs-1] = np.size(np.where(Lab == cs)) / np.size(idxTP)
g[0,Ti] = gini(p[Ti,:])
ww[Ti,0] = np.size(idxTP) / Len
gi[i] = np.dot(g,ww)
del idxTP,Lab
idxa = np.argmin(gi)
ThA = Tha[idxa]
impur = gi[idxa]
return impur,ThA
def gini(p):
# 基尼系数计算公式
if np.all(p == 0):
g = 0
else:
g = 1 - np.sum(np.square(p))
return g
X = np.array([0,1,5,4,3,4,5,6,8,7,9,0])
Label = np.array([1,1,1,1,2,2,2,2,3,3,3,3])
impur,ThA = Impurity(X,Label)
print("impurity=",impur,"Best dividing point:",ThA)
最终输出的结果
impurity= 0.444444444444 Best dividing point 6.5
为了验证以上结果的准确性,在MATLAB中也进行了检验。(先完成的MATLAB代码,并且在MATLAB中已经实现了这个决策树模型)
MATLAB实现
function [impur,ThA] = Impurity(X,Label,ClassNum,method)
%% 不纯都计算子程序
% ===============================Iuput=====================================
% X: 节点样本特征
% Label: 节点样本对应的标签
% ClassNum: 分类数 (默认 3)
% Method: 计算不纯度的方法 (gini:基尼系数...除此之外还有熵增等。默认 gini)
% ===============================Output====================================
% impur:各特征的不纯度
% ThA:对于连续特征的最佳分割点
% ===============================Info======================================
% Written by XuJiaCheng, 2017.10.08
% =========================================================================
if nargin <4,method = 'gini';end
if nargin <3,ClassNum = 2;end
Len = length(X);
sX = sort(X);
for ii = 1:Len-1
Th = ( sX(ii) + sX(ii+1) )/2;
Tha(ii) = Th;
idx1 = find(X > Th) ;
idx2 = find(X <= Th) ;
for Ti = 1 : 2
clear idxTp
switch Ti
case 1
idxTp = idx1;
case 2
idxTp = idx2;
end
clear Lab
Lab = Label(idxTp);
for kk = 1 :ClassNum
p(kk,Ti) = length( find( Lab == kk)) ./ length(idxTp) ;
end
end
switch method
case 'gini'
w = [length(idx1) length(idx2)] ./ Len;
gi = [gini(p(:,1));gini(p(:,2))];
imp(ii) = w * gi;
case 'entropy'
end
end
switch method
case 'gini'
[impur, I] = min(imp);
ThA = Tha(I);
case 'entropy'
impur = max(imp);
end
end
function gi = gini(p)
%% 基尼系数计算子程序
% ===============================Iuput=====================================
% p: 概率分布
% ===============================Ouput=====================================
% gi:基尼系数
% ===============================Info======================================
% Written by XuJiaCheng, 2017.10.08
% =========================================================================
if all(p==0)
gi = 0;
else
gi = 1 - sum(power(p,2));
end
end
输出结果:
disp(['基尼系数=',num2str( impur ),' 最佳划分点:',num2str(ThA)])
基尼系数=0.44444 最佳划分点:6.5
参考文章
- 数据挖掘十大算法之决策树详解