1. 程式人生 > >大白話5分鐘帶你走進人工智慧-第二十六節決策樹系列之Cart迴歸樹及其引數(5)

大白話5分鐘帶你走進人工智慧-第二十六節決策樹系列之Cart迴歸樹及其引數(5)

                                                第二十六節決策樹系列之Cart迴歸樹及其引數(5)

上一節我們講了不同的決策樹對應的計算純度的計算方法,其實都是針對分類來說,本節的話我們講解迴歸樹的部分。

目錄

1-Cart迴歸樹的概念

1-程式碼詳解


 

1-Cart迴歸樹的概念

對於迴歸樹來說,之前咱們講的三個決策樹(ID3,C4.5和Cart樹)裡只有CART樹具有迴歸上的意義,其實它無非就是把分裂條件給變了變,把葉子節點的表達給變了變。剩下的全部過程都是和分類樹沒有區別的。它的分裂條件變成什麼了呢?分裂條件仍然是通過遍歷維度搜索。當你搜索完了,嘗試分裂,你要評估這次分裂是好還是不好的時候?不能再使用Gini係數和資訊熵了。因為每一個樣本跟每一個樣本之間的結果都不一樣。你想你原來是怎麼算資訊熵和Gini係數的?先看看我這葉子連線節點有幾類資料,把它們分別統計一下,算出一個數。而回歸問題,它的y lable有一樣的嗎?應該說沒有一樣的。這種情況下肯定不能用剛才那個Gini係數和熵來做了。那用什麼呢,用mse來統計。

舉例比如下圖:

根節點裡有100個數據我嘗試分裂。分裂出兩支來, 一分支是有60個數據。另一支有40個數據。此時怎麼評估這次的分裂效果呢?先計算這60條資料的y的均值。然後用這60條資料的每一個真實的y減去y的均值加平方求和除以60。就得出了這個葉子節點裡邊的平均mse,能夠理解吧?那麼右邊一樣,先是計算出40條y平均。用每一條y減去這個y的平均加平方求和,最後乘以各自的權重,還是要乘以一個1/60和1/40的。那麼你多次嘗試分裂是不是就得到 或者你去想它會把y比較相近的一些節點分到同一個節點裡邊去,對不對? 所以這就是迴歸樹的計算流程。評估每次分裂效果的指標我們叫它mse,它實際上是方差。就是一個集合裡邊的每一個數減去均值平方通通加起來再除以數目本身,假如有十個數,求這10個數的方差,首先要求出它的均值μ,用每一個數減去μ的差的平方,再相加,除一個1/10。這就是這個集合的方差。方差是一個統計學的指標,它描述的是什麼?是這一組資料的離散程度。你方差越大代表這個資料裡邊天差地別,對嗎?天南海北。方差越小,代表這一組資料非常緊密。彼此之間都差不了多少。那我們既然要做迴歸問題,我最終希望落到這個葉子節點裡邊的lable越近越好還是越遠越好?那肯定是越近越好對吧。我分著分著,越分越近,越分越近,最後得到的葉子結點都是最近的那些落到同一個葉子節點。那未來預測的時候怎麼辦?它落到某一個葉子節點了。這個葉子節點是不是不知道應該給它輸出多少值啊?它會輸出多少呢?平均值。能夠理解嗎?也就是說這個東西迴歸分析做出來之後,它是鋸齒狀的。能夠理解嗎?鋸齒狀的一個迴歸分析。例如下圖:

 

就是因為x都落在同一個葉子節點裡邊輸出一個均值。而不象引數型模型了,按理來說,你只要變一點兒,那麼y的結果多多少少都會變一點兒。而這個你的x只要變了一點兒就會影響到你最終落到那一個葉子節點。這樣你給的輸出是不是就都是一樣的了。所以對於迴歸樹來說還是那四個問題。

一、它分幾支,我們剛才看了這個數分兩支,對不對?

二、它怎麼判斷分裂條件。從原來的Gini係數變成了方差。或者說變成了mse

三、它什麼時候停止?還是那些預剪枝的過程。我們後面會講。

四、葉子節點怎麼表達。從原來的投票算概率變成了算平均值。就是這麼簡單。

1-程式碼詳解

我們來看下決策樹的應用程式碼:



import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
import matplotlib as mpl
#讀取iris資料集
iris = load_iris()
#iris['data'] ['target']
# 讀取資料集
data = pd.DataFrame(iris.data)

