決策樹和隨機(jī)森林既可以解決分類問題荡灾,也可以解決預(yù)測問題。
隨機(jī)森林的構(gòu)建有兩個(gè)方面:數(shù)據(jù)的隨機(jī)性選取拓轻,以及待選特征的隨機(jī)選取。
數(shù)據(jù)的隨機(jī)選染铩:
第一扶叉,從原始的數(shù)據(jù)集中采取有放回的抽樣,構(gòu)造子數(shù)據(jù)集帕膜,子數(shù)據(jù)集的數(shù)據(jù)量是和原始數(shù)據(jù)集相同的枣氧。不同子數(shù)據(jù)集的元素可以重復(fù),同一個(gè)子數(shù)據(jù)集中的元素也可以重復(fù)垮刹。
第二达吞,利用子數(shù)據(jù)集來構(gòu)建子決策樹,將這個(gè)數(shù)據(jù)放到每個(gè)子決策樹中荒典,每個(gè)子決策樹輸出一個(gè)結(jié)果酪劫。最后,如果有了新的數(shù)據(jù)需要通過隨機(jī)森林得到分類結(jié)果寺董,就可以通過對(duì)子決策樹的判斷結(jié)果的投票覆糟,得到隨機(jī)森林的輸出結(jié)果了。
待選特征的隨機(jī)選日诳А:
與數(shù)據(jù)集的隨機(jī)選取類似滩字,隨機(jī)森林中的子樹的每一個(gè)分裂過程并未用到所有的待選特征,而是從所有的待選特征中隨機(jī)選取一定的特征御吞,之后再在隨機(jī)選取的特征中選取最優(yōu)的特征麦箍。這樣能夠使得隨機(jī)森林中的決策樹都能夠彼此不同,提升系統(tǒng)的多樣性陶珠,從而提升分類性能挟裂。
隨機(jī)森林屬于集成算法,森林從字面理解就是由多棵決策樹構(gòu)成的集合揍诽,而且這些子樹都是經(jīng)過充分生長的CART樹话瞧;隨機(jī)表示構(gòu)成多棵決策樹的數(shù)據(jù)是隨機(jī)生成的嫩与,生成過程采用的是Bootstrap抽樣法,運(yùn)行速度快交排,預(yù)測準(zhǔn)確高划滋。
隨機(jī)性具體體現(xiàn)在:一、每棵樹的訓(xùn)練樣本隨機(jī)埃篓;二处坪、樹中每個(gè)節(jié)點(diǎn)的分裂字段也是隨機(jī)選擇的,從而不容易產(chǎn)生過擬合架专。
優(yōu)點(diǎn):
決策樹易于理解和解釋同窘,可以可視化分析,容易提取出規(guī)則部脚;
計(jì)算復(fù)雜度不高想邦,對(duì)中間值的缺失不敏感,可以處理不相關(guān)特征數(shù)據(jù)委刘;
測試數(shù)據(jù)集時(shí)丧没,運(yùn)行速度比較快;
決策樹可以很好的擴(kuò)展到大型數(shù)據(jù)庫中锡移,同時(shí)它的大小獨(dú)立于數(shù)據(jù)庫大信煌;
不需要任何領(lǐng)域知識(shí)或參數(shù)假設(shè)淆珊。
缺點(diǎn):
容易出現(xiàn)過擬合問題夺饲。
對(duì)缺失數(shù)據(jù)處理比較困難。
忽略數(shù)據(jù)集中屬性的相互關(guān)聯(lián)施符。
ID3 算法計(jì)算信息增益時(shí)結(jié)果偏向數(shù)值比較多的特征往声。
改進(jìn)措施(主要解決過擬合問題):
對(duì)決策樹進(jìn)行剪枝,可以采用交叉驗(yàn)證法和正則化的方法戳吝;
使用基于決策樹的 combination 算法烁挟,如 Bagging,Random Forest 等骨坑。
應(yīng)用領(lǐng)域:
企業(yè)管理實(shí)踐撼嗓,企業(yè)投資決策,由于決策樹很好的分析能力欢唾,在決策過程應(yīng)用較多且警。
**隨機(jī)森林的優(yōu)點(diǎn): **
可以處理高維數(shù)據(jù),不同進(jìn)行特征選擇(特征子集是隨機(jī)選擇)
模型的泛化能力較強(qiáng)
訓(xùn)練模型時(shí)速度快礁遣,成并行化方式斑芜,即樹之間相互獨(dú)立
模型可以處理不平衡數(shù)據(jù),平衡誤差
最終訓(xùn)練結(jié)果祟霍,可以對(duì)特種額排序杏头,選擇比較重要的特征
隨機(jī)森林有袋外數(shù)據(jù)(OOB)盈包,因此不需要單獨(dú)劃分交叉驗(yàn)證集
對(duì)缺失值、異常值不敏感
模型訓(xùn)練結(jié)果準(zhǔn)確度高
相對(duì)Bagging能夠收斂于更小的泛化誤差
數(shù)據(jù)預(yù)處理
# 導(dǎo)入第三方模塊
import pandas as pd
# 讀入數(shù)據(jù)
Titanic = pd.read_csv('F:\Titanic.csv')
Titanic.shape
891個(gè)觀測醇王,12個(gè)變量
Titanic.head()
數(shù)據(jù)有下面幾列:
PassengerId呢燥,乘客的標(biāo)識(shí)符;
Survived寓娩,他(她)是否存活了下來,為因變量叛氨,1表示存活,0表示未存活
Pclass棘伴,艙室類別寞埠,也許 1 表示經(jīng)濟(jì)艙,2 表示商務(wù)艙焊夸,3 表示頭等艙仁连;
Name,乘客的名字阱穗;
Sex饭冬,性別;
Age颇象,年齡伍伤;
SibSp并徘,即兄弟姐妹(siblings)或配偶(spouses)遣钳,表示在船上的兄弟姐妹以及配偶的數(shù)目;
Parch麦乞,即父母(Parents)或子女(Children)蕴茴,表示在船上的父母子女的數(shù)目;
Ticket姐直,船票詳情倦淀;
Cabin,艙號(hào)声畏,NaN 表示未知撞叽;
Embarked,登船的起始地插龄,S 表示南安普頓(Southampton)愿棋,Q 表示皇后鎮(zhèn)(Queenstown),C 表示瑟堡(Cherbourg)
PassengerID均牢、Name糠雨、Ticket、Cabin無意義徘跪,此處刪除
# 刪除無意義的變量
Titanic.drop(['PassengerId','Name','Ticket','Cabin'], axis = 1, inplace = True)
#檢查剩余自字是否含有缺失值甘邀,并按行統(tǒng)計(jì)缺失值個(gè)數(shù)
Titanic.isnull().sum(axis = 0)
數(shù)據(jù)清理中最常用的技術(shù)是填充缺失數(shù)據(jù)琅攘。可以用眾數(shù)松邪、平均數(shù)或中位數(shù)來填充缺失數(shù)據(jù)坞琴。選擇這些數(shù)據(jù)沒有絕對(duì)規(guī)則,可以一一嘗試测摔,然后看看它們的表現(xiàn)如何置济。但是根據(jù)經(jīng)驗(yàn)來講,分類數(shù)據(jù)只能用眾數(shù)锋八,連續(xù)數(shù)據(jù)可以用中位數(shù)或平均數(shù)
Age缺失比較多篡撵,不可用均值直接填充琳疏,按照性別對(duì)客戶的缺失年齡分組填充
# 對(duì)Sex分組,用各組乘客的平均年齡填充各組中的缺失年齡
Titanic.Sex.unique()
fillna_Titanic = []
for i in Titanic.Sex.unique():
update = Titanic.loc[Titanic.Sex == i,].fillna(value = {'Age': Titanic.Age[Titanic.Sex == i].mean()}, inplace = False)
fillna_Titanic.append(update)
fillna_Titanic
Embarked缺失較少,此處用眾數(shù)填充
Titanic = pd.concat(fillna_Titanic)
# 使用Embarked變量的眾數(shù)填充缺失值
Titanic.fillna(value = {'Embarked':Titanic.Embarked.mode()[0]}, inplace=True)
Titanic.head()
將數(shù)據(jù)集中的離散變量Pclass冀宴、Sex、Embarked進(jìn)行啞變量處理
以登船地?cái)?shù)據(jù)為例——這是用 Q牢硅、S 或 C 填充的數(shù)據(jù)蒙谓。Python 庫不能處理這個(gè),因?yàn)樗荒芴幚頂?shù)字欺嗤。所以需要獨(dú)熱向量化(One Hot Vectorization)來處理参萄,它可以把一列變成三列。用 0 或 1 填充 Embarked_Q煎饼、Embarked_S 和 Embarked_C讹挎,來表示這個(gè)人是不是從這個(gè)港口出發(fā)的。
# 將數(shù)值型的Pclass轉(zhuǎn)換為類別型吆玖,否則無法對(duì)其啞變量處理
Titanic.Pclass = Titanic.Pclass.astype('category')
# 啞變量處理
dummy = pd.get_dummies(Titanic[['Sex','Embarked','Pclass']])
# 水平合并Titanic數(shù)據(jù)集和啞變量的數(shù)據(jù)集
Titanic = pd.concat([Titanic,dummy], axis = 1)
# 刪除原始的Sex筒溃、Embarked和Pclass變量
Titanic.drop(['Sex','Embarked','Pclass'], inplace=True, axis = 1)
Titanic.head()
表中右邊8個(gè)變量為啞變量
構(gòu)建決策樹模型
# 導(dǎo)入第三方包
from sklearn import model_selection
# 取出所有自變量名稱
predictors = Titanic.columns[1:]
predictors
# 將數(shù)據(jù)集拆分為訓(xùn)練集和測試集,且測試集的比例為25%
X_train, X_test, y_train, y_test = model_selection.train_test_split(Titanic[predictors], Titanic.Survived,
test_size = 0.25, random_state = 1234)
為防止構(gòu)建決策樹過擬合沾乘,需進(jìn)行預(yù)剪枝怜奖,限制樹生長的最大深度,中間節(jié)點(diǎn)能夠繼續(xù)分支的最小樣本量翅阵,葉節(jié)點(diǎn)的最小樣本量
Python提供了網(wǎng)格搜索法歪玲,即調(diào)用GridSearch類選擇最佳的參數(shù)組合
# 導(dǎo)入第三方模塊
from sklearn.model_selection import GridSearchCV
from sklearn import tree
# 預(yù)設(shè)各參數(shù)的不同選項(xiàng)值
max_depth = [2,3,4,5,6]
min_samples_split = [2,4,6,8]
min_samples_leaf = [2,4,8,10,12]
# 將各參數(shù)值以字典形式組織起來
parameters = {'max_depth':max_depth, 'min_samples_split':min_samples_split, 'min_samples_leaf':min_samples_leaf}
parameters
# 網(wǎng)格搜索法,測試不同的參數(shù)值
grid_dtcateg = GridSearchCV(estimator = tree.DecisionTreeClassifier(), param_grid = parameters, cv=10)
# 模型擬合
grid_dtcateg.fit(X_train, y_train)
# 返回最佳組合的參數(shù)值
grid_dtcateg.best_params_
經(jīng)過十重交叉驗(yàn)證掷匠,可得最佳組合值:3,4,2
# 導(dǎo)入第三方模塊
from sklearn import metrics
# 構(gòu)建分類決策樹
CART_Class = tree.DecisionTreeClassifier(max_depth=3, min_samples_leaf = 4, min_samples_split=2)
# 模型擬合
decision_tree = CART_Class.fit(X_train, y_train)
decision_tree
# 模型在測試集上的預(yù)測
pred = CART_Class.predict(X_test)
pred
# 模型的準(zhǔn)確率
print('模型在測試集的預(yù)測準(zhǔn)確率:\n',metrics.accuracy_score(y_test, pred))
此時(shí)因變量為離散變量(分類變量)滥崩,使用準(zhǔn)確率指標(biāo)
當(dāng)因變量為連續(xù)型的數(shù)值,使用均方誤差MSE或者均方根誤差RMSE槐雾,越小代表擬合效果越好夭委,即metrics.mean_squared_error(y_test,pred),在隨機(jī)森林中類似,不再用準(zhǔn)確率,也用MSE株灸。即tree.DecisionTreeClassifier改為Regressor
預(yù)測精度比較高崇摄,但無法體現(xiàn)正例和負(fù)例的覆蓋率,為進(jìn)一步驗(yàn)證模型在測試集上預(yù)測效果慌烧,繪制ROC曲線
# 導(dǎo)入第三方包
import matplotlib.pyplot as plt
y_score = CART_Class.predict_proba(X_test)[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test, y_score)
# 計(jì)算AUC的值
roc_auc = metrics.auc(fpr,tpr)
roc_auc
# 繪制面積圖
plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
# 添加邊際線
plt.plot(fpr, tpr, color='black', lw = 1)
# 添加對(duì)角線
plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
# 添加文本信息
plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
# 添加x軸與y軸標(biāo)簽
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 顯示圖形
plt.show()
ROC曲線下的面積AUC為0.85逐抑,超過0.8,模型擬合效果比較好
下面將決策樹進(jìn)行可視化屹蚊,需要在電腦中安裝Graphviz厕氨, 然后將解壓文件中的bin設(shè)置到環(huán)境變量中
# 導(dǎo)入第三方模塊
from sklearn.tree import export_graphviz
from IPython.display import Image
import pydotplus
from sklearn.externals.six import StringIO
# 繪制決策樹
dot_data = StringIO()
export_graphviz(
decision_tree,
out_file=dot_data,
feature_names=predictors,
class_names=['Unsurvived','Survived'],
# filled=True,
rounded=True,
special_characters=True
)
# 決策樹展現(xiàn)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
Image(graph.create_png())
構(gòu)建隨機(jī)森林模型
# 導(dǎo)入第三方包
from sklearn import ensemble
# 構(gòu)建隨機(jī)森林
RF_class = ensemble.RandomForestClassifier(n_estimators=200, random_state=1234)
# 隨機(jī)森林的擬合
RF_class.fit(X_train, y_train)
# 模型在測試集上的預(yù)測
RFclass_pred = RF_class.predict(X_test)
# 模型的準(zhǔn)確率
print('模型在測試集的預(yù)測準(zhǔn)確率:\n',metrics.accuracy_score(y_test, RFclass_pred))
用隨機(jī)森林確實(shí)提高了測試數(shù)據(jù)集上的預(yù)測準(zhǔn)確率
同樣,也繪制ROC曲線
# 計(jì)算繪圖數(shù)據(jù)
y_score = RF_class.predict_proba(X_test)[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test, y_score)
roc_auc = metrics.auc(fpr,tpr)
# 繪圖
plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
plt.plot(fpr, tpr, color='black', lw = 1)
plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
plt.show()
AUC的值為0.87汹粤,同樣比單棵決策樹的AUC高
再挑選出重要因素
# 變量的重要性程度值
importance = RF_class.feature_importances_
# 構(gòu)建含序列用于繪圖
Impt_Series = pd.Series(importance, index = X_train.columns)
# 對(duì)序列排序繪圖
Impt_Series.sort_values(ascending = True).plot('barh')
plt.show()
年齡命斧,票價(jià),是否為女性是最重要的前三個(gè)因素嘱兼,從而在一定程度上體現(xiàn)婦女和兒童優(yōu)先的原則