1. 程式人生 > >整合學習和隨機森林——自學第十二篇

整合學習和隨機森林——自學第十二篇

1、整合學習

在面臨選擇的時候需要作出決策,這時候你就會去詢問不同的人該做怎樣的決斷,最後將詢問後的決策進行投票,選擇投票個數最多的那個。對同一個問題,可以有不同的演算法,也會給出不同的結果,在這種情況下,可以整合不同的演算法,少數服從多數,選擇結果數最多的那類演算法。
下面是用邏輯迴歸、SVM、決策樹三種演算法進行的整合學習過程

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

x,y=datasets.make_moons(n_samples=500,noise=0.3,random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()

from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=42)
#使用邏輯迴歸
from sklearn.linear_model import LogisticRegression
log_clf=LogisticRegression()
log_clf.fit(x_train,y_train)
print(log_clf.score(x_test,y_test))

#使用SVM
from sklearn.svm import SVC
svm_clf=SVC()
svm_clf.fit(x_train,y_train)
print(svm_clf.score(x_test,y_test))

#使用決策樹
from sklearn.tree import DecisionTreeClassifier
dt_tree=DecisionTreeClassifier()
dt_tree.fit(x_train,y_train)
print(dt_tree.score(x_test,y_test))
#進行投票
y_predict1=log_clf.predict(x_test)
y_predict2=svm_clf.predict(x_test)
y_predict3=dt_tree.predict(x_test)
#如果三個值相加大於等於2,說明至少有兩個模型的結果是1,那就定為1
y_predict=np.array((y_predict1+y_predict2+y_predict3)>=2,dtype='int')
print(y_predict[:10])

from sklearn.metrics import accuracy_score
print(accuracy_score(y_test,y_predict))
0.864
0.888
0.872
[1 0 0 1 1 1 0 0 0 0]
0.896

可以看出通過整合學習得到的準確度是大於其中任意一個演算法的。
(1)Hard Voting,少數服從多數
當然也可以使用sklearn中的整合演算法VotingClassifier

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

x,y=datasets.make_moons(n_samples=500,noise=0.3,random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()

from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=666)

#載入三種演算法
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier

#傳入多個估計器(演算法),元祖形式
from sklearn.ensemble import VotingClassifier
voting_clf=VotingClassifier(estimators=[
    ("log_clf",LogisticRegression()),
    ("svm_clf",SVC()),
    ("dt_clf",DecisionTreeClassifier())
],voting='hard')
voting_clf.fit(x_train,y_train)
print(voting_clf.score(x_test,y_test))

在使用多個演算法整合之前,可以分別對每個演算法進行調整,使得該演算法最優,再進行整合學習。
(2)Soft Voting(投票時不是按照少數服從多數,而是使用權值)
在這裡插入圖片描述
假設有五個模型,進行二分類問題,每個模型對A,B類分類的概率分別如上所示。如果按照hard演算法的話,其中有三個模型都分為了B類,結果應該為B類,但是可以看出這三個模型分類為B類的概率並不高,而兩個模型分類結果為A的概率都是90%以上。所以soft演算法就是將五個模型的分類概率作為權值進行計算:A-(0.99+0.49+0.4+0.9+0.3)/5=0.616;B-(0.01+0.51+0.6+0.1+0.7)/5=0.384 ,最後結果應該為A
要求:集合中每個模型都可以估計分類概率(KNN,邏輯迴歸,SVM等都可以直接或者間接求出概率)(其中SVM如果使用預設演算法是不支援計算概率的,需要改成true)

import matplotlib.pyplot as plt
from sklearn import datasets

x,y=datasets.make_moons(n_samples=500,noise=0.3,random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()

from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=42)

#載入三種演算法
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier

#傳入多個估計器(演算法),元祖形式
from sklearn.ensemble import VotingClassifier

voting_clf=VotingClassifier(estimators=[
    ("log_clf",LogisticRegression()),
    ("svm_clf",SVC(probability=True)),
    ("dt_clf",DecisionTreeClassifier())
],voting='soft')
voting_clf.fit(x_train,y_train)
print(voting_clf.score(x_test,y_test))

輸出

0.928

可見使用Soft Voting得到的準確度更高。