data.columns = iris.feature_names
print(data.columns )
data['Species'] = load_iris().target
print(data)
print(data.shape)
# #取資料幀的前四列(所有行)也就是X
x = data.iloc[:, :4]  # 花萼長度和寬度
# x = data.iloc[:, :4]  # 花萼長度和寬度
#取資料幀的最後一列(所有行)也就y
y = data.iloc[:, -1]
# print(type(x),1)
# y = pd.Categorical(data[4]).codes
# print(x)
# print(y)

# #訓練集和測試集的劃分
x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.75, random_state=42)

tree_clf = DecisionTreeClassifier(max_depth=6, criterion='entropy')
tree_clf.fit(x_train, y_train)
y_test_hat = tree_clf.predict(x_test)
print("acc score:", accuracy_score(y_test, y_test_hat))
#

# export_graphviz(
#     tree_clf,
#     out_file="./iris_tree.dot",
#     feature_names=iris.feature_names[:2],
#     class_names=iris.target_names,
#     rounded=True,
#     filled=True
# )
#
# # ./dot -Tpng ~/PycharmProjects/mlstudy/bjsxt/iris_tree.dot -o ~/PycharmProjects/mlstudy/bjsxt/iris_tree.png

print(tree_clf.predict_proba([[5, 1.5]]))
print(tree_clf.predict([[5, 1.5]]))
# RandomForestClassifier
#生成一個數組
depth = np.arange(1, 15)#不同的深度對決策樹的影響
err_list = []
for d in depth:
    clf = DecisionTreeClassifier(criterion='entropy', max_depth=d)#預剪枝
    clf.fit(x_train, y_train)
    y_test_hat = clf.predict(x_test)
    result = (y_test_hat == y_test)
    # 生成一個長度為驗證集數量的陣列,每一個元素是yhat和y是否相等的結果,
    print(list(result))
    if d == 1:
        print(result)
    #生成錯誤率
    err = 1 - np.mean(result)
    print(100 * err)
    err_list.append(err)
    print(d, ' 錯誤率:%.2f%%' % (100 * err))
plt.figure(facecolor='w')
plt.plot(depth, err_list, 'ro-', lw=2)
plt.xlabel('決策樹深度', fontsize=15)
plt.ylabel('錯誤率', fontsize=15)
plt.title('決策樹深度和過擬合', fontsize=18)
plt.grid(True)
# plt.show()

from sklearn import tree
X = [[0, 0], [2, 2]]
y = [0.5, 2.5]
clf = tree.DecisionTreeRegressor()#迴歸樹
clf = clf.fit(X, y)
clf.predict([[1, 1]])
# tree_reg = DecisionTreeRegressor(max_depth=2)
# # tree_reg.fit(X, y)

 



解釋下上面程式碼:

1、from sklearn.datasets import load_iris      iris = load_iris(),iris['data'] ['target']。這個iris裡邊就包含了iris(data)和(target),這裡邊有兩種呼叫它的方式。一種你可以寫iris.Data,一種還有這種字典的方式,索引data,實際上sklearn把我們這兩種風格的ATI都保留下來了。

2、我們在這兒引入了一個工具叫pandas,我們之前簡單的講了講numpy就是一個簡單的玩陣列的東西,而pandas就是對numpy簡單的進行了一個加強。原來的numpy是一個數組,pandas給每一列陣列起了一個名字。比如說data是陣列。你想呼叫其中一個元素,用numoy來去你就必須寫data[0,0],而pandas分別給行和列起了索引號。可以使用名稱來更靈活的呼叫它,這是其一,也是最根本的區別。其次,pandas裡邊集成了很多方面的資料操作的東西。這兩個就是一個簡單的tool就是兩個簡單的工具。你學Excel有多難學它就有多難能明所以它不是很複雜的東西。pandas裡邊有一個物件叫dataframe實際上是叫資料幀,資料幀就是一個帶名稱的二維陣列。二維陣列只有索引號。而dataframe加了一個名稱。data = pd.DataFrame(iris.data),我們把這個iris裡邊兒的data拿出來,它是一個numpy陣列。二維陣列。data扔到dataframe中返回的一個什麼東西呢?返回一個panda裡邊叫df的物件。那df物件有兩個屬性。一個叫columns,是指它這個列的名稱。一個叫index是指行的名稱。

