1. 程式人生 > >資料探勘入門系列教程(四)之基於scikit-lean實現決策樹

資料探勘入門系列教程(四)之基於scikit-lean實現決策樹

    • 資料探勘入門系列教程(四)之基於scikit-lean決策樹處理Iris
      • 載入資料集
      • 資料特徵
      • 訓練
      • 隨機森林
      • 調參工程師
      • 結尾

資料探勘入門系列教程(四)之基於scikit-lean決策樹處理Iris

在上一篇部落格,我們介紹了決策樹的一些知識。如果對決策樹還不是很瞭解的話,建議先閱讀上一篇部落格,在來學習這一篇。

本次實驗基於scikit-learn中的Iris資料。說了好久的Iris,從OneR到決策樹,那麼Iris到底長啥樣呢?


載入資料集

首先我們還是需要先載入資料集,資料集來自scikit自帶的iris資料集,資料集的內容可以參考以前的部落格,這裡就不在贅述。

首先讓我們從scikit-learn中載入資料集。

from sklearn.datasets import load_iris
dataset = load_iris()
data = dataset.data
target = dataset.target

然後我們再使用pandas將資料進行格式化以下,新增Iris的屬性到資料集中。

import numpy as np
import pandas as pd
data = pd.DataFrame(data,columns=["sepal_length","sepal_width","petal_length","petal_width"])
data["class"] = target

data的資料如下所示:


class代表類別。其他的就是Iris的屬性了。

資料特徵

這裡我們主要是用畫圖來看一看Iris資料集的特徵。本來以為畫圖就matpotlib就行了,但是沒想到有seaborn這個好使用的庫,來自B站up主的提示。使用的庫如下:

  • matplotlib
  • seaborn

首先我們畫散點圖:

import matplotlib.pyplot as plt
import seaborn as sb
# data.dropna()去除裡面的none元素
sb.pairplot(data.dropna(),hue="class")

影象如下所示:


上面的這幅圖展示了在四個屬性中的類別的分別情況。

同時我們還可以畫小提琴圖:

plt.figure(figsize=(20, 20))
for column_index, column in enumerate(data.columns):
    if column == 'class':
        continue
    plt.subplot(2, 2, column_index + 1)
    sb.violinplot(x='class', y=column, data=data)

畫出的圖如下:


通過上面的這幅圖我們可以直觀的比較出哪一個變數更具有代表性。比如說petal_width 對類別0更加的友好。

接下來就是進行訓練了。

訓練

首先的首先,我們還是需要從資料集中抽出訓練集和測試集。這個內容在前面講過了,就不多講了。

from sklearn.model_selection import train_test_split

input_data = data[["sepal_length","sepal_width","petal_length","petal_width"]]
input_class =  data["class"]

train_data,test_data,train_class,test_class = train_test_split(input_data,input_class,random_state = 14)

then,讓我們來開始進行訓練吧,在scikit-learn中實現了決策樹,和前面的K近鄰演算法一樣我們直接引用就行,呼叫fit(訓練)和predict(預測)函式。使用如下所示:

from sklearn.tree import DecisionTreeClassifier

decision_tree = DecisionTreeClassifier(random_state=14)
decision_tree.fit(train_data,train_class)
predict_class = decision_tree.predict(test_data)
predict_score = np.mean(predict_class == test_class)
print("預測的準確度為{}".format(predict_score))

DecisionTreeClassifier其他的引數在後面說,這裡主要說一下random_state引數。為什麼決策樹還需要random_state這個引數,以下知乎上面的兩位博主的說法。



至於哪個說法是正確的,我暫時也不知道,如果有知道的,可以在評論區留言哦!

最後得到的預測結果如下所示:


這裡值得注意的是DecisionTreeClassifier()函式,裡面可以新增很多引數。官方文件在這裡: https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html 。

這裡還是稍微的說一下引數。

# criterion  gini(預設)/tropy:這裡對應的就是之前的熵增益和Gini係數

