1.什么是隨機森林
簡述
隨機森林是一個高度靈活的機器學習方法,擁有廣泛的應用前景,從市場營銷到醫療保健保險。 既可以用來做市場營銷模擬的建模,統計客戶來源,保留和流失。也可用來預測疾病的風險和病患者的易感性。
隨機森林是一個可做能夠回歸和分類。 它具備處理大數據的特性,而且它有助於估計或變量是非常重要的基礎數據建模。
隨機 森林 是 幾乎 任何 預測 問題 (甚至 非直線 部分) 的固有 選擇 。 它是 一個 相對較 新 的 機器 學習 的策略 ( 在90 年代產生於 貝爾 實驗室 ) 和 它 可以 幾乎用於 任何方面 。
思想
隨機森林就是通過集成學習的思想將多棵樹集成的一種算法,它的基本單元是決策樹,而它的本質屬於機器學習的一大分支——集成學習(Ensemble Learning)方法。隨機森林的名稱中有兩個關鍵詞,一個是“隨機”,一個就是“森林”。“森林”我們很好理解,一棵叫做樹,那么成百上千棵就可以叫做森林了,這樣的比喻還是很貼切的,其實這也是隨機森林的主要思想--集成思想的體現。“隨機”的含義我們會在下邊部分講到。
其實從直觀角度來解釋,每棵決策樹都是一個分類器(假設現在針對的是分類問題),那么對於一個輸入樣本,N棵樹會有N個分類結果。而隨機森林集成了所有的分類投票結果,將投票次數最多的類別指定為最終的輸出,這就是一種最簡單的 Bagging 思想。
2.相關知識
集成學習
集成學習通過建立幾個模型組合的來解決單一預測問題。它的工作原理是生成多個分類器/模型,各自獨立地學習和作出預測。這些預測最后結合成單預測,因此優於任何一個單分類的做出預測。
隨機森林是集成學習的一個子類,由於它依靠於策率樹的合並。
信息、熵以及信息增益的概念
這三個基本概念是決策樹的根本,是決策樹利用特征來分類時,確定特征選取順序的依據。理解了它們,決策樹你也就了解了大概。
引用香農的話來說,信息是用來消除隨機不確定性的東西。當然這句話雖然經典,但是還是很難去搞明白這種東西到底是個什么樣,可能在不同的地方來說,指的東西又不一樣。對於機器學習中的決策樹而言,如果帶分類的事物集合可以划分為多個類別當中,則某個類(xi)的信息可以定義如下:
I(x)用來表示隨機變量的信息,p(xi)指是當xi發生時的概率。
- 熵是用來度量不確定性的,當熵越大,X=xi的不確定性越大,反之越小。對於機器學習中的分類問題而言,熵越大即這個類別的不確定性更大,反之越小。
- 信息增益在決策樹算法中是用來選擇特征的指標,信息增益越大,則這個特征的選擇性越好。
這方面的內容不再細述,感興趣的同學可以看 信息&熵&信息增益 這篇博文。
決策樹
決策樹是一種樹形結構,其中每個內部節點表示一個屬性上的測試,每個分支代表一個測試輸出,每個葉節點代表一種類別。常見的決策樹算法有C4.5、ID3和CART。
隨機決策樹
我們知道隨機森林是其他的模型聚合, 但它聚合了什么類型模型 ?你可能已經從其名稱 、隨機森林聚合分類(或回歸)的樹中猜到。決策樹是由一系列的決策的組合,可用於分類觀察數據集 。
隨機森林
算法引入了一個隨機森林來自動創建隨機決策樹群 。 由於樹隨機生成的樹,大部分的樹(或許 99.9%樹)不會對學習的分類/回歸問題都有意義 。
如果 觀察到 長度 為 45 ,藍 眼睛 , 和 2 條腿 , 就 被 歸類 為 紅色 。
3.隨機森林的特點
前邊提到,隨機森林是一種很靈活實用的方法,它有如下幾個特點:
- 在當前所有算法中,具有極好的准確率
- 能夠有效地運行在大數據集上
- 能夠處理具有高維特征的輸入樣本,而且不需要降維
- 能夠評估各個特征在分類問題上的重要性
- 在生成過程中,能夠獲取到內部生成誤差的一種無偏估計
- 對於缺省值問題也能夠獲得很好得結果
實際上,隨機森林的特點不只有這六點,它就相當於機器學習領域的Leatherman(多面手),你幾乎可以把任何東西扔進去,它基本上都是可供使用的。在估計推斷映射方面特別好用,以致都不需要像SVM那樣做很多參數的調試。
4.隨機森林的生成
前面提到,隨機森林中有許多的分類樹。我們要將一個輸入樣本進行分類,我們需要將輸入樣本輸入到每棵樹中進行分類。打個形象的比喻:森林中召開會議,討論某個動物到底是老鼠還是松鼠,每棵樹都要獨立地發表自己對這個問題的看法,也就是每棵樹都要投票。該動物到底是老鼠還是松鼠,要依據投票情況來確定,獲得票數最多的類別就是森林的分類結果。森林中的每棵樹都是獨立的,99.9%不相關的樹做出的預測結果涵蓋所有的情況,這些預測結果將會彼此抵消。少數優秀的樹的預測結果將會超脫於芸芸“噪音”,做出一個好的預測。將若干個弱分類器的分類結果進行投票選擇,從而組成一個強分類器,這就是隨機森林bagging的思想(關於bagging的一個有必要提及的問題:bagging的代價是不用單棵決策樹來做預測,具體哪個變量起到重要作用變得未知,所以bagging改進了預測准確率但損失了解釋性。)
有了樹我們就可以分類了,但是森林中的每棵樹是怎么生成的呢?
每棵樹的按照如下規則生成:
1)如果訓練集大小為N,對於每棵樹而言,隨機且有放回地從訓練集中的抽取N個訓練樣本(這種采樣方式稱為bootstrap sample方法),作為該樹的訓練集;
從這里我們可以知道:每棵樹的訓練集都是不同的,而且里面包含重復的訓練樣本(理解這點很重要)。
為什么要隨機抽樣訓練集?
如果不進行隨機抽樣,每棵樹的訓練集都一樣,那么最終訓練出的樹分類結果也是完全一樣的,這樣的話完全沒有bagging的必要;
為什么要有放回地抽樣?
如果不是有放回的抽樣,那么每棵樹的訓練樣本都是不同的,都是沒有交集的,這樣每棵樹都是"有偏的",都是絕對"片面的"(當然這樣說可能不對),也就是說每棵樹訓練出來都是有很大的差異的;而隨機森林最后分類取決於多棵樹(弱分類器)的投票表決,這種表決應該是"求同",因此使用完全不同的訓練集來訓練每棵樹這樣對最終分類結果是沒有幫助的,這樣無異於是"盲人摸象"。
2)如果每個樣本的特征維度為M,指定一個常數m<<M,隨機地從M個特征中選取m個特征子集,每次樹進行分裂時,從這m個特征中選擇最優的;
3)每棵樹都盡最大程度的生長,並且沒有剪枝過程。
一開始我們提到的隨機森林中的“隨機”就是指的這里的兩個隨機性。兩個隨機性的引入對隨機森林的分類性能至關重要。由於它們的引入,使得隨機森林不容易陷入過擬合,並且具有很好得抗噪能力(比如:對缺省值不敏感)。
隨機森林分類效果(錯誤率)與兩個因素有關:
- 森林中任意兩棵樹的相關性:相關性越大,錯誤率越大;
- 森林中每棵樹的分類能力:每棵樹的分類能力越強,整個森林的錯誤率越低。
減小特征選擇個數m,樹的相關性和分類能力也會相應的降低;增大m,兩者也會隨之增大。所以關鍵問題是如何選擇最優的m(或者是范圍),這也是隨機森林唯一的一個參數。
5.袋外錯誤率(oob error)
構建隨機森林的關鍵問題就是如何選擇最優的m,要解決這個問題主要依據計算袋外錯誤率oob error(out-of-bag error)。
隨機森林有一個重要的優點就是,沒有必要對它進行交叉驗證或者用一個獨立的測試集來獲得誤差的一個無偏估計。它可以在內部進行評估,也就是說在生成的過程中就可以對誤差建立一個無偏估計。
在構建每棵樹時,我們對訓練集使用了不同的bootstrap sample(隨機且有放回地抽取)。所以對於每棵樹而言(假設對於第k棵樹),大約有1/3的訓練實例沒有參與第k棵樹的生成,它們稱為第k棵樹的oob樣本。
而這樣的采樣特點就允許我們進行oob估計,它的計算方式如下:
(note:以樣本為單位)
1)對每個樣本,計算它作為oob樣本的樹對它的分類情況(約1/3的樹);
2)然后以簡單多數投票作為該樣本的分類結果;
3)最后用誤分個數占樣本總數的比率作為隨機森林的oob誤分率。
6.隨機森林工作原理解釋的一個簡單例子
描述:根據已有的訓練集已經生成了對應的隨機森林,隨機森林如何利用某一個人的年齡(Age)、性別(Gender)、教育情況(Highest Educational Qualification)、工作領域(Industry)以及住宅地(Residence)共5個字段來預測他的收入層次。
收入層次 :
Band 1 : Below $40,000
Band 2: $40,000 – 150,000
Band 3: More than $150,000
隨機森林中每一棵樹都可以看做是一棵CART(分類回歸樹),這里假設森林中有5棵CART樹,總特征個數N=5,我們取m=1(這里假設每個CART樹對應一個不同的特征)。
CART 1 : Variable Age
CART 2 : Variable Gender
CART 3 : Variable Education
CART 4 : Variable Residence
CART 5 : Variable Industry
我們要預測的某個人的信息如下:
1. Age : 35 years ; 2. Gender : Male ; 3. Highest Educational Qualification : Diploma holder; 4. Industry : Manufacturing; 5. Residence : Metro.
根據這五棵CART樹的分類結果,我們可以針對這個人的信息建立收入層次的分布情況:
最后,我們得出結論,這個人的收入層次70%是一等,大約24%為二等,6%為三等,所以最終認定該人屬於一等收入層次(小於$40,000)。
7.python實現
#-*- coding:utf-8 -*- from sklearn.datasets import load_iris from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import cross_val_score, ShuffleSplit from sklearn.ensemble import ExtraTreesClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import make_blobs import pandas as pd import numpy as np import sys # 利用iris數據集划分訓練數據和測試數據,最后得到的結果顯示為圖表 def testTable(iris): # 創建DataFrame,列名為特征名稱,屬性值為特征值 df = pd.DataFrame(iris.data, columns=iris.feature_names) # 從一個均勻分布 [ 0, 1 ) 中隨機采樣,注意定義域是左閉右開,即包含 0 ,不包含 1,長度為數據集長度 df['is_train'] = np.random.uniform(0, 1, len(df)) <= .75 # 從分類代碼和分類類別數組中創建一個分類類型 df['species'] = pd.Categorical.from_codes(iris.target, iris.target_names) # 使用head查看前幾行數據(默認是前5行) print df.head() # 划分訓練集和測試集 train, test = df[df['is_train']==True], df[df['is_train']==False] # 得到所有的列標簽 features = df.columns[:4] # 並行數為2 n = 2 clf = RandomForestClassifier(n_jobs=n) #pandas.factorize()把文本標注的屬性列還原特征化 # factorize函數可以將Series中的標稱型數據映射稱為一組數字, # 相同的標稱型映射為相同的數字。factorize函數的返回值是一個tuple(元組),元組中包含兩個元素。 # 第一個元素是一個array,其中的元素是標稱型元素映射為的數字; # 第二個元素是Index類型,其中的元素是所有標稱型元素,沒有重復。 y, _ = pd.factorize(train['species']) # 放入訓練的屬性以及分類的特征值 clf.fit(train[features], y) print y # 預測訓練集預測的類別,獲得類別對應的名稱 preds = iris.target_names[clf.predict(test[features])] # 第一個參數是行索引,第二個屬性為列索引 print pd.crosstab(test['species'], preds, rownames=['actual'], colnames=['preds']) # 利用iris數據集訓練數據,進行預測 def testRegress(iris): print iris # 讀取列表的長度 print(iris['target'].shape) rf = RandomForestRegressor(n_estimators=100, n_jobs=2) rf.fit(iris.data[:150], iris.target[:150]) # 進行模型的訓練 # 隨機挑選兩個預測不相同的樣本 instance = iris.data[[100, 109]] print(instance) rf.predict(instance[[0]]) print('instance 0 prediction:', rf.predict(instance[[0]])) print('instance 1 prediction:', rf.predict(instance[[1]])) print(iris.target[100], iris.target[109]) # 測試數據集中屬性對分類的影響的重要性 def importClass(iris): X = iris["data"] Y = iris["target"] names = iris["feature_names"] rf = RandomForestRegressor() scores = [] # 讀取X的列數 for i in range(X.shape[1]): # cross_val_score(estimator, X, y=None, scoring=None, cv=None, n_jobs=1, # verbose=0, fit_params=None, pre_dispatch=‘2*n_jobs’) # estimator:數據對象 X:數據 y:預測數據 soring:調用的方法 # cv:交叉驗證生成器或可迭代的次數 n_jobs:同時工作的cpu個數(-1代表全部) # ShuffleSplit:把X中數據打亂,迭代三次,選取0.3的數據作為測試數據 score = cross_val_score(rf, X[:, i:i + 1], Y, scoring="r2", cv=ShuffleSplit(len(X), 3, .3)) # print score # 取3次迭代的平均值,保留小數點后三位 scores.append((round(np.mean(score), 3), names[i])) print(sorted(scores, reverse=True)) # 三種方法比較 def compTest(iris): # 生成用於聚類的各向同性高斯blob # n_samples: 待生成的樣本的總數 n_features:每個樣本的特征數 # centers:要生成的樣本中心(類別)數,或者是確定的中心點 # random_state:random_state是隨機數生成器使用的種子 X, y = make_blobs(n_samples=10000, n_features=10, centers=100, random_state=0) # 決策樹分類器 clf = DecisionTreeClassifier(max_depth=None, min_samples_split=2, random_state=0) scores = cross_val_score(clf, X, y) print(scores.mean()) # 隨機森林分類器 clf = RandomForestClassifier(n_estimators=10, max_depth=None, min_samples_split=2, random_state=0) scores = cross_val_score(clf, X, y) print(scores.mean()) # ExtraTree分類器 clf = ExtraTreesClassifier(n_estimators=10, max_depth=None, min_samples_split=2, random_state=0) scores = cross_val_score(clf, X, y) print(scores.mean()) # 設置編碼 reload(sys) sys.setdefaultencoding('utf-8') #iris的4個屬性是:萼片寬度 萼片長度 花瓣寬度 花瓣長度 標簽是花的種類:setosa versicolour virginica iris = load_iris() testTable(iris) testRegress(iris) importClass(iris) compTest(iris)
運行結果:
使用head查看前幾行數據(默認是前5行)
相同的屬性映射為相同的數字
預測的表格
testRegress方法
importClass方法
compTest方法
8.函數解釋
class sklearn.ensemble.RandomForestClassifier(n_estimators=10, crite-rion=’gini’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=’auto’, max_leaf_nodes=None, bootstrap=True, oob_score=False, n_jobs=1, ran-dom_state=None, verbose=0, warm_start=False, class_weight=None)
- 隨機森林參數
1) n_estimators=100:決策樹的個數,一般來說n_estimators太小,容易欠擬合,n_estimators太大,又容易過擬合,一般選擇一個適中的數值,至少100左右可以達到可接受的性能和誤差率。默認是100。
2) oob_score=False :即是否采用袋外樣本來評估模型的好壞。默認是False。推薦設置為True,因為袋外分數反應了一個模型擬合后的泛化能力。
3) criterion: 即CART樹做划分時對特征的評價標准。分類模型和回歸模型的損失函數是不一樣的。分類RF對應的CART分類樹默認是基尼系數gini,另一個可選擇的標准是信息增益。回歸RF對應的CART回歸樹默認是均方差mse,另一個可以選擇的標准是絕對值差mae。一般來說選擇默認的標准就已經很好的。
4)bootstrap=True:是否有放回的采樣,默認為True
5)n_jobs=1:並行job個數。這個在ensemble算法中非常重要,尤其是bagging(而非boosting,因為boosting的每次迭代之間有影響,所以很難進行並行化),因為可以並行從而提高性能。1=不並行;n:n個並行;-1:CPU有多少core,就啟動多少job
6)warm_start=False:熱啟動,決定是否使用上次調用該類的結果然后增加新的
7)class_weight=None:各個label的權重
- 決策樹參數
1) 最大特征數max_features: 可以使用很多種類型的值,默認是"None",意味着划分時考慮所有的特征數;如果是"log2"意味着划分時最多考慮log2N個特征;如果是"sqrt"或者"auto"意味着划分時最多考慮√N個特征。如果是整數,代表考慮的特征絕對數。如果是浮點數,代表考慮特征百分比,即考慮(百分比xN)取整后的特征數。其中N為樣本總特征數。一般來說,可以使用"sqrt"。
2) 決策樹最大深度max_depth: 默認可以不輸入,如果不輸入的話,決策樹在建立子樹的時候不會限制子樹的深度。一般來說,數據少或者特征少的時候可以不管這個值。如果模型樣本量多,特征也多的情況下,推薦限制這個最大深度,具體的取值取決於數據的分布。常用的可以取值10-100之間。
3) 內部節點再划分所需最小樣本數min_samples_split: 這個值限制了子樹繼續划分的條件,如果某節點的樣本數少於min_samples_split,則不會繼續再嘗試選擇最優特征來進行划分。 默認是2.如果樣本量不大,不需要管這個值。如果樣本量數量級非常大,則推薦增大這個值。
4) 葉子節點最少樣本數min_samples_leaf: 這個值限制了葉子節點最少的樣本數,如果某葉子節點數目小於樣本數,則會和兄弟節點一起被剪枝。 默認是1,可以輸入最少的樣本數的整數,或者最少樣本數占樣本總數的百分比。如果樣本量不大,不需要管這個值。如果樣本量數量級非常大,則推薦增大這個值。
5)葉子節點最小的樣本權重和min_weight_fraction_leaf:這個值限制了葉子節點所有樣本權重和的最小值,如果小於這個值,則會和兄弟節點一起被剪枝。 默認是0,就是不考慮權重問題。一般來說,如果我們有較多樣本有缺失值,或者分類樹樣本的分布類別偏差很大,就會引入樣本權重,這時我們就要注意這個值了。
6) 最大葉子節點數max_leaf_nodes: 通過限制最大葉子節點數,可以防止過擬合,默認是"None”,即不限制最大的葉子節點數。如果加了限制,算法會建立在最大葉子節點數內最優的決策樹。如果特征不多,可以不考慮這個值,但是如果特征分成多的話,可以加以限制,具體的值可以通過交叉驗證得到。
7) 節點划分最小不純度min_impurity_split: 這個值限制了決策樹的增長,如果某節點的不純度(基於基尼系數,均方差)小於這個閾值,則該節點不再生成子節點。即為葉子節點 。一般不推薦改動默認值1e-7。
上面決策樹參數中最重要的包括最大特征數max_features, 最大深度max_depth, 內部節點再划分所需最小樣本數min_samples_split和葉子節點最少樣本數min_samples_leaf。
- 預測
predict_proba(x):給出帶有概率值的結果。每個點在所有label的概率和為1.
predict(x):直接給出預測結果。內部還是調用的predict_proba(),根據概率的結果看哪個類型的預測值最高就是哪個類型。
predict_log_proba(x):和predict_proba基本上一樣,只是把結果給做了log()處理。