菜菜的sklearn課堂
文章目錄
- 1 概述
-
- 1.1 內建算法概述
- 1.2 sklearn中的內建算法
- 2 随機森林分類器 RandomForestClassifier
-
- 2.1 參數
- 2.2 重要參數
-
- 2.2.1 控制基評估器的參數
- 2.2.2 n_estimators
- 2.2.3 random_state
- 2.2.4 bootstrap & oob_score
- 2.2.5 重要屬性和接口
- 3 RandomForestRegressor
-
- 3.1 随機森林回歸應用—填補缺失值
-
- (1)使用均值進行填補
- (2)使用 0 進行填補
- (3)使用随機森林回歸進行填補
- 三種方法效果對比
- 4 機器學習中調參的基本思想
-
- 4.1 泛化誤差
- 5 執行個體:随機森林在乳腺癌資料上的調參
- 補充:為什麼随機森林不剪枝也不會出現過拟合
Github項目-100-Days-Of-ML-Code以及代碼
#導入庫
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#導入資料集
dataset = pd.read_csv('../datasets/Social_Network_Ads.csv')
X = dataset.iloc[:, [2, 3]].values
y = dataset.iloc[:, 4].values
#将資料集拆分成訓練集和測試集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)
#特征縮放
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
#調試訓練集的随機森林
from sklearn.ensemble import RandomForestClassifier
classifier = RandomForestClassifier(n_estimators = 10, criterion = 'entropy', random_state = 0)
classifier.fit(X_train, y_train)
#預測測試集結果
y_pred = classifier.predict(X_test)
#生成混淆矩陣,也稱作誤差矩陣
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
#将訓練集結果可視化
from matplotlib.colors import ListedColormap
X_set, y_set = X_train, y_train
X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),
np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),
alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(y_set)):
plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],
c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Random Forest Classification (Training set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()
#将測試集結果可視化
from matplotlib.colors import ListedColormap
X_set, y_set = X_test, y_test
X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),
np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),
alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(y_set)):
plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],
c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Random Forest Classification (Test set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()
1 概述
随機森林本質為內建學習的一種,可用于回歸和分類,是以決策樹為基礎的更進階的算法。
随機森林中每個決策樹都有一個自己的結果,随機森林通過統計每個決策樹的結果,選擇投票數最多的結果作為其最終結果。
以随機的方式建構出的一個森林,而這個森林是由很多的互相不關聯的決策樹組成。通過建立n個模型的組合來解決單一預測問題。
圖檔:用通俗易懂的方式剖析随機森林
1.1 內建算法概述
內建算法會考慮多個評估器的模組化結果,彙總之後得到一個綜合的結果,以此來擷取比單個模型更好的回歸或分類表現。
多個模型內建成為的模型叫做內建評估器,組成內建評估器的每個模型都叫做基評估器
(base estimator)
通常來說,有三類內建算法:裝袋法(Bagging),提升法(Boosting)和stacking。
Bagging
Bagging的核心思想是建構多個互相獨立的評估器,然後對其預測進行平均或多數表決原則來決定內建評估器的結果。裝袋法的代表模型就是随機森林。
參見:https://www.jianshu.com/p/28ed0cd16d92
Boosting
Boosting中,基評估器是相關的,是按順序一 一建構的。其核心思想是結合弱評估器的力量一次次對難以評估的樣本進行預測,進而構成一個強評估器。提升法的代表模型有Adaboost和梯度提升樹。
參見:https://www.jianshu.com/p/28ed0cd16d92
Bagging與Boosting的差別
參見:https://www.jianshu.com/p/28ed0cd16d92
決策樹與這些算法架構進行結合所得到的新的算法:
1)Bagging + 決策樹 = 随機森林
2)Adaptive boosting+ 決策樹 = 提升樹
3)Gradient Boosting + 決策樹 = GBDT
參見:https://zhuanlan.zhihu.com/p/334714191
1.2 sklearn中的內建算法
sklearn中的內建算法子產品ensemble,內建算法中,有一半以上都是樹的內建模型
2 随機森林分類器 RandomForestClassifier
随機森林是非常具有代表性的Bagging內建算法,它的所有基評估器都是決策樹,分類樹組成的森林就叫做随機森林分類器,回歸樹所內建的森林就叫做随機森林回歸器。
2.1 參數
sklearn.ensemble.RandomForestClassifier (
n_estimators=’10’,
criterion=’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,
min_impurity_decrease=0.0,
min_impurity_split=None,
bootstrap=True,
oob_score=False,
n_jobs=None,
random_state=None,
verbose=0,
warm_start=False,
class_weight=None)
2.2 重要參數
2.2.1 控制基評估器的參數
單個決策樹的準确率越高,随機森林的準确率也會越高,因為裝袋法Bagging是依賴于平均值或者少數服從多數原則來決定內建的結果的。
2.2.2 n_estimators
森林中樹木的數量,即基評估器的數量。n_estimators越大,模型的效果往往越好。
n_estimators達到一定的程度之後,随機森林的精确性往往不在上升或開始波動,并且,n_estimators越大,需要的計算量和記憶體也越大,訓練的時間也會越來越長。
一般選擇0到200之間的一個數量
sklearn模組化—随機森林和單個決策樹效益的對比
# 導包
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_wine
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
# 導入需要的資料集
wine = load_wine()
wine.data # 特征矩陣
wine.target # 标簽
# 模組化 決策樹 随機森林對比
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)# 劃分測試集、訓練集
clf = DecisionTreeClassifier(random_state=0) # 決策樹執行個體化
rfc = RandomForestClassifier(random_state=0) # 随機森林執行個體化
# 訓練
clf = clf.fit(Xtrain,Ytrain)
rfc = rfc.fit(Xtrain,Ytrain)
# 得分
score_Single_Tree = clf.score(Xtest,Ytest)
score_Random_Forest = rfc.score(Xtest,Ytest)
print(score_Single_Tree,score_Random_Forest)
# 0.9074074074074074 0.9629629629629629
一次交叉驗證效果對比
# 随機森林交叉驗證
rfc = RandomForestClassifier(n_estimators=25)
rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10)
# 單個決策樹的交叉驗證
clf = DecisionTreeClassifier()
clf_s = cross_val_score(clf,wine.data,wine.target,cv=10)
plt.plot(range(1,11),rfc_s,label = "RandomForest")
plt.plot(range(1,11),clf_s,label = "Decision Tree")
plt.legend()
plt.show()
十組交叉驗證下的效果對比
rfc_l = []
clf_l = []
for i in range(10):
# 随機森林
rfc = RandomForestClassifier(n_estimators=25)
rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
rfc_l.append(rfc_s)
# 決策樹
clf = DecisionTreeClassifier()
clf_s = cross_val_score(clf,wine.data,wine.target,cv=10).mean()
clf_l.append(clf_s)
plt.plot(range(1,11),rfc_l,label = "Random Forest")
plt.plot(range(1,11),clf_l,label = "Decision Tree")
plt.legend()
plt.show()
n_estimators的學習曲線
因為代碼跑的時間太長,是以 n_estimators 限制在 1-50
superpa = []
for i in range(50):
rfc = RandomForestClassifier(n_estimators=i+1,n_jobs=-1)
rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
superpa.append(rfc_s)
print(max(superpa),superpa.index(max(superpa))) # 0.9888888888888889 15
plt.figure(figsize=[20,5])
plt.plot(range(1,51),superpa)
plt.show()
2.2.3 random_state
随機森林的本質是一種裝袋內建算法(bagging),裝袋內建算法是對基評估器的預測結果進行平均或用多數表決原則來決定內建評估器的結果。
在分類樹中,一個random_state隻控制生成一棵樹,而随機森林中的random_state控制的是生成森林的模式,其中的每一棵樹的random_state都不一樣,而非讓一個森林中隻有一棵樹。
當random_state固定時,随機森林中生成的是一組固定的樹,但每棵樹依然是不一緻的,這是用”随機挑選特征進行分枝“的方法得到的随機性。并且我們可以證明,當這種随機性越大的時候,袋裝法的效果一般會越來越好。
用袋裝法內建時,基分類器應當是互相獨立的,是不相同的
但這種做法的局限性是很強的,當我們需要成千上萬棵樹的時候,資料不一定能夠提供成千上萬的特征來讓我們構築盡量多盡量不同的樹。是以,除了random_state。還需要其他的随機性。
rfc = RandomForestClassifier(n_estimators=20,random_state=2)
rfc = rfc.fit(Xtrain, Ytrain)
#随機森林 使用屬性estimators_,檢視森林中所有樹的狀況
rfc.estimators_
"""
[DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort='deprecated',
random_state=1872583848, splitter='best'),
DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort='deprecated',
random_state=794921487, splitter='best'),
...
DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort='deprecated',
random_state=570104212, splitter='best')]
"""
# 除random_state,每一棵樹的其他參數都一樣
for i in range(len(rfc.estimators_)):
print(rfc.estimators_[i].random_state)
"""
1872583848
794921487
111352301
1853453896
213298710
1922988331
1869695442
2081981515
1805465960
1376693511
1418777250
663257521
878959199
854108747
512264917
515183663
1287007039
2083814687
1146014426
570104212
"""
2.2.4 bootstrap & oob_score
要讓基分類器盡量都不一樣,一種很容易了解的方法是使用不同的訓練集來進行訓練,而袋裝法正是通過有放回的随機抽樣技術來形成不同的訓練資料,bootstrap就是用來控制抽樣技術的參數。
随機采樣
bootstrap參數預設True,代表采用這種有放回的随機抽樣技術
有放回的随機抽樣技術
有放回的随機抽樣會使一些樣本可能在同一個自助集中出現多次,而其他一些卻可能
被忽略,一般來說,自助集大約平均會包含63%的原始資料。是以,會有約37%的訓練資料被浪費掉,沒有參與模組化,這些資料被稱為袋外資料(oob)
是以,在使用随機森林時,可以不劃分測試集和訓練集,隻需要用袋外資料來測試我們的模型即可。
如果希望用袋外資料來測試,則需要在執行個體化時就将oob_score這個參數調整為True,訓練完畢之後,可以用oob_score_來檢視在袋外資料上測試的結果:
# 預設bootstrap=True
rfc = RandomForestClassifier(n_estimators=25,bootstrap=True, oob_score=True)
rfc = rfc.fit(wine.data,wine.target)
#重要屬性oob_score_
rfc.oob_score_ # 0.9887640449438202
在做随機森林模組化的時候,可以選擇袋外資料;也可以劃分測試集、訓練集,交叉驗證
2.2.5 重要屬性和接口
rfc = RandomForestClassifier(n_estimators=25)
rfc = rfc.fit(Xtrain, Ytrain)
rfc.score(Xtest,Ytest)
# 特征重要性
[*zip(wine.feature_names,rfc.feature_importances_)]
"""
[('alcohol', 0.06896540423597283),
('malic_acid', 0.052688046303931875),
('ash', 0.014399355972368931),
('alcalinity_of_ash', 0.027490363477529634),
('magnesium', 0.043205031258377595),
('total_phenols', 0.052816448485066274),
('flavanoids', 0.1361530184886118),
('nonflavanoid_phenols', 0.007814582111531488),
('proanthocyanins', 0.0029810556020386588),
('color_intensity', 0.2198296566555652),
('hue', 0.10997900350269595),
('od280/od315_of_diluted_wines', 0.09759078271547955),
('proline', 0.16608725119083018)]
"""
# 傳回這個樣本在這棵樹中所在的葉子節點所在的索引
rfc.apply(Xtest)
"""
array([[15, 8, 14, ..., 14, 19, 13],
[ 2, 5, 17, ..., 8, 15, 6],
[ 9, 5, 5, ..., 3, 4, 2],
...,
[15, 8, 21, ..., 14, 19, 13],
[ 9, 1, 11, ..., 3, 2, 2],
[ 9, 1, 19, ..., 8, 2, 2]], dtype=int64)
"""
rfc.predict(Xtest)
"""
array([0, 2, 1, 0, 2, 1, 1, 0, 0, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1, 0, 0, 2,
1, 1, 1, 0, 0, 2, 1, 1, 1, 2, 2, 0, 1, 0, 1, 0, 2, 2, 2, 2, 2, 0,
0, 0, 2, 0, 0, 2, 2, 0, 1, 1])
"""
# 每一個樣本對應的每一類标簽的機率
rfc.predict_proba(Xtest)
"""
array([[0.96, 0.04, 0. ],
[0. , 0. , 1. ],
...
[0. , 0.84, 0.16]])
"""
3 RandomForestRegressor
所有的參數,屬性與接口,全部和随機森林分類器一緻。僅有的不同就是回歸樹與分類樹的不同,不純度的名額,參數Criterion不一緻。
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestRegressor
boston = load_boston()
regressor = RandomForestRegressor(n_estimators=100,random_state=0)
cross_val_score(regressor, boston.data, boston.target, cv=10,scoring = "neg_mean_squared_error")
3.1 随機森林回歸應用—填補缺失值
在sklearn中,可以使用sklearn.impute.SimpleImputer來輕松地将均值,中值,或者其他最常用的數值填補到資料中
使用均值,0,和随機森林回歸來填補缺失值,并驗證四種狀況下的拟合狀況,找出對使用的資料集來說最佳的缺失值填補方法。
導包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score
加載資料集
dataset = load_boston()
# 總共506*13=6578個資料
# 完整的資料
X_full, y_full = dataset.data, dataset.target
n_samples = X_full.shape[0] # 506
n_features = X_full.shape[1] # 13
構造缺失值資料集
rng = np.random.RandomState(0)
# 缺失率為0.5,即構造的缺失值占據一半
missing_rate = 0.5
n_missing_samples = int(np.floor(n_samples * n_features * missing_rate))
# 缺失值索引
missing_col_index = rng.randint(0,n_features,n_missing_samples)
missing_row_index = rng.randint(0,n_samples,n_missing_samples)
X_missing = X_full.copy()
y_missing = y_full.copy()
# 替換,構造缺失值資料集
X_missing[missing_row_index,missing_col_index] = np.nan
X_missing = pd.DataFrame(X_missing)
注意:這裡特征矩陣是有缺失的,而标簽列完整的
(1)使用均值進行填補
#使用均值進行填補
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')
X_missing_mean = imp_mean.fit_transform(X_missing)
#使用0進行填補
imp_0 = SimpleImputer(missing_values=np.nan, strategy="constant",fill_value=0)
X_missing_0 = imp_0.fit_transform(X_missing)
# 在sklearn中,可以使用sklearn.impute.SimpleImputer來輕松地将均值,中值,或者其他最常用的數值填補到資料中
from sklearn.impute import SimpleImputer
# 執行個體化
imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')
# 訓練和導出 X_missing_mean 為用均值填充卻隻是的資料集
X_missing_mean = imp_mean.fit_transform(X_missing)
# 檢視缺失值是否全部被替換
pd.DataFrame(X_missing_mean).isnull().sum()
'''
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
dtype: int64
'''
(2)使用 0 進行填補
#使用0進行填補
imp_0 = SimpleImputer(missing_values=np.nan, strategy="constant",fill_value=0)
X_missing_0 = imp_0.fit_transform(X_missing)
# 檢視缺失值是否全部被替換
pd.DataFrame(X_missing_mean).isnull().sum()
(3)使用随機森林回歸進行填補
對于一個有n個特征的資料來說,其中特征T有缺失值,我們就把特征T當作标簽,其他的
n-1個特征 + 原本的标簽 = 新的特征矩陣
那對于T來說,它沒有缺失的部分,就是我們的 Y_train,這部分資料既有标簽也有特征,而它缺失的部分,隻有特征沒有标簽,就是我們需要預測的部分。
特征T不缺失的值對應的其他n-1個特征 + 本來的标簽:X_train
特征T不缺失的值:Y_train
特征T缺失的值對應的其他n-1個特征 + 本來的标簽:X_test
特征T缺失的值:未知,我們需要預測的 Y_test
那如果資料中除了特征T之外,其他特征也有缺失值怎麼辦?
答案是周遊所有的特征,從缺失最少的開始進行填補(因為填補缺失最少的特征所需要的準确資訊最少)。填補一個特征時,先将其他特征的缺失值用0代替,每完成一次回歸預測,就将預測值放到原本的特征矩陣中,再繼續填補下一個特征。每一次填補完畢,有缺失值的特征會減少一個,是以每次循環後,需要用0來填補的特征就越來越少。當進行到最後一個特征時(這個特征應該是所有特征中缺失值最多的),已經沒有任何的其他特征需要用0來進行填補了,而我們已經使用回歸為其他特征填補了大量有效資訊,可以用來填補缺失最多的特征。周遊所有的特征後,資料就完整,不再有缺失值了。
#用随機森林回歸來填補缺失值
X_missing_reg = X_missing.copy()
# 檢視缺失值情況
pd.DataFrame(X_missing_reg).isnull().sum()
'''
0 200
1 201
2 200
3 203
4 202
5 201
6 185
7 197
8 196
9 197
10 204
11 214
12 189
dtype: int64
'''
# 缺失值從小到大的特征順序
# argsort 傳回從小到大的順序所對應的索引
sortindex = np.argsort(X_missing_reg.isnull().sum(axis=0)).values
'''
array([ 6, 12, 8, 7, 9, 0, 2, 1, 5, 4, 3, 10, 11], dtype=int64)
'''
# 周遊所有的特征,從缺失最少的開始進行填補,每完成一次回歸預測,就将預測值放到原本的特征矩陣中,再繼續填補下一個特征
for i in sortindex:
#建構我們的新特征矩陣和新标簽
df = X_missing_reg # 充當中間資料集
fillc = df.iloc[:,i] # 缺失值最少的特征列
# 除了第 i 特征列,剩下的特征列+原有的完整标簽 = 新的特征矩陣
df = pd.concat([df.iloc[:,df.columns != i],pd.DataFrame(y_full)],axis=1)
#在新特征矩陣中,對含有缺失值的列,進行0的填補 ,沒循環一次,用0填充的列越來越少
df_0 =SimpleImputer(missing_values=np.nan,strategy='constant',fill_value=0).fit_transform(df)
#找出訓練集和測試集
# 标簽
Ytrain = fillc[fillc.notnull()] # 沒有缺失的部分,就是 Y_train
Ytest = fillc[fillc.isnull()] # 不是需要Ytest的值,而是Ytest的索引
# 特征矩陣
Xtrain = df_0[Ytrain.index,:]
Xtest = df_0[Ytest.index,:] # 有缺失值的特征情況
rfc = RandomForestRegressor(n_estimators=100) # 執行個體化
rfc = rfc.fit(Xtrain, Ytrain) # 訓練
Ypredict = rfc.predict(Xtest) # 預測結果,就是要填補缺失值的值
#将填補好的特征傳回到我們的原始的特征矩陣中
X_missing_reg.loc[X_missing_reg.iloc[:,i].isnull(),i] = Ypredict
# 最後,再次檢視缺失值是否全部被替換
pd.DataFrame(X_missing_reg).isnull().sum()
'''
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
dtype: int64
'''
三種方法效果對比
對填補好的資料進行模組化
X = [X_full,X_missing_mean,X_missing_0,X_missing_reg]
mse = []
std = []
for x in X:
estimator = RandomForestRegressor(random_state=0, n_estimators=100)
scores = cross_val_score(estimator,x,y_full,scoring='neg_mean_squared_error',cv=5).mean()
# 負的軍方誤差
mse.append(scores * -1)
[*zip(['X_full','X_missing_mean','X_missing_0','X_missing_reg'],mse)]
'''
[('X_full', 21.62860460743544),
('X_missing_mean', 40.84405476955929),
('X_missing_0', 49.50657028893417),
('X_missing_reg', 20.760516310561048)]
'''
from pyecharts import options as opts
from pyecharts.charts import Bar
c = (
Bar(init_opts=opts.InitOpts())
.add_xaxis(['X_full','X_missing_mean','X_missing_0','X_missing_reg'])
.add_yaxis("",mse)
.render("C:/bar.html")
)
# 或者
x_labels = ['Full data','Zero Imputation','Mean Imputation','Regressor Imputation']
colors = ['r', 'g', 'b', 'orange']
plt.figure(figsize=(12, 6))
ax = plt.subplot(111)
for i in np.arange(len(mse)):
ax.barh(i, mse[i],color=colors[i], alpha=0.6, align='center')
ax.set_title('Imputation Techniques with Boston Data')
ax.set_xlim(left=np.min(mse) * 0.9,right=np.max(mse) * 1.1)
ax.set_yticks(np.arange(len(mse)))
ax.set_xlabel('MSE')
ax.set_yticklabels(x_labels)
plt.show()
4 機器學習中調參的基本思想
4.1 泛化誤差
衡量模型在未知資料上的準确率的名額
當模型太複雜,模型就會過拟合,泛化能力就不夠,是以泛化誤差大。當模型太簡單,模型就會欠拟合,拟合能力就不夠,是以誤差也會大。隻有當模型的複雜度剛剛好的才能夠達到泛化誤差最小的目标。
樹模型是天生位于圖的右上角的模型,随機森林是以樹模型為基礎,是以随機森林也是天生複雜度高的模型
調參之前,要先判斷,模型現在究竟處于圖像的哪一邊。
1)模型太複雜或者太簡單,都會讓泛化誤差高,我們追求的是位于中間的平衡點
2)模型太複雜就會過拟合,模型太簡單就會欠拟合
3)對樹模型和樹的內建模型來說,樹的深度越深,枝葉越多,模型越複雜
4)樹模型和樹的內建模型的目标,都是減少模型複雜度,把模型往圖像的左邊移動
在調參的時候,可以參考這個順序
5 執行個體:随機森林在乳腺癌資料上的調參
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
data = load_breast_cancer()
rfc = RandomForestClassifier(n_estimators=100,random_state=90)
score_pre = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score_pre # 0.9638809523809524
調參
随機森林調整的第一步:無論如何先來調n_estimators
首先畫學習曲線
scorel = []
for i in range(0,200,10):
rfc = RandomForestClassifier(n_estimators=i+1,n_jobs=-1,random_state=90)
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
scorel.append(score)
print(max(scorel),(scorel.index(max(scorel))*10)+1)
plt.figure(figsize=[20,5])
plt.plot(range(1,201,10),scorel)
plt.show()
0.9639265664160402 71
在 n_estimators = 71 左右 ,有一個峰值
在确定好的範圍内,進一步細化學習曲線
scorel = []
for i in range(65,75):
rfc = RandomForestClassifier(n_estimators=i,n_jobs=-1,random_state=90)
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
scorel.append(score)
print(max(scorel),([*range(65,75)][scorel.index(max(scorel))]))
plt.figure(figsize=[20,5])
plt.plot(range(65,75),scorel)
plt.show()
0.9666353383458647 73
為網格搜尋做準備,書寫網格搜尋的參數
有一些參數是沒有參照的,很難說清一個範圍,這種情況下我們使用學習曲線,看趨勢
從曲線跑出的結果中選取一個更小的區間,再跑曲線
param_grid = {'n_estimators':np.arange(0, 200, 10)}
param_grid = {'max_depth':np.arange(1, 20, 1)}
param_grid = {'max_leaf_nodes':np.arange(25,50,1)}
有一些參數是可以找到一個範圍的,或者說我們知道他們的取值和随着他們的取值,模型的整體準确率會如何變化,這樣的參數我們就可以直接跑網格搜尋
param_grid = {'criterion':['gini', 'entropy']}
param_grid = {'min_samples_split':np.arange(2, 2+20, 1)}
param_grid = {'min_samples_leaf':np.arange(1, 1+10, 1)}
param_grid = {'max_features':np.arange(5,30,1)}
開始按照參數對模型整體準确率的影響程度進行調參,首先調整max_depth
param_grid = {'max_depth':np.arange(1, 20, 1)}
# 一般根據資料的大小來進行一個試探,資料很小,可以采用1~10,或者1~20這樣的試探
# 大型資料應該嘗試30~50層深度(或許還不足夠
# 更應該畫出學習曲線,來觀察深度對模型的影響
rfc = RandomForestClassifier(n_estimators=39,random_state=90)
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_ # 顯示調整出來的最佳參數
GS.best_score_ # 最佳參數的準确率
根據分數,推測模型屬于下圖左邊還是右邊
調整一下max_features,看看模型如何變化。
調整min_samples_leaf
繼續嘗試min_samples_split
最後嘗試一下criterion
調整完畢,總結出模型的最佳參數
補充:為什麼随機森林不剪枝也不會出現過拟合
引用《機器學習python實戰》
總而言之
因為兩個随機采樣過程已經保證了随機性,是以就不會過拟合