sklearn開卷:一、決策樹——22.8.9~11


一、決策樹:

包中所包含的各種樹;

1.1 建模流程:

  • 這個(gè)流程適用于所有的模型:

第一步要知道使用函數(shù)的參數(shù)有些啥;
第二步就是找哪個(gè)接口來(lái)用,幾乎所有都可以用 fit 接口;
第三步就是根據(jù)指標(biāo)對(duì)生成的模型進(jìn)行打分;

  • 分類樹對(duì)應(yīng)代碼:

1.1.2 分類樹 與紅酒數(shù)據(jù)集

class sklearn.tree.DecisionTreeClassifier (criterion=’gini’,splitter=’best’,max_depth=None,min_samples_split=2,min_samples_leaf=1, min_weight_fraction_leaf=0.0,max_features=None,random_state=None,max_leaf_nodes=None,min_impurity_decrease=0.0, min_impurity_split=None,class_weight=None, presort=False)

1.1.2.1 重要參數(shù)

(1)criterion
  • 作用: 決定不純度(類似于熵)的 計(jì)算方法
    (1)輸入“entropy”,使用信息熵;
    (2)輸入“gini”,使用基尼指數(shù);
    他倆對(duì)應(yīng)的算法:

比起基尼系數(shù),信息熵對(duì)不純度更加敏感,對(duì)不純度的懲罰最強(qiáng)。但是在實(shí)際使用中,信息熵和基尼系數(shù)的效果基本相同。

  • 這個(gè)參數(shù)的影響:
  • 決策樹的基本流程:

1.導(dǎo)入需要的庫(kù)和模塊

from sklearn import tree 
 #用于生成數(shù)據(jù)集的模塊,dataset是自帶的一個(gè)數(shù)據(jù)庫(kù),里頭有很多數(shù)據(jù)
from sklearn.datasets import load_wine
#導(dǎo)入訓(xùn)練集和測(cè)試集的類
from sklearn.model_selection import train_test_split 

2.探索數(shù)據(jù)

import pandas as pd
#把特征矩陣和標(biāo)簽變成一張表,axis參數(shù)是用來(lái)連接的
pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1) 
  1. 分訓(xùn)練/測(cè)試集
#這里要注意前面的循序,test_size=0.3說(shuō)明30%做測(cè)試機(jī),70%做訓(xùn)練集;
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3) 
# f/target_names可以用來(lái)在構(gòu)建決策樹的時(shí)候作為分割點(diǎn)的提示
wine.feature_names

wine.target_names

4.建立模型clf

clf = tree.DecisionTreeClassifier(criterion="entropy") #實(shí)例化
clf = clf.fit(Xtrain, Ytrain) #fit就是拿來(lái)訓(xùn)練的接口
score = clf.score(Xtest, Ytest) #返回預(yù)測(cè)準(zhǔn)確度

score #訓(xùn)練集和測(cè)試集隨即劃分,所以得到的結(jié)果是不一樣的

5.畫出決策樹

feature_name = ['酒精','蘋果酸','灰','灰的堿性','鎂','總酚','類黃酮','非黃烷類酚類','花青素','顏色強(qiáng)度','色調(diào)','od280/od315稀釋葡萄酒','脯氨酸']

import graphviz
#clf參數(shù)是上面訓(xùn)練好的模型;feature_names是特征名字;class_names是標(biāo)簽的名字,前面默認(rèn)是0,1,2;filled是框的顏色,round是框的形狀;
dot_data = tree.export_graphviz(clf
                                ,out_file = None
                                ,feature_names = feature_name
                                ,class_names=["琴酒","雪莉","貝爾摩德"]
                                ,filled=True
                                ,rounded=True
)
graph = graphviz.Source(dot_data)
graph

6.探索決策樹

#特征重要性,有用的話就有值,不然就是0
clf.feature_importances_

#把重要性和對(duì)應(yīng)的名字連接起來(lái)
[*zip(feature_name,clf.feature_importances_)]
#結(jié)果為:
#[('酒精', 0.0),
# ('蘋果酸', 0.0),
# ('灰', 0.03424265229804312),
# ('灰的堿性', 0.0),
# ('鎂', 0.0),
# ('總酚', 0.0),
# ('類黃酮', 0.4212422739689356),
# ('非黃烷類酚類', 0.0),
# ('花青素', 0.0),
# ('顏色強(qiáng)度', 0.24875172479063973),
# ('色調(diào)', 0.0),
# ('od280/od315稀釋葡萄酒', 0.0),
# ('脯氨酸', 0.2957633489423816)]