3、然後我們通過train_test_split 這個工具來劃分出驗證集和測試集。然後我們新建一個物件叫做DecisionTreeClassifier,然後我們可以看到它實際上有兩個類是決策樹的。DecisionTreeClassifier,DecisionTreeRegressor。分別是什麼意思呢?不用我說大家是不是已經明白了?一個是用來做分類的,一個是用來做迴歸的。

4、我們看下DecisionTreeClassifier的超引數有哪些呢?

criterion,是拿什麼東西來評價的標準。可以取值gini,Gini越高它越不純。也可以取值entropy評估的是資訊增益。

splitter,取值Best是找到最好的那個分裂。取值random是找到最好的隨機分裂,也就是說它隨機多少次之後,把隨機出來過的最好的結果給你。相當於一個加速運算的東西。相當於找到了一個隨機出來的最優解,有點像隨機梯度的意思。

max-depth,樹的最大深度。這個可以說是我們最常用的預剪枝的操作手段。我們很多時候不去設定那些細枝末節的規則。僅僅設一下樹的最大深度,就是你分裂多少層就不要再繼續分裂了。我管你分的好分不好,你都不要再分裂了。

min_samples_split ,除了根結點和葉子結點其他中間的那些節點分裂一個所需要的最小的樣本量預設是2。意思是這些節點要分裂所需的最小樣本數是2。

min_samples_leaf,葉節點最小樣本數。

min_weight_fraction_leaf,就是你這個葉子結點佔總的比例有多少能成為葉子結點,這個比較有意思。

max_features,就是說在你尋找最佳切割點的時候要不要考慮所有的維度咱們本來是不是遍歷所有的維度?現在改成隨機取幾個維度遍歷。不取全了,能明白我的意思嗎?因為它要分裂很多層,雖然第一層沒有考慮到這個維度。第二層的時候有可能就考慮到了,如果是default=none那麼如果是none什麼意思啊?全部的維度都要進來去考慮如果你是int那麼是什麼意思呢?你傳一個整形進來。就是每次在尋找切割的時候就隨機的找到。你比如說乘以六。那麼它就隨機找的六個維度去考慮,尋找最佳切割點。那這樣就肯定會變的不準了,但會變得更快了。然後如果你傳一個浮點數過來那麼實際上是百分比。你比如說傳一個0.6。就是你每一次分裂的時候,就隨機挑選出60%的維度出來,來尋找最佳切割點,如果是auto,是開個根號。比如說你有100個維度。我就給你整十個緯度。能夠理解嗎?sqrt也是開根號。Log2是取個log2然後再取,預設的通常是就選none,有多少我就考慮多少。

max_leaf_nodes ,最多的葉子節點也是,如果葉子節點夠多了,你就不用再分裂了。

min_impurity_decrease ,我們的目的是gini係數必須得變小,我才讓你分裂。你原來的分裂越大,當傳入一個float進來,必須要gini係數必須要縮小多少才能進行此次分裂。

class-weigh,我們可以看到所有的函式,分類器也好,迴歸器也好,都會有這個引數。class-weight代表什麼呢?代表每類樣本,你到底有多麼看重它?它的目的是將不同的類別對映為不同的權值,該引數用來在訓練過程中調整損失函式(只能用於訓練)。該引數在處理非平衡的訓練資料(某些類的訓練樣本數很少)時,可以使得損失函式對樣本數不足的資料更加關注。

5、我們創造一個這個DecisionTreeClassifier,然後輸出acc score,然後輸出我們再驗證集上的準確度,達到了97%,能看到嗎?比之前咱們的邏輯迴歸,訓練及效果要好不少。

6、for d in depth,以及下面的程式碼大致意思是,我把樹的深度從一到15遍歷了一遍。然後分別畫出這15棵樹到底錯誤率是多少。訓練15個模型,我們可以看,隨著樹的深度增加,在4的時候驗證集錯誤率最低,但是後來隨著深度的增加,反倒又上升了。這就有一點點過擬合的意思,但在咱們這個資料集裡很難形成過擬合。因為總共才150條資料。但是這個東西你可以看到,不是說樹越深在驗證集上效果就表現得越好。

下一節裡面我們會講解決策樹的另一個問題即什麼時候停止的問題。

 

 

 

&n