" ^! z8 [' f6 l" W9 `%分为训练集和测试集5 I1 u* H4 K* U* |) C; _
x_train = watermelon(1:size_data(1)-2, %这里加上了属性标签行 & {# S- Y/ W; P2 O0 Xx_test = watermelon(size_data(1)-1:end,1:size_data(2)-1); %选择最后两个当测试集 8 y8 z) x4 R0 p) g ) s* G) B3 K: F/ i/ k: {- |$ m3 l' z) y' Z3 j' Y9 o5 S
%训练/ D- D$ I) o4 P$ z3 Y
size_data = size(x_train);) I* V6 R2 \8 V N
dataset = x_train(2:size_data(1),; %纯数据集 4 O( A+ d- l. f: U4 W; plabels = x_train(1,1:size_data(2)-1); %属性标签 5 h+ Y5 r3 X$ F/ I. M0 O 1 \8 x3 n8 { b7 C/ H 7 c; {+ h) y4 T/ X! z1 n%生成决策树 : k7 m' Z" c! q" k, m& Gmytree = ID3(dataset,labels);' o! b. S1 {6 N9 `
[nodeids,nodevalue,branchvalue] = print_tree(mytree);" u; [* a7 S/ J4 V6 Y6 s
tree_plot(nodeids,nodevalue,branchvalue);, k. r* v- r( R5 N! t( L- z2 y2 C
predict(x_test,mytree,x_train(1,1:end-1)) ' H0 [ T! B( m, o. e0 H ( Z( U; A/ ?% o1 l2 `/ n" l 构建决策树代码如下:6 ?7 }1 t5 {' Z7 _0 D, a
`. G1 Q7 \& B) w8 l' N" R
function myTree = ID3(dataset,labels)# x: y7 e0 O% S0 E2 h' w9 R3 ?
% ID3算法构建决策树; a- O; \1 ^6 a5 r+ U( A
% 输入参数:! d4 G0 g2 x2 r4 A, P- v* R
% dataset:数据集 0 P2 Q& [5 H& a% labels:属性标签6 H9 @6 b8 p: ~& I; r9 d9 E
% 输出参数: 6 M$ ]$ \ T; [, F% tree:构建的决策树 6 B3 z9 h( m% t* Z7 ~0 O. Xsize_data = size(dataset);6 F# J# y6 ^ C! g$ h0 n
classList = dataset(:,size_data(2)); %得到标签# q; |! Y& \5 Q$ ^+ P+ m
% ~ b2 \' J# ]3 @1 W; C
%全为同一类,熵为0 : ?5 E4 u/ ~( c Hif length(unique(classList))==1 - o4 z! R C/ u( @/ s) t myTree = char(classList(1));" v5 x' u5 ?# B: C) [
return 8 r* \2 o: T0 M1 A S8 h) aend3 Z) B0 x1 I6 Y
; V* U( r' r2 t( C%去除完全相同的属性,避免产生没有分类结果的节点 ' ?2 u8 M) {; ~' m3 s6 ^% choose=ones(1,size_data(2)); ; m. T+ x" s/ B- k8 h, n) s- E' g$ `% for i=1size_data(2)-1) 1 }+ ?. s" c; S9 e% featValues = dataset(:,i);" J; W9 `: u- a, `' z+ c+ W2 r
% uniqueVals = unique(featValues); - r# M6 B4 E9 w/ b2 f0 b% if(length(uniqueVals)<=1). a3 S+ Z5 k i& u
% choose(i)=0; $ E/ b: G/ e8 X* ^2 k2 }4 D3 Y$ t% end , v/ c% V4 q2 {, I% end # a- W7 I" B' ~6 P1 W( V8 H& g# @! D% labels=labels((choose(1:size_data(2)-1))==1);' {' K) s# C) c/ y) ~
% dataset=dataset(:,choose==1); ! W* P% m1 {+ Z" L1 N& J5 U" [8 U; P- [7 c3 t- d
size_data = size(dataset);+ m' l; }& [: `# Z# V; _6 t( [( I8 r
classList = dataset(:,size_data(2)); 6 x# [2 n. y: S ' o1 k1 d* Y* l2 q2 s( Q%%属性集为空,用找最多数 # u# J4 W9 z) v1 Rif size_data(2) == 1 ; k# Q0 j7 l6 _, w, c) B5 U temp=tabulate(classList); ; t( i8 I- u, }- h ~# n5 u value=temp(:,1); %属性值 % H. I, v" e: n; x" F2 C% B count=cell2mat(temp(:,2)); %不同属性值的各自数量 ) p+ |0 F0 ]) z index=find(max(count)==count); , u* H& x$ \7 i# S! e0 s choose=index(randi(length(index)));0 B+ F. O' B) c1 \: F2 {9 y1 c! X: ~4 b
myTree = char(value(choose));4 v$ R8 D) B2 ~; l, X" P
return- [2 D' n- b6 D- u6 f9 v* O
end# s: D: v; M) J, A
& ~3 I7 ~" o" t7 G+ B! V- }1 S
%bestFeature = chooseFeature(dataset); %找到信息增益最大的特征, \2 A m8 k3 F7 p( Q
bestFeature = chooseFeatureGini(dataset); %找到信息增益最大的特征 . j0 X$ ^7 t2 \; i$ h" c: \bestFeatureLabel = char(labels(bestFeature)); %得到信息增益最大的特征的名字,即为接下来要删除的特征 ) ], w1 L: \' @ |4 m6 m0 Q, K) R+ u- lmyTree = containers.Map; / O! D/ y3 V2 q; r1 Tleaf = containers.Map; 9 Z. N9 U) A1 I& yfeatValues = dataset(:,bestFeature);( w6 o. V" d& F3 H
uniqueVals = unique(featValues); % w' @) \' u0 j" [3 R , s7 f3 X) n+ g$ llabels=[labels(1:bestFeature-1) labels(bestFeature+1:length(labels))]; %删除该特征 $ ~: X H6 @$ |( I7 G, A) _' R+ t6 r# H( p$ |+ {& w
%形成递归,一个特征的按每个类别再往下分7 I' v' ?; P- ~, K) ~ B
for i=1:length(uniqueVals)1 f! F" _- c, e! B
subLabels = labels('; - c) `# v) _0 R value = char(uniqueVals(i));+ z! F+ J' i& p
subdata = splitDataset(dataset,bestFeature,value); %取出该特征值为value的所有样本,并去除该属性 + E, k4 W/ g6 v' |' m5 z/ w) q: i& _ leaf(value) = ID3(subdata,subLabels); 6 g! ] m- ]8 w4 G myTree(char(bestFeatureLabel)) = leaf; 5 V1 \' G2 M" C3 qend0 ]' I- Q% s4 S
$ O5 q1 B7 ^& o. Jend) F; a0 I( ?/ y u: h* `* J& c0 r g
( j! V7 @0 m7 Y9 X; O
构建决策树过程中根据基尼指数选择特征的代码: + e; W: m4 l% |8 X- g' N1 _ & m/ C6 A8 C4 o8 J7 _9 zfunction bestFeature=chooseFeatureGini(dataset,~)/ l5 n; [5 z0 b# S* G: O0 l' Q/ t
% 选择基尼指数最小的属性特征3 G' m% j+ ^" i+ p4 B' U( ~* P
) n3 ?4 j' g( U, [6 }
%数据预处理 / L9 T! Q, T) C[N,M]=size(dataset); %样本数量N7 W x2 K, l8 s. a) E0 k
M=M-1; %特征个数M 2 i3 ~) g5 M- m! H: ^* b& [y=strcmp(dataset(:,M+1),dataset(1,M+1)); %标签y(以第一个标签为1) 4 l. h. ]7 U, G2 ^x=dataset(:,1:M); %数据x/ ]4 s7 S9 ~; h& {6 ~: d
Gini_index = zeros(1,M); %创建一个数组,用于储存每个特征的信息增益# Y% U* f: R7 ]( v
%bestFeature; %最大基尼系数的特征 0 Q7 c+ f: b, ~7 _4 h2 r* p+ R; k9 }8 e5 o0 p9 o
%计算基尼指数 2 x; P1 P/ ^7 f9 z1 S% wfor i=1:M 9 W! H, ^, ?( p+ C1 m3 ^ % 计算第i种属性的基尼指数4 o' H9 c% u3 Y6 k; h+ h5 q& ~
temp=tabulate(x(:,i)); # n: |- k# X, B% K. m value=temp(:,1); %属性值 ' S* i8 Y8 L a( i. w+ s count=cell2mat(temp(:,2)); %不同属性值的各自数量 p( L+ r) y4 z1 K1 O* }
Kind_Num=length(value); %取值数目 : }4 F8 y1 G* r1 l4 v. N Gini=zeros(Kind_Num,1);3 Y8 k# c5 L" t: r" l5 [* x
% i属性下 j取值的基尼指数' g; ?% P r3 K# Z1 M. n
for j=1:Kind_Num " O- G* `; ^3 [ % 在第j种取值下正例的数目; R, K6 [+ ]6 q, x F
Gini(j)= getGini( y(strcmp(x(:,i),value(j))) );: E) @" q6 I! ~: i* U6 J( C" I
end 4 k" @3 U" B9 e+ P0 q Gini_index(i)=count'/N*Gini; + y& B; s; I& rend 3 Y( O- T8 B7 L2 l2 a%随机挑选一个最小值. D; ?& Z" M% p+ [2 f3 H
min_GiniIndex=find(Gini_index==min(Gini_index));6 Q' v+ r8 X1 j
choose=randi(length(min_GiniIndex)); ! k$ d: f+ z" ]bestFeature=min_GiniIndex(choose); 9 x7 Q8 \1 j3 z0 o* d! |: f V0 wend/ R, N' c, k3 \) L' @2 z; m
6 `; X. Y+ l- V计算基尼指数的代码如下:6 o5 D- L/ `# i$ V
% J! t3 F0 x- l* ?' H) efunction Gini = getGini(y)( \. T, o- j4 ~$ q9 _
% 计算基尼系数 : F; L9 a" j% D7 u S6 ^2 A% y对应的标签,为1或0,对应正例与反例, P$ ?/ h' R+ T1 T3 P
%%%%%%===============================================================================( N- j V/ q4 v2 J
N=length(y); %标签长度 $ c4 x: _2 N8 t% J O0 S P_T=sum(y)/N; %正例概率 2 @0 T- n. J7 v g/ u( e2 V/ e P_F=1-P_T; %正例概率3 t3 p8 d6 B) \1 F' g4 ?
Gini=1-P_T*P_T-P_F*P_F; %基尼系数 / P2 T! R$ \1 v ~3 S8 H, G%%%%%%===============================================================================: D" I& T! K% ~6 E
end0 b' ], P8 q! o; [0 Y2 y
构造决策树的过程中,划分数据集的方法: 7 ^9 r$ Q2 w7 P: G+ c" I& y9 k1 X- I
function subDataset = splitDataset(dataset,axis,value) L& k# K, _6 D2 o# ]0 ?2 `; q%划分数据集,axis为某特征列, 取出该特征值为value的所有样本,并去除该属性" O1 U; x& q/ g; o3 x. S, s
# Y. J* u+ s) u5 }# w$ \+ Y
subDataset = {}; 9 B3 F# Y2 k5 l4 ~, G5 T N, Bdata_size = size(dataset);8 I: B+ E' i; i/ W
6 p5 Y( Z( g- ?. s" [& [
%取 该特征列 该属性 对应的数据集1 ^/ `0 a2 `9 t2 z7 v) m6 h
for i=1:data_size(1) - }; ~8 m7 B- z! P data = dataset(i,;' S3 G4 N( W6 d
if strcmp(cellstr(data(axis)),cellstr(value))8 k j# `# [4 Y6 e: z
subDataset = [subDataset;[data(1:axis-1) data(axis+1:length(data))]]; %取 该特征列 该属性 对应的数据集( f6 K: A7 O d2 x$ ~5 Z' `9 V
end ' m9 Y6 F. r1 P5 t. p" q/ send : N9 t" `, y: @7 ]2 d2 U/ L7 bend " M4 z& `# N R7 R7 I遍历决策树的方法:! s* y4 d# f! W( U# U' K2 L
w i- E0 `- G& I/ vfunction [nodeids_,nodevalue_,branchvalue_] = print_tree(tree). `9 _! G8 b% x4 f, Q8 `
% 层序遍历决策树,返回nodeids(节点关系),nodevalue(节点信息),branchvalue(枝干信息) C/ Q/ I2 a [
nodeids(1) = 0;4 K& s1 v8 n! X( S" H
nodeid = 0;, C; s' p5 q( s2 D1 v
nodevalue={}; ; e: A \' u' b( dbranchvalue={};$ w6 ~& E( M) z
4 \ E$ x6 j1 c% l. p1 H
queue = {tree} ; %形成队列,一个一个进去" I) p* V, D% n! T3 n
while ~isempty(queue) + q7 d2 _6 U4 ^9 w$ B' {9 D node = queue{1}; 3 J) m8 } I4 w1 U$ u3 P queue(1) = []; %在队列中除去该节点2 V3 u' k% V3 a7 t& r$ v) w! Z
if strcmp(cellstr(class(node)),'containers.Map') == 0 %叶节点的话(即走到底了)* ^' X: @* W% E0 l) U, Q9 K* H
nodeid = nodeid+1; " H5 h! U# w. D* }1 y9 z nodevalue = [nodevalue,{node}]; ! j$ N: h1 o- X9 o6 h; [7 X elseif length(node.keys)==1 %节点的话" T2 X3 q( Q4 j- z% P
nodevalue = [nodevalue,node.keys]; %储存该节点名 9 _) k! ?- ?# ?8 o0 t$ D) B node_info = node(char(node.keys)); %储存该节点下的属性对应的map : M+ p" T" b& z! g* k nodeid = nodeid+1; 9 j3 @/ N. ~+ b9 B. B branchvalue = [branchvalue,node_info.keys]; %每个节点下的属性 % i% ]1 j/ h* @+ ~4 L for i=1:length(node_info.keys)! q1 q/ E, S t
nodeids = [nodeids,nodeid]; 2 f* q+ N( b$ E( |' a, H end6 p6 t) q$ R' g# o+ Z5 i
end! E% t8 \' n0 M
+ j& h2 H1 Q% k- f# U if strcmp(cellstr(class(node)),'containers.Map') , s# P" n0 _) c5 J2 | keys = node.keys();# Z# s$ {+ G# f$ m
for i = 1:length(keys) ! y! ^$ o. B" f: k& V( B2 n9 ]4 l6 t key = keys{i};7 |. C! P0 |6 A* |1 D9 e- m9 h
queue=[queue,{node(key)}]; %队列变成该节点下面的节点 7 U( q, `3 @1 p( j4 O end+ a }* `8 T/ S( R/ _5 R
end' f4 k" {3 a+ z4 |- @
nodeids_=nodeids; * m* H5 R8 b! p- unodevalue_=nodevalue;: }# z/ A: r( L7 f' p3 y
branchvalue_ = branchvalue; & e9 L3 p7 U, f8 U! Lend \5 u* `$ T' u# r8 @ - ?7 [& Y* L- P8 s) p* H绘制决策树的方法: 6 `- g! a) _* m$ f0 Y- W e ) w6 M# f3 @, i& B! d3 l* L3 d+ u* p5 F$ T5 D* h3 I
function tree_plot(p,nodevalue,branchvalue) * T" }$ }- T7 Y4 h6 \2 u _) D% 参考treeplot 3 ] P7 q7 g. O/ |# @& l2 q1 D. l ) j6 e8 R& e3 O* I[x,y,h] = treelayout(p); %x:横坐标,y:纵坐标;h:树的深度# ^3 `/ z+ Y$ z8 F
f = find(p~=0); %非0节点; ]$ o4 a" I! q2 d T/ t' C, ~
pp = p(f); %非0值1 p9 m% d. I" w/ R
X = [x(f); x(pp); NaN(size(f))]; 4 \( A0 j$ [8 {9 _- ^Y = [y(f); y(pp); NaN(size(f))];- a8 u/ N$ Z9 n7 r5 k
+ ^& k& {$ F1 d, wX = X(; 1 `* Z9 k* D, jY = Y(;9 N+ Q- `& X. E. m N V
" r2 r+ c4 h% g6 p' In = length(p); " z6 t' ?3 e9 a X* ~" lif n<500# I9 D8 X# e) m7 `" S+ d
hold on; 1 _6 s9 ^. U0 N( Q! z) ]0 m plot(x,y,'ro',X,Y,'r-'). M' k, E5 I% M4 U# l
nodesize = length(x); " L% `% [" q, N Y for i=1:nodesize 2 o' ~1 {$ ?7 O text(x(i)+0.01,y(i),nodevalue{1,i}); ; I& v% L2 `4 F
end 1 K; j E) v6 J4 H i) g6 _ for i=2:nodesize6 u" Z5 O2 ?2 i. @
j = 3*i-5; " t' S3 i, f' h text((X(j)+X(j+1))/2-length(char(branchvalue{1,i-1}))/200,(Y(j)+Y(j+1))/2,branchvalue{1,i-1}) 8 x. z, ?8 Y' n5 ?4 [. o% { end ' T2 ~4 O5 z3 z3 M. [% D& h hold off & J7 o( W4 ~) ?! Felse ) M$ `" j7 M$ M! N' y( l plot(X,Y,'r-');, p1 k- A6 {; ]" j7 {
end * ^) B4 r" j' p9 O, Hxlabel(['height = ' int2str(h)]);( y2 @& |& Y: [$ c
axis([0 1 0 1]); ; k/ X6 C5 }! m5 v- |end & p( [2 a2 m: w1 i! u2 ] ' ]3 c. B2 A" f2 s7 c: \2 @测试集进行预测的方法: % c1 a7 U4 Z) [+ R5 m1 K* ? ) K! r% S0 [& a2 m$ i1 y* Ufunction y_test=predict(x_test,mytree,feature_list) * ~8 k3 a: |/ i- m1 u%测试 ( @ H, _# V: e - d, P' G* K; h; d! v- t qy_test = {};3 S0 R" Q- L8 {, E5 w
row = size(x_test); 4 p% z4 Y% r1 N: `6 G2 q 9 ]% K% Y% |. U4 t- p4 D/ L3 I ; c1 g+ `7 _' `: \7 l! ~! y+ i$ gfor j= 1:row(1): A! W' [1 s$ n3 O
queue = {mytree}; %形成队列,一个一个进去( C+ M5 l4 a; |3 q
feature_name = 0;- S e# m; S1 G/ w) n( s$ n
feature = 0;7 C: _+ Z) F) E
2 F9 T& N$ m7 F# I, _: m while ~isempty(queue), W5 w9 ~8 H% E) s$ S
node = queue{1}; . z5 \" B% W% g4 b0 u& | queue(1) = []; %在队列中除去该节点/ D1 O4 C) T# M, F
* ^2 S4 l1 H/ `8 [3 L {5 ?
tag = 2; 3 O7 w8 R y# y/ j if strcmp(cellstr(class(node)),'containers.Map') == 0%叶节点的话(即走到底了)- d5 [- e% z9 u% B2 c5 R
y_test{j} = node; %走到底就是我们需要的标签! }3 t7 z0 \, p7 U& ^" A
continue " a" {8 c3 t( x7 [( |6 @ j elseif length(node.keys)==1 %节点的话 4 j" ]0 g- u3 F4 H feature_name = char(node.keys); %得到mytree节点的名字, H5 R0 Y: j: Y$ d3 o$ b
id = ismember(feature_list,feature_name); %mytree该特征所在的坐标 8 X; }+ C* J0 M8 W$ Z/ D0 H x = x_test(j,; + f; A: O$ j- @8 m. d# h. D feature = x(id); %得到测试数据的特征属性1 G5 D/ I! f+ m" ~! M
tag = 1; 1 t" F% q! }. ~, ]# V" Q1 N7 H
end. T- U- f. ]9 M; R, J* c+ b
# _$ i# H6 ~' i8 w9 O
" q3 U' ]; z% C1 ? %tag==2 即要走入下个节点% l* D+ l# F1 d( [% Y2 h
if tag==2 # W& O8 |( ]* |( f& [ if strcmp(cellstr(class(node)),'containers.Map') 8 D% \6 e$ ]0 k2 J3 V hasKeys=0; 0 [; C9 I( M. h, h w) B7 G$ _ keys = node.keys();5 D0 b8 X' I/ P
for i = 1:length(keys): C% S& k2 }7 q4 f w; r5 [
key = keys{i}; ]$ ~5 K) f, s5 U c = char(feature);- G2 l4 |. h7 p7 R/ R
if strcmp(key,c) / J# L9 @* T& J: X3 \ queue=[queue,{node(key)}]; %队列变成该节点下面的节点 ! n f! ?7 F# ]& q M; ]5 @ hasKeys=1; # X" K9 p! A* B; e% _- s" H1 G2 e end 1 Q% P8 i( I: |/ m( X+ g: a: s end/ h# {+ k2 K m$ \) I' C
if(~hasKeys)5 B9 x2 a4 a$ M
key = keys{randi(length(keys))};! ]- U1 ]& ?5 Z: A; O7 J( S; g3 }# I
queue=[queue,{node(key)}]; %队列变成该节点下面的节点$ N E5 g% L9 ^+ \6 ~
end8 p7 B! ]7 D* G4 I6 [( w
end9 h9 Q9 A# s1 L! x# s4 a
end2 _. ]8 O/ [+ X, {) X
9 R( m+ @4 `1 { %tag==1 即要选则符合测试数据的特征属性,这样就不用历遍整个mytree 3 g) I) @8 |. \ if tag==1 , g. i( Z& j/ U/ A if strcmp(cellstr(class(node)),'containers.Map'), ^5 A! i. A" |
keys = node.keys(); 2 l& {9 K7 X: L4 f for i = 1:length(keys) ! R# G* n3 }& j" ?1 q; H key = keys{i}; : g# |2 w9 C# ~% c- [ queue=[queue,{node(key)}]; %队列变成该节点下面的节点 - `+ a A' I( @5 z& j# x3 I end ' |' Z5 u0 c- N- s8 R! \3 C% ]- V' \ end , d) N) B. `! S+ n! d' t1 }# s end * b4 h" a( a: a- H' {: C end, _5 u) {7 ^: C
if length(y_test)<j ( c6 o6 u1 |$ u" i! L test=1;/ k" d! L, j( g" a6 m1 v% i& d
end' j0 M$ _$ z# [& Y N# q
end 8 P, W) C4 H4 Q* B$ [, y2 S* f. h, ]9 u3 s
end 4 u/ ]- T' x5 U % t1 d0 @6 @" k* h% |二、随机森林) ^. P" } i. X
2.1、随机森林的算法原理& I! K' O( p- O2 ~
我们首先看卡集成算法,也可以叫集成学习,目的是让机器的学习效果更好,常见的又bagging,boosting和stacking,其中bagging是训练多个取平均值,boosting是训练多个组合加权,stacking是聚合多个分类,就是融合多个算法。+ h- g. S1 m5 j) {! y2 I- j
* ]* A4 D$ a f, R! h; D- G
# e. }+ v% n% S' X4 c, @ 3 P. C& o! X" M, [% p& p 我们看一下Bagging模型,典型的Bagging模型就是随机森林,并行的训练一堆分类器,数据随机采样,特征选择随机,建立多个决策树,即多个分类器,将多个分类器放到一起就组成了森林。3 h' q6 Y4 m$ E! q
* e+ K* a' R2 m* C0 j% b; v8 w6 | 9 [6 Y4 | ]/ ~) d8 C + y' d/ P0 G1 x8 C/ B& H通过2重随机性,就是随机采样,随机获取特征,使得构造的决策树具有多样性,最后的平均才能取得更好的效果,更具有说服力。1 a( \ v% F3 X
$ L p, N, R# ~( t; d6 d: N
% U! U( E0 Z7 z( s2 p! }
- P4 c1 U2 [3 [6 Y' d3 U+ i4 a5 V8 @2.2、随机森林的优势与特征重要指标- N& E9 h: o5 k& G. R8 k
随机森林的可解释性很强,神经网络虽然也可以用来预测和分类,但是神经网络的隐含层不具有可解释性,我们只知道输入和输出,具体内部怎么做的,细节无从得知。随机森林方便进行可视化展示,可以自动做特征筛选,并行速度较快。 * z3 M! d( q. d9 w7 ?9 m: y2 W3 u) F4 v5 D1 L
$ g' H' J) K' D/ E4 U1 J