python機器學習——隨機森林算法

背景與原理:

首先我們需要知道集成學習的概念,所謂集成學習,就是使用一系列學習器進行學習,並且通過某種規則把這些學習器的學習結果整合起來從而獲得比單個學習器學習效果更好的機器學習方法。這樣的方法可以用於解決單個學習器的過擬合、性能瓶頸等問題,常用的集成方式主要有Bagging(並行)和Boosting(串行),隨機森林就是Bagging的一種擴展變體。

傳統意義上的隨機森林算法是基於決策樹的集成學習方法,在數據量比較大時決策樹會出現性能瓶頸,而隨機森林以決策樹爲基分類器,其由多個由Bagging集成學習技術訓練得到的決策樹,當輸入待分類樣本時,最終的分類結果由單個決策樹的輸出結果投票決定,這樣的隨機森林解決了性能瓶頸問題、對噪聲有較好的容忍度,高度並行且泛化性能較好;同時其還是非參數驅動的分類方法,並不需要對樣本的先驗知識。

隨機森林算法的第一步是構建數據集,假設我們的隨機森林由$k$棵決策樹組成,那麼我們就要從原始數據集中生成$k$個數據集,使用的抽樣方法稱爲Bootstrap方法,是一種隨機的有放回抽樣。

而對於每個數據集,我們都需要構建一棵決策樹,這裏我們使用CART,全名爲Classification and Regression Tree,即這種樹既可以用於分類問題,也可以用於迴歸問題(即連續值的預測)(值得注意的是這種樹每個節點至多有兩個分支)

CART迴歸樹:

回顧一下,所謂迴歸問題就是給定一組數據,每個數據形如$(x_{1},...,x_{n},y)$,現想要訓練一個模型$f$實現在已知$X$的情況下對$y$進行預測。

而回歸樹是怎麼操作呢?我們看到這組數據有$n$個特徵,我們從中選取一個特徵,不妨設爲第$i$個特徵吧,然後選定一個分界點$p$,然後做一個非常簡單粗暴的預測:如果$x_{i}<p$,那麼我們就預測滿足這樣條件的$f(X)=y_{1}$,否則我們預測$f(X)=y_{2}$,這就是最基礎的一個樹形結構

因爲我們的觀點是如果數據集中兩個數據點足夠接近,那麼這兩個數據點對應的$y$值應該也很接近,所以如果我們把這些數據點劃分的足夠細,我們就可以認爲此時還被劃分在一起的點的值可以近似看做相等了。

當然,爲了準確性,假設此時被劃分在一起的點對應的值爲$y_{1},..,y_{k}$,那麼我們的預測值應該是$\hat{y}=\dfrac{\sum_{i=1}^{k}y_{i}}{k}$

而我們的迴歸樹的構建就是不斷選取一個特徵,找到一個劃分點把數據劃分成幾個部分,直到我們認爲誤差在可以接受的範圍內爲止。

而我們度量準確性的方法也是非常自然的MSE損失函數,即$J=\dfrac{1}{m}\sum_{i=1}^{m}(f(X_{i})-y_{i})^{2}$

於是現在的問題就變成了:在每個節點上,我們要選取一個特徵和一個分界點把這個節點上的數據集分成兩部分,如何選取呢?

這個選取方式直觀來講就是遍歷所有特徵和分界點,每個特徵和分界點都會把這個數據集分成兩部分,那麼我們如果不再向下劃分,這兩部分的預測值就分別是每個部分的真實值的平均,那麼我們有了預測值,自然可以計算出損失函數,而我們選取的特徵和分界點應該是使得損失函數值最小的那個!

因此我們重複這個過程就可以構造出一個迴歸樹了。

CART分類樹:

這個分類樹與前一篇博客所述的決策樹有少許不同,這裏我們並不使用信息增益,而是使用基尼係數(GINI)作爲特徵劃分點的依據。

基尼係數:在分類問題中,對於一個有$k$個類的數據集$D$,其基尼係數$GINI(D)=\sum_{i=1}^{k}p_{i}(1-p_{i})=1-\sum_{i=1}^{k}p_{i}^{2}$,其中$p_{i}$是屬於第$i$類的數據在數據集中的佔比。

那麼基尼係數越大,說明樣本純度越低,如果想追求比較好的分類效果,我們希望分類到最後的葉節點時基尼係數儘可能低,這樣我們如果選了某個特徵和劃分點將數據集$D$劃分爲$D_{1},D_{2}$兩部分,那麼這裏的基尼係數可以寫作$GINI=\dfrac{|D_{1}|}{|D|}GINI(D_{1})+\dfrac{|D_{2}|}{|D|}GINI(D_{2})$,即兩部分的基尼係數的加權平均,這樣我們找到使這個基尼係數最小的特徵和劃分點將數據集分裂,重複這一過程直至取得較好效果即可。

在建立了$k$棵決策樹之後,我們通過這$k$棵決策樹的多數投票(如果是隨機問題,可以按某種加權平均)來得到最終的分類(迴歸)結果即可。

代碼實現:

import numpy as np
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import LinearSVC
import matplotlib.pyplot as plt
import pylab as plt
from sklearn.model_selection import train_test_split


X,y=datasets.make_classification(n_samples=10000,n_features=20,n_informative=2,n_redundant=2)
X_train,X_test,Y_train,Y_test=train_test_split(X,y,test_size=0.25)

lr=LogisticRegression()
svc=LinearSVC(C=1.0)
rfc=RandomForestClassifier(n_estimators=100)#森林中樹的個數

lr=lr.fit(X_train,Y_train)
score1=lr.score(X_test,Y_test)
print(score1)

svc=svc.fit(X_train,Y_train)
score2=svc.score(X_test,Y_test)
print(score2)

rfc=rfc.fit(X_train,Y_train)
score3=rfc.score(X_test,Y_test)
print(score3)

x=[]
sc=[]
for i in range(1,101):
    rfc = RandomForestClassifier(n_estimators=i)
    rfc = rfc.fit(X_train, Y_train)
    sc.append(rfc.score(X_test, Y_test))
    x.append(i)

plt.plot(x,sc,c='r')
plt.show()

這段代碼對比了常用的三種分類器的表現:邏輯迴歸、支持向量機和隨機森林,使用了sklearn的一個數據生成器,同時還展示了隨機森林的表現隨森林中樹的個數的變化。

變化圖形如上所示,可以看到事實上選擇20棵左右的樹就已經能有相當不錯的表現了,因此隨機森林中樹的個數選擇一定要注意,如果選擇的樹過多不僅不會使預測效果有明顯提高,反而會大大提高模型訓練的開銷。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章