#用random_state來(lái)控制隨機(jī)性,是來(lái)設(shè)置分枝中的隨機(jī)模式的參數(shù)
clf = tree.DecisionTreeClassifier(criterion="entropy",random_state=30)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回預(yù)測(cè)的準(zhǔn)確度

score
#0.9629629629629629(這里的值會(huì)因?yàn)槊看芜x的訓(xùn)練/測(cè)試集不同而發(fā)生變化)

不難看出,由于每次選的訓(xùn)練/測(cè)試集不同而導(dǎo)致這個(gè)模型的得分每次都不一樣,這對(duì)于實(shí)際應(yīng)用來(lái)說(shuō)十分不利,所以就有了下面的這個(gè)玩意兒;


(2)random_state & splitter
  • 作用:
    (1)random_state用來(lái)設(shè)置分枝中的隨機(jī)模式的參數(shù),默認(rèn)None,在高維度時(shí)隨機(jī)性會(huì)表現(xiàn)更明顯,低維度的數(shù)據(jù)(比如鳶尾花數(shù)據(jù)集),隨機(jī)性幾乎不會(huì)顯現(xiàn)。輸入任意整數(shù),會(huì)一直長(zhǎng)出同一棵樹,讓模型穩(wěn)定下來(lái);
    (2)splitter用來(lái)控制決策樹中的隨機(jī)選項(xiàng)的,有兩種輸入值,輸入”best",決策樹在分枝時(shí)雖然隨機(jī),但是還是會(huì)優(yōu)先選擇更重要的特征進(jìn)行分枝(重要性可以通過(guò)屬性feature_importances_查看),輸入“random",決策樹在分枝時(shí)會(huì)更加隨機(jī),樹會(huì)因?yàn)楹懈嗟牟槐匾畔⒍罡?,并因這些不必要信息而降低對(duì)訓(xùn)練集的擬合;
clf = tree.DecisionTreeClassifier(criterion="entropy"
                                    ,random_state=30
                                     ,splitter="random"
)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
score
#0.9259259259259259(不會(huì)變了,是從一大堆中選出最優(yōu)的那個(gè))

import graphviz
dot_data = tree.export_graphviz(clf
                                   ,feature_names= feature_name
                                   ,class_names=["琴酒","雪莉","貝爾摩德"]
                                   ,filled=True
                                   ,rounded=True
)
graph = graphviz.Source(dot_data)
graph

由于增加了隨機(jī)性所以這個(gè)樹變得很大


(3)剪枝參數(shù)
  • 作用:為了讓決策樹有更好的泛化性,sklearn為我們提供了不同的剪枝策略:
  • max_depth:限制樹的最大深度,超過(guò)設(shè)定深度的樹枝全部剪掉,建議從3開始用;
  • min_samples_leaf & min_samples_split:
    (1)min_samples_leaf(分支后)限定,一個(gè)節(jié)點(diǎn)在分枝后的每個(gè)子節(jié)點(diǎn)都必須包含至少min_samples_leaf個(gè)訓(xùn)練樣本,否則分枝就不會(huì)發(fā)生,一般從5開始用。如果葉節(jié)點(diǎn)中含有的樣本量變化很大,建議輸入浮點(diǎn)數(shù)作為樣本量的百分比來(lái)使用。同時(shí),這個(gè)參數(shù)可以保證每個(gè)葉子的最小尺寸,可以在回歸問(wèn)題中避免低方差,過(guò)擬合的葉子節(jié)點(diǎn)出現(xiàn)。對(duì)于類別不多的分類問(wèn)題,=1通常就是最佳選擇(不絕對(duì));
    (2)min_samples_split(分支前)限定,一個(gè)節(jié)點(diǎn)必須要包含至少min_samples_split個(gè)訓(xùn)練樣本,這個(gè)節(jié)點(diǎn)才允許被分枝,否則分枝就不會(huì)發(fā)生;
#對(duì)前面得到的決策樹進(jìn)行剪枝:
clf = tree.DecisionTreeClassifier(criterion="entropy"
                                     ,random_state=30
                                     ,splitter="random"
                                     ,max_depth=3
                                     #,min_samples_leaf=10
                                     #,min_samples_split=10
                                     )
