本文根据 决策树DecisionTree(附代码实现) - 知乎 (zhihu.com)这篇文章为基础进行学习,并且给出自己的总结
1.什么是决策树
决策树是一种基于树结构的有监督学习算法,用于解决分类和回归问题。它通过建立一棵树来对数据进行划分和预测,每个非叶子节点表示一个特征维度上的测试,每个叶子节点表示一个类别或一个数值。
2.如何决策?
对一个东西进行分类和回归,首先就需要了解,我们是根据什么东西来判断它是什么?
1.信息熵
它可以衡量一个事件的不确定性或者说随机性。熵越大,数据的不确定性就越大。 熵越小,数据的不确定性就越小,也就是越确定。
所以我们在做决策的时候要想办法将上述的H(X)弄到最小
使用代码实现我们这个公式
def entropy(y_label):
counter = Counter(y_label)
ent = 0.0
for num in counter.values():
p = num / len(y_label)
ent += -p * log(p)
return ent
3.划分数据集
为什么要划分数据集呢?
划分数据集的目的是为了在构建决策树时,选择最优的特征进行划分,使得在该特征下 不同类别的样本尽可能地被分离到不同子树中,同时保证同一子树中的类别尽量相同,从而 提高决策树的分类或回归性能,下面提供如何划分,和划分一次的代码。
def split(x_data, y_label, dimension, value):
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 = -1
best_value = -1
for 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]) / 2
x_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 = ent
best_dimension = d
best_value = value
return best_entropy, best_dimension, best_value
解释一下其中比较关键的几行代码
sorted_index = np.argsort(x_data[:, d])
这个arrgsort是numpy中的一个排列数组的函数,并且将他们的原来位置记作一个数组返回给sorted_index。
举个简单的例子【1,2,3,4,6,5】
用完那个函数后 sorted_index[5] = 4 sorted_index[4] = 5
if x_data[sorted_index[i], d] != x_data[sorted_index[i - 1], d]:
这个是避免相同数据作为划分点,提高算法效率。
所以划分数据集的目的是对我们已有的数据进行降噪处理,让我们训练得出的东西更具有适用性。
4.建立树
通过将父节点和子节点关联起来组成了树,大概结构长这样
以下是通过python的代码实现的
class Node:
def __init__(self,x_data, y_label, dimension, value):
self.x_data = x_data
self.y_label = y_label
self.dimension = dimension
self.value = value
self.left = None
self.right = None
class DTree:
def __init__(self):
self.root = None
def fit(self,x_train, y_train):
def entropy(y_label):
counter = Counter(y_label)
ent = 0.0
for num in counter.values():
p = num / len(y_label)
ent += -p * log(p)
return ent
def one_split(x_data, y_label):
best_entropy = float('inf')
best_dimension = -1
best_value = -1
for 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]) / 2
x_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 = ent
best_dimension = d
best_value = value
return best_entropy, best_dimension, best_value
def split(x_data, y_label, dimension, value):
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 node
node.left = create_tree(x_left, y_left)
node.right = create_tree(x_right, y_right)
return node
self.root = create_tree(x_train, y_train)
return self
def predict(self,x_predict):
def travel(x_data, node):
p = node
if 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 pred
y_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')"
5.个人总结
在我看来决策树就像是做选择题,对于基于的数据根据提特性不断的选择,就类似于不断的if else ,来一层层判断最后结果