# splitter  best(預設)/random 每個結點選擇的拆分策略

# max_depth  樹的最大深度。

# min_samples_split int型別或者float(預設2) 如果某節點的樣本數少於min_samples_split,則不會進行拆分了。浮點值表示分數,代表所佔比例

# min_samples_leaf 預設=1 這個值限制了葉子節點最少的樣本數,如果某葉子節點數目小於樣本數,則會和兄弟節點一起被剪枝。

# min_weight_fraction_leaf float(預設0.0) 這個值限制了葉子節點所有樣本權重,如果小於這個值,則會和兄弟節點一起被剪枝。一般來說,如果我們有較多樣本有缺失值,或者分類樹樣本的分佈類別偏差很大,就會引入樣本權重,這時我們就要注意這個值了。

# max_features int, float or {“auto”, “sqrt”, “log2”}(預設0.0)

# max_leaf_nodes 通過限制最大葉子節點數,可以防止過擬合,預設是"None”,即不限制最大的葉子節點數。如果加了限制,演算法會建立在最大葉子節點數內最優的決策樹。

# class_weight dict/balanced 指定樣本各類別的的權重,主要是為了防止訓練集某些類別的樣本過多導致訓練的決策樹過於偏向這些類別。這裡可以自己指定各個樣本的權重。“balanced”,則演算法會自己計算權重,樣本量少的類別所對應的樣本權重會高。

# min_impurity_split 這個值限制了決策樹的增長,如果某節點的不純度(基尼係數,資訊增益,均方差,絕對差)小於這個閾值則該節點不再生成子節點。即為葉子節點 。

更多的可以去看官網細節。

然後我們可以將這個樹的結構視覺化,將檔案儲存在“tree.dot”中:

from sklearn.tree import export_graphviz
with open("tree.dot",'w') as f:
    export_graphviz(decision_tree, feature_names =['sepal_length', 'sepal_width', 'petal_length', 'petal_width'], out_file = f)

這個是決策樹的圖:


同樣,我們還可以使用交叉驗證,具體的使用可以參考別人的部落格,或者看我的這一篇部落格:

from sklearn.model_selection import cross_val_score
decision_tree = DecisionTreeClassifier()
scores = cross_val_score(decision_tree,input_data,input_class,scoring='accuracy')
print("交叉驗證結果: {0:.2f}%".format(np.mean(scores) * 100))

通過交叉驗證得到的準確度如下:


比上面的結果略低,不過這個是正常的。

隨機森林

前面的部落格介紹了隨機樹,這裡不多做介紹,直接看使用吧。我們通過匯入RandomForestClassifier模組,並指令森林中樹的個數為30,具體的引數看官網

from  sklearn.ensemble import RandomForestClassifier
rft = RandomForestClassifier(n_estimators=20,random_state=14)
rft.fit(train_data,train_class)
predict_class = rft.predict(test_data)
predict_score = np.mean(predict_class == test_class)
print("隨機森林預測的準確度為{}".format(predict_score))

最後的結果如下圖

然後進行交叉驗證:

scores = cross_val_score(rft,input_data,input_class,scoring='accuracy')
print("Accuracy: {0:.2f}%".format(np.mean(scores) * 100))

結果如下:


emm,好像和上面的結果一樣,因為這個資料集很小,可能會有這種情況。

調參工程師

首先,我們可以對決策樹的max_feature和max_depth進行調參,改變其值,最終的結果如下:


在隨機森林中,我們可以對樹的個數進行調參,結果如下圖:


結尾

這次並沒有使用《 Python資料探勘入門與實踐 》書上的例子,實在是它打籃球的資料找不到,emm。相比較與oneR演算法的70%左右的正確率,決策樹95%正確率已經算足夠優秀了。

儘管程式碼寫起來很簡單,也很容易實現得到結果,但是我們真正應該瞭解的是裡面的內涵:決策樹是什麼?裡面是怎樣工作的?以及所蘊含的含義……

專案地址:GitHub