clf = clf.fit(Xtrain, Ytrain)
dot_data = tree.export_graphviz(clf
                                   ,feature_names= feature_name
                                   ,class_names=["琴酒","雪莉","貝爾摩德"]
                                   ,filled=True
                                   ,rounded=True
                                   )
graph = graphviz.Source(dot_data)
graph

生成的樹就是:


clf.score(Xtrain,Ytrain)
#0.9596774193548387
clf.score(Xtest,Ytest)
#0.9444444444444444
#發(fā)現(xiàn)此時(shí)的準(zhǔn)確率竟然比之前的要高。。。說(shuō)明下面那些沒(méi)用的
  • max_features & min_impurity_decrease:
    (1)max_features限制分枝時(shí)考慮的特征個(gè)數(shù),超過(guò)限制個(gè)數(shù)的特征都會(huì)被舍棄,但其方法比較暴力,是直接限制可以使用的特征數(shù)量而強(qiáng)行使決策樹停下的參數(shù),可能省去一些比較重要的參數(shù);
    (2)min_impurity_decrease限制信息增益的大小,信息增益小于設(shè)定數(shù)值的分枝不會(huì)發(fā)生;

  • 確認(rèn)最優(yōu)的剪枝參數(shù):用超參數(shù)的學(xué)習(xí)曲線來(lái)進(jìn)行確認(rèn),是一條以超參數(shù)的取值為橫坐標(biāo),模型的度量指標(biāo)為縱坐標(biāo)的曲線,它是用來(lái)衡量不同超參數(shù)取值下模型的表現(xiàn)的線:

#專門用來(lái)可視化的模塊
import matplotlib.pyplot as plt
test = []
#利用for循環(huán)建模后測(cè)試其在測(cè)試集上的表現(xiàn)并繪制學(xué)習(xí)曲線
for i in range(10):
        clf = tree.DecisionTreeClassifier(max_depth=i+1
                                         ,criterion="entropy"
                                         ,random_state=30
                                         ,splitter="random"
                                         )
        clf = clf.fit(Xtrain, Ytrain)
        score = clf.score(Xtest, Ytest)
        test.append(score)
plt.plot(range(1,11),test,color="red",label="max_depth")
plt.legend()
plt.show()
  • 問(wèn)題:
  1. 剪枝參數(shù)一定能夠提升模型在測(cè)試集上的表現(xiàn)嗎? - 調(diào)參沒(méi)有絕對(duì)的答案,一切都是看數(shù)據(jù)本身;
  2. 這么多參數(shù),一個(gè)個(gè)畫學(xué)習(xí)曲線? - 在泰坦尼克號(hào)的案例中,我們會(huì)解答這個(gè)問(wèn)題。