2、建立子模型

(1)為什麼需要子模型
雖然上面使用了很多的機器學習演算法,但是從哪投票的角度來說,演算法的數量還不夠多,為了得到更多的投票,需要建立更多的子模型,並且這些子模型之間必須要有差異性。
解決:每個子模型只看樣本資料中一部分資料(樣本資料不一樣,得到的子模型也不一樣)
雖然單個的子模型的準確率不高(至少>50%),但是模型越多之後,整體的準確率會增加:假設每個模型的準確率為51%(整體準確率是指一半以上的模型都預測準確)
在這裡插入圖片描述
如果每個子模型準確率為605,那麼500個子模型的整體準確率就為99.99%(整合學習威力很大)
(2)如何建立子模型(對樣本的隨機取樣)
每個子模型只看樣本資料的一部分,通過取樣的方式(放回取樣(Bagging),不放回取樣(Pasting))
Bagging更常用,且不依賴於取樣本的隨機性
下面在sklearn中,對每個模型採用決策樹模型,因為決策樹模型是非引數模型,更容易產生差異較大的子模型

import matplotlib.pyplot as plt
from sklearn import datasets

x,y=datasets.make_moons(n_samples=500,noise=0.3,random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()

from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=42)

#使用Bagging
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
bagging_clf=BaggingClassifier(DecisionTreeClassifier(),n_estimators=500,max_samples=100,
                              bootstrap=True)
#n_estimators:整合幾個決策樹模型,max_samples每個子模型需要看多少個樣本資料,bootstrap=True為放回取樣
bagging_clf.fit(x_train,y_train)
print(bagging_clf.score(x_test,y_test))
0.904

在BaggingClassifier函式中,n_estimators:整合幾個決策樹模型,max_samples每個子模型需要看多少個樣本資料,bootstrap=True為放回取樣

(3)out-of-bag
放回取樣會導致一部分樣本可能沒取到,所以可以不用測試資料集(不用劃分訓練集和測試集),而將那些沒有被取樣到的資料作為測試集和驗證集。
sklearn中在BaggingClassifier函式中新增超引數:oob_score=True,則會在放回過程中記錄被取樣過的樣本,從而可以知道哪些樣沒有被取過。

import matplotlib.pyplot as plt
from sklearn import datasets

