數據挖掘入門系列教程(四)之基於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