(4)目標(biāo)權(quán)重參數(shù):
  • class_weight & min_weight_fraction_leaf:(這倆很少用
    (1)class_weight完成樣本標(biāo)簽平衡的參數(shù)。樣本不平衡是指在一組數(shù)據(jù)集中,標(biāo)簽的一類天生占有很大的比例。使用class_weight參數(shù)對(duì)樣本標(biāo)簽進(jìn)行一定的均衡,給少量的標(biāo)簽更多的權(quán)重,讓模型更偏向少數(shù)類,向捕獲少數(shù)類的方向建模,默認(rèn)是None,此模式表示自動(dòng)給與數(shù)據(jù)集中的所有標(biāo)簽相同的權(quán)重;
    (2)min_weight_fraction_leaf基于權(quán)重的剪枝參數(shù),有了權(quán)重之后,樣本量就不再是單純地記錄數(shù)目,而是受輸入的權(quán)重影響了,所以這時(shí)候剪枝就要配合這個(gè)一起用了;

1.1.3 重要屬性和接口

  • fit、score**:前面用過(guò)了,不想再說(shuō)了;
  • apply:返回每個(gè)測(cè)試樣本所在的葉子節(jié)點(diǎn)的索引;
  • predict:返回每個(gè)測(cè)試樣本的分類/回歸結(jié)果;

上面這兩個(gè)接口只輸入測(cè)試集的特征,而不需要標(biāo)簽

注意:所有接口中要求輸入X_train和X_test的部分,輸入的特征矩陣必須至少是一個(gè)二維矩陣。sklearn不接受任何一維矩陣作為特征矩陣被輸入,如果真就硬塞給只有一個(gè)特征,那必須用reshape(-1,1)來(lái)給矩陣增維;如果你的數(shù)據(jù)只有一個(gè)特征和一個(gè)樣本,使用reshape(1,-1)來(lái)給你的數(shù)據(jù)增維;


總結(jié)

  • 八個(gè)參數(shù):Criterion,兩個(gè)隨機(jī)性相關(guān)的參數(shù)(random_state,splitter),五個(gè)剪枝參數(shù)(max_depth,min_samples_split,min_samples_leaf,max_feature,min_impurity_decrease);
  • 一個(gè)屬性:feature_importances_
  • 四個(gè)接口:fit,score,apply,predict

1.2 回歸樹

classsklearn.tree.DecisionTreeRegressor(criterion=’mse’,splitter=’best’,max_depth=None,min_samples_split=2,min_samples_leaf=1,min_weight_fraction_leaf=0.0,max_features=None,random_state=None,max_leaf_nodes=None,min_impurity_decrease=0.0,min_impurity_split=None, presort=False)

  • 幾乎所有參數(shù),屬性及接口都和分類樹一模一樣。需要注意的是,在回歸樹種,沒(méi)有標(biāo)簽分布是否均衡的問(wèn)題,因此沒(méi)有class_weight這樣的參數(shù)。

1.2.1 重要參數(shù)、接口

(1)criterion:

  • 作用:回歸樹衡量分枝質(zhì)量的指標(biāo);
  • 支持的標(biāo)準(zhǔn):
    1.輸入"mse"使用均方誤差mean squared error(MSE),父節(jié)點(diǎn)和葉子節(jié)點(diǎn)之間的均方誤差的差額將被用來(lái)作為特征選擇的標(biāo)準(zhǔn),這種方法通過(guò)使用葉子節(jié)點(diǎn)的均值來(lái)最小化L2損失;
    2.輸入“friedman_mse”使用費(fèi)爾德曼均方誤差,這種指標(biāo)使用弗里德曼 針對(duì)潛在分枝中的問(wèn)題改進(jìn)后 的均方誤差;
    3.輸入"mae"使用絕對(duì)平均誤差MAE(mean absolute error),這種指標(biāo)使用 葉節(jié)點(diǎn)的中值 來(lái)最小化L1損失屬性中最重要的依然是feature_importances_,接口依然是apply, fit, predict, score最核心。

在回歸中,我們追求的是,MSE越小越好。然而,回歸樹的接口score返回的是R平方,并不是MSE。R平方被定義如下:

其中u是殘差平方和(MSE * N),v是總平方和,N是樣本數(shù)量,i是每一個(gè)數(shù)據(jù)樣本,fi是模型回歸出的數(shù)值,yi是樣本點(diǎn)i實(shí)際的數(shù)值標(biāo)簽。y帽是真實(shí)數(shù)值標(biāo)簽的平均數(shù)。R2可以為正為負(fù)(如果模型的殘差平方和遠(yuǎn)遠(yuǎn)大于模型的總平方和,模型非常糟糕,R平方就會(huì)為負(fù)),而均方誤差永遠(yuǎn)為正。

注意: 雖然均方誤差永遠(yuǎn)為正,但是sklearn當(dāng)中使用均方誤差作為評(píng)判標(biāo)準(zhǔn)時(shí),卻是計(jì)算”負(fù)均方誤差“(neg_mean_squared_error),而真正的均方誤差MSE的數(shù)值,其實(shí)就是neg_mean_squared_error去掉負(fù)號(hào)的數(shù);


(2)交叉驗(yàn)證:默認(rèn)就是k折交叉驗(yàn)證:

#用波士頓房?jī)r(jià)數(shù)據(jù),因?yàn)榛貧w型用的是連續(xù)變量
from sklearn.datasets import load_boston
#直接調(diào)用cross_val_score方法來(lái)進(jìn)行交叉驗(yàn)證
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeRegressor
boston = load_boston()
regressor = DecisionTreeRegressor(random_state=0)
#前三個(gè)給沒(méi)啥好說(shuō)的,第四個(gè)就是k;第五個(gè)是指明衡量標(biāo)準(zhǔn)
cross_val_score(regressor, boston.data, boston.target, cv=10, 
                    scoring = "neg_mean_squared_error")
#交叉驗(yàn)證cross_val_score的用法

輸出結(jié)果為:

不寫 scoring = "neg_mean_squared_error"的話就是越接近1的越好;寫了之后就是越接近0越好


1.2.2 案例:一維回歸的圖像繪制

  • 1.導(dǎo)入需要的庫(kù)
#numpy用于生成圖上曲線
import numpy as np
from sklearn.tree import DecisionTreeRegressor
#畫圖的
import matplotlib.pyplot as plt
  • 2.創(chuàng)造一條含有噪聲的曲線
#用numpy生成一個(gè)隨機(jī)樹的種子,但是是是一種固定的隨機(jī)
rng = np.random.RandomState(1)

#生成隨機(jī)樹,下面這個(gè)函數(shù)隨機(jī)生成0到1之間隨機(jī)樹
5*rng.rand(80,1)
#生成二維的樹是為了能夠進(jìn)行擬合(接口不允許一維的特征)

#np.sort()用來(lái)排序,從小到大排序,X就是橫坐標(biāo)的數(shù)據(jù)
X = np.sort(5 * rng.rand(80,1), axis=0)
#用sin函數(shù)來(lái)求y,因?yàn)閥只能是一維的,所以要用ravel函數(shù)來(lái)進(jìn)行降維
y = np.sin(X).ravel()

此時(shí)所的圖像為:

加噪聲,模擬現(xiàn)實(shí)的抽樣狀況(通過(guò)給其某些數(shù)據(jù)加上/減去一個(gè)值來(lái)進(jìn)行)
#::是用來(lái)切片的,5表示步長(zhǎng)
y[::5] += 3 * (0.5 - rng.rand(16))
#為了構(gòu)建一個(gè)通用性高的模型,所以要避免對(duì)這些有噪聲的點(diǎn)進(jìn)行擬合

此時(shí)所的圖像為:

3.實(shí)例化&訓(xùn)練模型

#建兩個(gè)模擬,用來(lái)區(qū)別不同條件下的擬合情況
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)

