sklearn 决策树例子_决策树DecisionTree(附代码实现)
開局一張圖(網圖,隨便找的)。
對這種類型的圖很熟悉的小伙伴應該馬上就看出來了,這是一顆決策樹,沒錯今天我們的主題就是理解和實現決策樹。
決策樹和我們以前學過的算法稍微有點不一樣,它是個樹形結構。決策樹的決策流程就是從所有輸入特征中選擇一個特征做為決策的依據,找出一個閾值來決定將其劃分到哪一類。
也就是說,創建一個決策樹的主要問題在于:
1.決策樹中每個節點在哪個維度的特征上面進行劃分?
2.被選中的維度的特征具體在哪個值上進行劃分?
為了解決這兩個問題我們引入信息熵的概念。
信息熵的概念本身是信息論中的一個重要概念,因為我們的重點是決策樹,所以就不多涉及信息論的知識,我們只需要知道信息熵是什么。
信息熵簡單的來說就是表示隨機變量不確定度的度量。
熵越大,數據的不確定性就越大。
熵越小,數據的不確定性就越小,也就是越確定。
信息熵的計算公式
其中
是指,數據中一共有n類信息,就是指第i類數據所占的比例。舉個例子,假設我們的數據中一共有三類。每一類所占比例為
,那么信息熵就是假設我們數據一共有三類,每類所占比例是0,0,1,那么信息熵就是
(注:實際上log(0)是不能計算的,定義上不允許,真實場景會做其他處理解決這個問題)很顯然第二組數據比第一組數據信息熵小,也就是不確定性要少,換句話講就是更為確定。
根據這兩個例子,應該就能理解信息熵是隨機變量不確定度的度量了。
如果我們的數據偏向于某一個類別,隨機變量的不確定性就降低了,會變的更為確定。
現在來回答關于決策樹的兩個問題:
1.決策樹中每個節點在哪個維度的特征上面進行劃分?
2.被選中的維度的特征具體在哪個值上進行劃分?
我們希望決策樹每次劃分數據都能讓信息熵降低,當劃分到最后一個葉子節點里面只有一類數據的時候,信息熵就自然的降為了0,所屬的類別就完全確定了。
那么問題來了,我們怎樣找到一個這樣的劃分使得劃分后的信息熵會降低?答案是對著所有維度的特征來一次搜索就行了。
我們來模擬一下這個過程。
導入數據和包
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split import numpy as np import matplotlib.pyplot as plt from collections import Counter from math import logiris = load_iris() x = iris.data y = iris.target x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=666666)計算熵
def entropy(y_label):counter = Counter(y_label)ent = 0.0for num in counter.values():p = num / len(y_label)ent += -p * log(p)return ent劃分數據集
def split(x_data, y_label, dimension, value):"""x_data:輸入特征y_label:輸入標簽類別dimension:選取輸入特征的維度索引value:劃分特征的數值return 左子樹特征,右子樹特征,左子樹標簽,右子樹標簽"""index_left = (x_data[:,dimension] <= value)index_right = (x_data[:,dimension] > value)return x_data[index_left], x_data[index_right], y_label[index_left], y_label[index_right]劃分一次數據集
遍歷所有維度的特征,不斷尋找一個合適的劃分數值,找到能把熵降到最低的那個特征和數值
def one_split(x_data, y_label):best_entropy = float('inf')best_dimension = -1best_value = -1for d in range(x_data.shape[1]):sorted_index = np.argsort(x_data[:, d])for i in range(1,len(x_data)):if x_data[sorted_index[i], d] != x_data[sorted_index[i - 1], d]:value = (x_data[sorted_index[i], d] + x_data[sorted_index[i-1], d]) / 2x_left, x_right, y_left, y_right = split(x_data, y_label, d, value)p_left = len(x_left) / len(x_data)p_right = len(x_right) / len(x_data)ent = p_left * entropy(y_left) + p_right * entropy(y_right)if ent < best_entropy:best_entropy = entbest_dimension = dbest_value = valuereturn best_entropy, best_dimension, best_value第一次模擬劃分
找出最好的劃分維度和對應的數值
best_entropy, best_dimension, best_value = one_split(x_train, y_train) print(best_entropy) print(best_dimension) #第二個維度的特征 print(best_value) #劃分的數值獲取左子樹特征,右子樹特征,左子樹標簽,右子樹標簽
x_left, x_right, y_left, y_right = split(x_train, y_train, best_dimension, best_value)再來一輪劃分
- 左子樹的熵已經是0了,沒必要劃分了
我們繼續劃分右子樹
best_entropy, best_dimension, best_value = one_split(x_right, y_right) print(best_entropy) print(best_dimension) print(best_value)x_left2, x_right2, y_left2, y_right2 = split(x_right,y_right,best_dimension,best_value)經過了兩輪劃分,基本上決策樹已經劃分的差不多了,根據對應維度的特征和閾值決策就行了。如果你熟悉數據結構中的二叉樹結構的話自己就能將決策樹給建起來。
下面給出封裝好的代碼,可以像調用sklearn的決策樹一樣調用它。
class Node:def __init__(self,x_data, y_label, dimension, value):self.x_data = x_dataself.y_label = y_labelself.dimension = dimensionself.value = valueself.left = Noneself.right = Noneclass DTree:def __init__(self):self.root = Nonedef fit(self,x_train, y_train):def entropy(y_label):counter = Counter(y_label)ent = 0.0for num in counter.values():p = num / len(y_label)ent += -p * log(p)return entdef one_split(x_data, y_label):best_entropy = float('inf')best_dimension = -1best_value = -1for d in range(x_data.shape[1]):sorted_index = np.argsort(x_data[:, d])for i in range(1,len(x_data)):if x_data[sorted_index[i], d] != x_data[sorted_index[i - 1], d]:value = (x_data[sorted_index[i], d] + x_data[sorted_index[i-1], d]) / 2x_left, x_right, y_left, y_right = split(x_data, y_label, d, value)p_left = len(x_left) / len(x_data)p_right = len(x_right) / len(x_data)ent = p_left * entropy(y_left) + p_right * entropy(y_right)if ent < best_entropy:best_entropy = entbest_dimension = dbest_value = valuereturn best_entropy, best_dimension, best_valuedef split(x_data, y_label, dimension, value):"""x_data:輸入特征y_label:輸入標簽類別dimension:選取輸入特征的維度索引value:劃分特征的數值return 左子樹特征,右子樹特征,左子樹標簽,右子樹標簽"""index_left = (x_data[:,dimension] <= value)index_right = (x_data[:,dimension] > value)return x_data[index_left], x_data[index_right], y_label[index_left], y_label[index_right]def create_tree(x_data, y_label):ent, dim, value = one_split(x_data, y_label)x_left, x_right, y_left, y_right = split(x_data, y_label, dim, value)node = Node(x_data, y_label, dim, value)if ent < 0.000000001:return nodenode.left = create_tree(x_left, y_left)node.right = create_tree(x_right, y_right)return nodeself.root = create_tree(x_train, y_train)return selfdef predict(self,x_predict):def travel(x_data, node):p = nodeif x_data[p.dimension] <= p.value and p.left:pred = travel(x_data, p.left)elif x_data[p.dimension] > p.value and p.right:pred = travel(x_data, p.right)else:counter = Counter(p.y_label)pred = counter.most_common(1)[0][0]return predy_predict = []for data in x_predict:y_pred = travel(data, self.root)y_predict.append(y_pred)return np.array(y_predict)def score(self,x_test,y_test):y_predict = self.predict(x_test)return np.sum(y_predict == y_test) / len(y_predict)def __repr__(self):return "DTree(criterion='entropy')"測試一下我們的決策樹
dt = DTree() dt.fit(x_train, y_train) dt.score(x_test,y_test)sklearn的決策樹
dt_clf = DecisionTreeClassifier() dt_clf.fit(x_train, y_train) dt_clf.score(x_test, y_test)結果一模一樣,完美!
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的sklearn 决策树例子_决策树DecisionTree(附代码实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: yy神曲url解析php_使用PHP来简
- 下一篇: numpy 数组抽取_Python 关于