x,y=datasets.make_moons(n_samples=500,noise=0.3,random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()

#使用Bagging
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
bagging_clf=BaggingClassifier(DecisionTreeClassifier(),n_estimators=300,max_samples=100,
                              bootstrap=True,oob_score=True)
#n_estimators:整合幾個決策樹模型,max_samples每個子模型需要看多少個樣本資料,bootstrap=True為放回取樣
bagging_clf.fit(x,y)
print(bagging_clf.oob_score_)
0.92

(4)對特徵空間進行隨機取樣(bootstrap_features)
改變max_features的值,即隨機取樣的最大特徵數;bootstrap_features=True表示對特徵取樣採用放回取樣的方式。
如果每個模型需要的樣本數(max_samples=100)小於生成的樣本總數(n_samples=500),則同時構成了對樣本進行隨機取樣和對特徵進行隨機取樣,這樣的效果會更好,當然如果特徵數本來就很少,再進行對特徵的隨機取樣,效果不會很明顯。

random_bagging_clf=BaggingClassifier(DecisionTreeClassifier(),n_estimators=300,max_samples=100,
                              bootstrap=True,oob_score=True,max_features=1,bootstrap_features=True)

這種集成了大量的決策樹的演算法又叫隨機森林,因為每棵樹得到的樣本都是不同的,具有隨機性。

3、隨機森林(集成了決策樹和放回取樣(Bagging))

(1)隨機森林
集成了成百上千的決策樹模型,每棵樹都是通過隨機取樣的方式生成的,具有隨機性。
隨機森林可以通過上面的方法:整合批量的隨機生成的決策樹模型,也可以用sklearn中現成的模型(在隨機的子模型中尋找最優的節點劃分)

import matplotlib.pyplot as plt
from sklearn import datasets

x,y=datasets.make_moons(n_samples=500,noise=0.3,random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()

from sklearn.ensemble import RandomForestClassifier
rf_clf=RandomForestClassifier(n_estimators=500,random_state=666,max_leaf_nodes=16,oob_score=True,n_jobs=-1)
rf_clf.fit(x,y)
print(rf_clf.oob_score_)

n_estimators決策樹子模型的個數,oob_score=True選擇放回取樣並記錄沒有被取樣的資料,max_leaf_nodes每一棵決策樹最多有多少個葉子結點(還有很多的超引數,可以通過輸出模型進行檢視並修改)
(2)Extra-Trees
在決策樹的節點劃分上,使用隨機的特徵和隨機的閾值進行劃分

  • 隨機性更大
  • 抑制了過擬合,方差更小
  • 增加了偏差
  • 訓練速度更快
import matplotlib.pyplot as plt
from sklearn import datasets

x,y=datasets.make_moons(n_samples=500,noise=0.3,random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()

from sklearn.ensemble import ExtraTreesClassifier
et_clf=ExtraTreesClassifier(n_estimators=500,random_state=666,max_leaf_nodes=16,oob_score=True,bootstrap=True)
et_clf.fit(x,y)
print(et_clf.oob_score_)

4、整合學習解決迴歸問題

from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier

超引數的使用和分類問題一樣處理

5、Boosting整合模型

(1)Ada Boosting
整合多個模型,每個模型都在嘗試增強整體效果
在這裡插入圖片描述
假設有一些樣本點,通過第一次擬合之後如上面第一張圖所示,其中有一個點沒有被擬合到,與曲線的誤差較大,那麼再下一次擬合前將增加這個點的權重,降低其餘點的擬合權重,得到第二張擬合曲線圖,當然又有三個點與擬合曲線誤差較大,再進行接下來的權重改變,重新擬合,使得擬合結果越來越好。

import matplotlib.pyplot as plt
from sklearn import datasets

x,y=datasets.make_moons(n_samples=500,noise=0.3,random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()

from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=666)
#AdaBoosting是一個整合的方法,也是需要基本的學習模型,這裡用決策樹模型
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
ada_clf=AdaBoostClassifier(DecisionTreeClassifier(max_depth=2),n_estimators=500)
ada_clf.fit(x_train,y_train)
print(ada_clf.score(x_test,y_test))

(2)Gradient Boosting
訓練一個模型m1,產生錯誤e1;針對e1訓練第二個模型m2,產生錯誤e2;針對e2訓練第三個模型m3,產生錯誤e3…以此類推,最後將一系列的模型預測結果的總和m1+m2+m3…作為最後的結果在這裡插入圖片描述
左邊一列第一幅圖擬合後的結果為右邊一幅圖,將擬合的結果的誤差作為左邊一列第二幅圖的模型輸入並進行第二次擬合,右圖為m1+m2的結果,左邊一列第三幅圖是上面第二幅圖的擬合誤差進行的擬合結果m3,右圖為m1+m2+m3的結果。通過不斷地傳遞與迭代可以看出擬合結果越來越好。

import matplotlib.pyplot as plt
from sklearn import datasets

x,y=datasets.make_moons(n_samples=500,noise=0.3,random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()
#Gradient Boosting本身就是用的決策樹模型
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=666)
from sklearn.ensemble import  GradientBoostingClassifier
gb_clf=GradientBoostingClassifier(max_depth=2,n_estimators=30)
gb_clf.fit(x_train,y_train)
print(gb_clf.score(x_test,y_test))

6、stacking

voting演算法中,是將幾個模型分別進行預測,並將預測結果進行投票,而stacking並不是直接將幾個預測概率結果進行綜合求結果,而是在最後增加一層演算法,將幾個預測結果作為該模型的輸入,最後得到新的概率。
(分類問題轉化為迴歸問題:將分類問題中的概率作為數值,即某一個數據是某一類的概率是多少,將這個數值作為迴歸的結果。)
在這裡插入圖片描述
我們需要將資料集分成兩部分,其中第一部分用來訓練這個底下的三個模型,並將第二部分資料輸入訓練好的三個模型得到新的資料,用來訓練最後一層的模型。
在這裡插入圖片描述
對於stacking來說,超引數有:模型有幾層,每一層有幾個模型(類似神經網路層數越深,越容易過擬合)