4.測(cè)試集導(dǎo)入模型,預(yù)測(cè)結(jié)果

#了解增維切片np.newaxis的用法
#這里在對(duì)測(cè)試集進(jìn)行增維,必要是二維的
l = np.array([1,2,3,4])
l.shape
#(4,)
l[:,np.newaxis] 
#array([[1],[2],[3],[4]])
l[:,np.newaxis].shape
#(4, 1)
l[np.newaxis,:].shape
#(1, 4)

#arange(開始點(diǎn),結(jié)束點(diǎn),步長(zhǎng))大于等于開始點(diǎn),小于結(jié)束點(diǎn)
#測(cè)試集是用arange生成的一堆隨機(jī)數(shù)
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)
#np.arrange(開始點(diǎn),結(jié)束點(diǎn),步長(zhǎng)) 生成有序數(shù)組的函數(shù)#測(cè)試集是用arange生成的一堆隨機(jī)數(shù)
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)
#np.arrange(開始點(diǎn),結(jié)束點(diǎn),步長(zhǎng)) 生成有序數(shù)組的函數(shù)

5.繪制圖像

#對(duì)于matplotlib的具體應(yīng)用
#figure是弄了塊畫布
plt.figure()
#c是點(diǎn)的顏色,label就是點(diǎn)的名字,s是點(diǎn)的大小
plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")
#plot是畫折線的,label是線的名字,可輸入也可以不輸入
plt.plot(X_test, y_1, color="cornflowerblue",label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2)

plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
#顯示圖例
plt.legend()
#把代碼所生成的圖畫出來(lái)
plt.show()

藍(lán)色的線和正弦的曲線比另外一個(gè)更貼合,那么綠色的線所對(duì)應(yīng)的回歸樹就是過(guò)擬合(受到噪聲影響)


總結(jié)

我們可以看到,如果樹的最大深度(由max_depth參數(shù)控制)設(shè)置得太高,則決策樹學(xué)習(xí)得太精細(xì),它從訓(xùn)練數(shù)據(jù)中學(xué)了很多細(xì)節(jié),包括噪聲得呈現(xiàn),從而使模型偏離真實(shí)的正弦曲線,形成過(guò)擬合。


1.3 實(shí)例:泰坦尼克號(hào)幸存者的預(yù)測(cè)

去看看jupyter的代碼部分

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容