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 numpy as np
import pandas as pd
# 模組化跑分
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()
# print(score_pre)
# 調參跑分
# todo:第一步,調試範圍在0到200之間的步長為10的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) # 結果 0.9684480598046841 41
# plt.figure(figsize=[20, 5])
# plt.plot(range(1, 201, 10), scorel)
# plt.show()
# # list.index([object]) 傳回這個object在清單list的索引
# todo:第二步 确定了範圍之後,再次畫學習曲線獲得最好的目标
# scorel = []
# for i in range(35, 45):
# 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(35, 45)][scorel.index(max(scorel))])) # 0.9719568317345088 39
# plt.figure(figsize=[20, 5])
# plt.plot(range(35, 45), scorel)
# plt.show()
# todo:第三步 确定了最佳的 n_estimators 為39這個最重要的參數之後,模型效果提升顯著,再用網格搜尋擷取别的最優參數
# 有一些參數是可以找到一個範圍的,或者說我們知道他們的取值和随着他們的取值,模型的整體準确率會如何變化,這
# 樣的參數我們就可以直接跑網格搜尋
# 例如:
# 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)# param_grid = {'max_features':np.arange(5,30,1)# param_grid = {'max_leaf_nodes': np.arange(25, 50, 1)}
# todo 試探 max_depth
# param_grid = {'max_depth': np.arange(1, 20, 1)}
# 一般根據資料的大小來進行一個試探,乳腺癌資料很小,是以可以采用1~10,或者1~20這樣的試探
# 但對于像digit recognition那樣的大型資料來說,我們應該嘗試30~50層深度(或許還不足夠
# 更應該畫出學習曲線,來觀察深度對模型的影響
# rfc = RandomForestClassifier(n_estimators=39
# , random_state=90
# )
# GS = GridSearchCV(rfc, param_grid, cv=10)
# GS.fit(data.data, data.target)
# print(GS.best_params_) # {'max_depth': 11}
# print(GS.best_score_) # 0.9718804920913884
# 在這裡,我們注意到,将max_depth設定為有限之後,模型的準确率下降了。限制max_depth,是讓模型變得簡
# 單,把模型向左推,而模型整體的準确率下降了,即整體的泛化誤差上升了,這說明模型現在位于圖像左邊,即泛
# 化誤差最低點的左邊(偏差為主導的一邊)。通常來說,随機森林應該在泛化誤差最低點的右邊,樹模型應該傾向
# 于過拟合,而不是拟合不足。這和資料集本身有關,但也有可能是我們調整的n_estimators對于資料集來說太大,
# 是以将模型拉到泛化誤差最低點去了。然而,既然我們追求最低泛化誤差,那我們就保留這個n_estimators,除非
# 有其他的因素,可以幫助我們達到更高的準确率。
# 當模型位于圖像左邊時,我們需要的是增加模型複雜度(增加方差,減少偏差)的選項,是以max_depth應該盡量
# 大,min_samples_leaf和min_samples_split都應該盡量小。這幾乎是在說明,除了max_features,我們沒有任何
# 參數可以調整了,因為max_depth,min_samples_leaf和min_samples_split是剪枝參數,是減小複雜度的參數。
# 在這裡,我們可以預言,我們已經非常接近模型的上限,模型很可能沒有辦法再進步了。
# 那我們這就來調整一下max_features,看看模型如何變化。
# 調整max_features
# param_grid = {'max_features':np.arange(5,30,1)}
# """
# max_features是唯一一個即能夠将模型往左(低方差高偏差)推,也能夠将模型往右(高方差低偏差)推的參數。我
# 們需要根據調參前,模型所在的位置(在泛化誤差最低點的左邊還是右邊)來決定我們要将max_features往哪邊調。
# 現在模型位于圖像左側,我們需要的是更高的複雜度,是以我們應該把max_features往更大的方向調整,可用的特征
# 越多,模型才會越複雜。max_features的預設最小值是sqrt(n_features),是以我們使用這個值作為調參範圍的
# 最小值。
# """
# rfc = RandomForestClassifier(n_estimators=39
# ,random_state=90
# )
# GS = GridSearchCV(rfc,param_grid,cv=10)
# GS.fit(data.data,data.target)
# print(GS.best_params_) {'max_features': 5}
# print(GS.best_score_) 0.9718804920913884
# 調整min_samples_leaf
# param_grid={'min_samples_leaf':np.arange(1, 1+10, 1)}
# #對于min_samples_split和min_samples_leaf,一般是從他們的最小值開始向上增加10或20
# #面對高次元高樣本量資料,如果不放心,也可以直接+50,對于大型資料,可能需要200~300的範圍
# #如果調整的時候發現準确率無論如何都上不來,那可以放心大膽調一個很大的資料,大力限制模型的複雜度
# rfc = RandomForestClassifier(n_estimators=39
# ,random_state=90
# )
# GS = GridSearchCV(rfc,param_grid,cv=10)
# GS.fit(data.data,data.target)
# # print(GS.best_params_) {'min_samples_leaf': 1}
# # print(GS.best_score_) 0.9718804920913884
# 不懈努力,繼續嘗試min_samples_split
# # 調整min_samples_split
# param_grid = {'min_samples_split': np.arange(2, 2 + 20, 1)}
# rfc = RandomForestClassifier(n_estimators=39
# , random_state=90
# )
# GS = GridSearchCV(rfc, param_grid, cv=10)
# GS.fit(data.data, data.target)
# # print(GS.best_params_) {'min_samples_split': 2}
# # print(GS.best_score_) 0.9718804920913884
# 最後嘗試一下criterion
# param_grid = {'criterion':['gini', 'entropy']}
# rfc = RandomForestClassifier(n_estimators=39
# ,random_state=90
# )
# GS = GridSearchCV(rfc,param_grid,cv=10)
# GS.fit(data.data,data.target)
# # print(GS.best_params_) {'criterion': 'gini'}
# # print(GS.best_score_) 0.9718804920913884
# 調整完畢,總結出模型的最佳參數
rfc = RandomForestClassifier(n_estimators=39,random_state=90)
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
print(score) # 0.9719568317345088