其實,之前就接觸過隨機森林,但僅僅是用來做分類和回歸。最近,因為要實現一個idea,想到用隨機森林做ensemble learning才具體的來看其理論知識。隨機森林主要是用到決策樹的理論,也就是用決策樹來對特征進行選擇。而在特征選擇的過程中用到的是熵的概念,其主要實現算法有ID3和C4.5.下面我們先來看看決策樹。
下面我們用一個例子具體的來說明
我們要選取一個最好的特征來判斷是否貸款,上面給出了年齡,工作,房子,信貸四種特征。如果一種特征具有更好的分類能力,或者說,按照這一特征將訓練數據集分割成子集,使得各個子集是當前條件下最好的分類,我們就應該選擇這個特征。對於這個問題,直觀上是否有房子應該是最好的特征。但這也僅僅是從直觀上判斷,具體上來講哪個特征最好了,這里我們引入一個概念-信息增益。
假設X是一個取值無限的離散隨機變量,其概率分布為:
由於熵只依賴X的分布,而與X的取值無關。所以,我們又把熵定義為:
![]()
假設我們有兩個隨機變量x,y(generally,X denote the feature vectors,and Y denote labels)。其聯合概率分布為:
這里,假如給定一個X,要我們准確的判斷其所屬類別,也就是要准確的判斷Y。很自然的,我們需要求解給定X下的條件熵:
假設,特征A 對訓練集D的信息增益為
,定義為集合D 的經驗熵H(D)與特征A給定條件下D的經驗熵H(D|A)之差,那么我們定義信息增益如下:
一般的,我們把熵H(Y)與條件熵H(Y|X)只差定義為互信息,決策樹中的信息增益就是訓練數據集中的類與特征的互信息。下面給出計算信息增益的方法:
如果我們以信息增益為划分訓練數據集的特征,存在於選擇取值較多的特征的問題。這里我們使用信息增益比(information gain ratio),可以對這一問題進行校正。這是特征選擇的另一准則。
下面來介紹一下ID3算法,該算法的核心就是不斷的利用信息增益准則選擇特征,最終達到分類的目的。
C4.5算法其實就是在ID3算法上做了一點的改動,把特征選擇的方法改為用信息增益比來計算,而不用ID3中的計算信息增益的方法。其算法流程和ID3差不多,這里就不介紹了。下面來簡單的談一下決策樹的剪枝問題,由於決策樹是嚴格的按照一定的規則進行計算,過多的考慮了訓練樣本的正確性,所以這導致其容易過擬合。所以這里引入剪枝的概念,通過優化損失函數,減少模型的復雜性。具體算法過程可以看課本P-66~P-67頁。
下面我給出C4.5的matlab代碼,改代碼轉自http://blog.csdn.net/ice110956/article/details/10049149。
1: function D = C4_5(train_features, train_targets, inc_node,test_features)
2: %http://blog.csdn.net/ice110956/article/details/10049149
3: % 1.train_features,為訓練集; train_targets,為訓練集標簽;
4: % inc_node為防止過擬合參數,表示樣本數小於一定閾值結束遞歸,可設置為5-10;test_features為測試集。
5: % 2.取消離散變量,上面說了,是因為我不知道如何處理Miss value的問題,至於影響,應該就是連貪心也算不上了吧,應該是一個理論上還過得去的處理方法。
6: % 3.圖怎么畫?介紹幾個畫圖軟件:http://www.cnblogs.com/damonlan/archive/2012/03/29/2410301.html
7: % 決策樹擴展篇:http://blog.csdn.net/ice110956/article/details/29175215
8:
9: [Ni, M] = size(train_features); %輸入向量為NI*M的矩陣,其中M表示訓練樣本個數,Ni為特征維數維數
10: inc_node = inc_node*M/100;
11:
12: disp('Building tree')
13: tree = make_tree(train_features, train_targets, inc_node);
14:
15: %Make the decision region according to the tree %根據產生的數產生決策域
16: disp('Building decision surface using the tree')
17: [n,m]=size(test_features);
18: targets = use_tree(test_features, 1:m, tree, unique(train_targets)); %target里包含了對應的測試樣本分類所得的類別數
19:
20: D = targets;
21: %END
22:
23: function targets = use_tree(features, indices, tree, Uc) %target里包含了對應的測試樣本分類所得的類別
24:
25:
26: targets = zeros(1, size(features,2)); %1*M的向量
27:
28: if (tree.dim == 0)
29: %Reached the end of the tree
30: targets(indices) = tree.child;
31: return %child里面包含了類別信息,indeces包含了測試樣本中當前測試的樣本索引
32: end
33:
34:
35: dim = tree.dim; %當前節點的特征參數
36: dims= 1:size(features,1); %dims為1-特征維數的向量
37:
38: %Discrete feature
39: in = indices(find(features(dim, indices) <= tree.split_loc)); %in為左子樹在原矩陣的index
40: targets = targets + use_tree(features(dims, :), in, tree.child_1, Uc);
41:
42: in = indices(find(features(dim, indices) > tree.split_loc)); %in為右子樹在原矩陣的index
43: targets = targets + use_tree(features(dims, :), in, tree.child_2, Uc);
44: return
45:
46:
47: function tree = make_tree(features, targets, inc_node)
48:
49: [Ni, L] = size(features);
50: Uc = unique(targets); %UC表示類別數
51: tree.dim = 0; %樹的維度為0
52: %tree.child(1:maxNbin) = zeros(1,maxNbin);
53:
54: if isempty(features), %如果特征為空,退出
55: return
56: end
57:
58: %When to stop: If the dimension is one or the number of examples is small
59: if ((inc_node > L) | (L == 1) | (length(Uc) == 1)), %剩余訓練集只剩一個,或太小,小於inc_node,或只剩一類,退出
60: H = hist(targets, length(Uc)); %返回類別數的直方圖
61: [m, largest] = max(H); %更大的一類,m為大的值,即個數,largest為位置,即類別的位置
62: tree.child = Uc(largest); %直接返回其中更大的一類作為其類別
63: return
64: end
65:
66: %Compute the node's I
67: %計算現有的信息量(經驗熵)
68: for i = 1:length(Uc),
69: Pnode(i) = length(find(targets == Uc(i))) / L;
70: end
71: Inode = -sum(Pnode.*log(Pnode)/log(2));
72:
73: %For each dimension, compute the gain ratio impurity
74: %This is done separately for discrete and continuous features
75: delta_Ib = zeros(1, Ni);
76: S=[];
77: for i = 1:Ni,
78: data = features(i,:);
79: temp=unique(data);
80: P = zeros(length(Uc), 2);
81:
82: %Sort the features
83: [sorted_data, indices] = sort(data);
84: sorted_targets = targets(indices);
85: %結果為排序后的特征和類別
86: %Calculate the information for each possible split
87: I = zeros(1, L-1);
88:
89: for j = 1:L-1,
90: for k =1:length(Uc),
91: P(k,1) = length(find(sorted_targets(1:j) == Uc(k))); %p(1,1):小於第j個樣本的b的個數,p(1,2):大於第j個樣本的b的個數。
92: P(k,2) = length(find(sorted_targets(j+1:end) == Uc(k))); %p(2,1):小於第j個樣本的g的個數,p(1,2):大於第j個樣本的g的個數。
93: end
94: Ps = sum(P)/L; %兩個子樹的權重
95: temp1=[P(:,1)];
96: temp2=[P(:,2)];
97: fo=[Info(temp1),Info(temp2)];
98: %info = sum(-P.*log(eps+P)/log(2)); %兩個子樹的I
99: I(j) = Inode - sum(fo.*Ps);%信息增益
100: end
101: [delta_Ib(i), s] = max(I);
102: S=[S,s];
103:
104: end
105:
106: %Find the dimension minimizing delta_Ib
107: %找到最大的划分方法
108: [m, dim] = max(delta_Ib); %第dim維特征最好,最大信息增益為m
109:
110: dims = 1:Ni;
111: tree.dim = dim;
112:
113: %Split along the 'dim' dimension
114: %分裂樹
115: %Continuous feature
116: [sorted_data, indices] = sort(features(dim,:));
117: %tree.split_loc = split_loc(dim);
118: %disp(tree.split_loc);
119: S(dim)
120: indices1=indices(1:S(dim))
121: indices2=indices(S(dim)+1:end)
122: tree.split_loc=sorted_data(S(dim))
123: tree.child_1 = make_tree(features(dims, indices1), targets(indices1), inc_node);
124: tree.child_2 = make_tree(features(dims, indices2), targets(indices2), inc_node);
125: %D = C4_5_new(train_features, train_targets, inc_node);
其實代碼不難,下面我給出我的理解。
Here we split the data into two sets,with 300 training samples and 51 testing samples,each data is a 34-dimensional vector. Here, each dimension can be regarded as a variable,with respect to a kind of “feature”.
在這個決策樹中,對每個節點我們計算它的信息增益比,如果信息增益比小於某個閾值。或者,節點包含的樣本數小於18(自己設定),則結束遞歸。從上圖中可以看出,從根節點出發(這個節點包含300個樣本),第5維特征最好,所以用這個特征進行划分。得到左子樹(57個樣本全為“1”),右子樹(包含243個樣本)。所以左子樹結束遞歸,接着計算右子樹的特征,第27維特征最好。一直循環….
最后我們得到這樣的一個決策樹,除了葉節點,中間節點都包含一個最佳分類的特征,和這個特征對應的特征值。每個葉節點包含一定數量的樣本,葉節點的類別規定為多數樣本對應的類別。得到了這樣的一個決策樹后,我們就可以對測試樣本進行分類了。使用中間節點記錄的特征對測試樣本進行划分,直到測試樣本划分到每個葉節點中。葉節點中樣本的類別就是該測試樣本的類別了。







