第8.6节 连续型特征变量下决策树实现
各位朋友大家好,欢迎来到月来客栈,我是掌柜空字符。
本期推送内容目录如下,如果本期内容对你有所帮助,欢迎点赞、转发支持掌柜!
8.6 连续型特征变量下决策树实现 8.6.1 特征离散化实现 8.6.2 信息熵与条件熵实现 8.6.3 决策树构建实现 8.6.4 样本预测实现 8.6.5 使用示例 8.6.6 小结 引用
8.6 连续型特征变量下决策树实现
在上一节内容中,笔者详细介绍了如何基于ID3与C4.5的原理来一步一步从零开始实现决策树模型,不过由于原始的决策树模型均是针对离散型的特征变量,因此并不能对连续型的特征变量进行建模处理。在这节内容中笔者将采用sklearn库中的做法来对连续型特征进行离散化处理,并以此来实现ID3与C4.5的建模过程。值得一提的是,在sklearn中不管输入的是离散型变量还是连续型变量,都会先对其以同样的方式来进行离散化处理,下面笔者也将采用同样的做法来进行处理。
8.6.1 特征离散化实现
由于在第8.5节内容中笔者已经详细介绍了对于离散型特征输入的ID3与C4.5的决策树实现过程,因此接下来只需要以之前的代码框架为基础,对其中部分判断逻辑进行修改即可。在实现这部分内容之前,笔者先来介绍如何对特征进行离散化。本节所有实现代码可参见Book/Chapter08/C14_id3_continuous.py
文件。
根据第8.2.5节内容可知,连续型特征变量的离散化过程可以先对原始特征进行排序处理,然后取所有连续两个值的均值来离散化整个连续型特征变量。在清楚上述特征离散化的原理后,便可以来进一步对其编码实现,实现代码如下所示:
1 def _get_feature_values(self, data):
2 n_features = data.shape[1]
3 feature_values = {}
4 for i in range(n_features):
5 x_feature = sorted(set(data[:, i])) # 去重与排序
6 tmp_values = [x_feature[0]] # 左边插入最小值
7 for j in range(1, len(x_feature)):
8 tmp_values.append(round((x_feature[j - 1] + x_feature[j]) / 2, 4))
9 tmp_values.append(x_feature[-1]) # 右边插入最大值
10 feature_values[i] = tmp_values
11 return feature_values
在上述代码中,第2行是得到特征的维度数量;第4~5行是遍历每一列特征维度并进行排序以及去重处理;第7~8行是计算得到两两相邻的特征值之间的平均值作为离散特征;第6、9行是为了方便后续决策树的实现,所以在离散化特征的两边分别加入了原始特征中的最小值和最大值。
最终,通过上述方法便可以得到离散化后的数据特征。例如对于如下测试数据来说
1 x = np.array([[3, 4, 5, 6, 7],
2 [2, 2, 3, 5, 8],
3 [3, 3, 8, 8, 9.]])
4 x = _get_feature_values(x)
5 print(x)
6 {0: [2.0, 2.5, 3.0], 1: [2.0, 2.5, 3.5, 4.0], 2: [3.0, 4.0, 6.5, 8.0],
7 3: [5.0, 5.5, 7.0, 8.0], 4: [7.0, 7.5, 8.5, 9.0]}
在上述结果中,第6~7行便是原始输入特征离散化后的结果,其中key
表示特征维度的ID,value
表示该特征维度对应的离散化特征取值。
8.6.2 信息熵与条件熵实现
在完成特征离散化的编码工作后,下一步便可以开始对第8.5.2中实现的代码进行修改以满足离散化特征的需求。信息熵的计算代码修改如下所示:
1 def _compute_entropy(self, y_class):
2 y_unique = np.unique(y_class)
3 if y_unique.shape[0] == 1: # 只有一个类别
4 return 0. # 熵为0
5 ety = 0.
6 for i in range(len(y_unique)): # 取每个类别
7 p = np.sum(np.abs(y_class - y_unique[i]) < 0.0001) / len(y_class)
8 ety += p * np.log2(p)
9 return -ety
在上述代码中,第1行是定义一个方法来计算信息熵,主要用于ID3和C4.5中计算样本的信息熵,以及C4.5中特征的信息熵;第2行是计算得到当前输入有多少重类别(或特征取值);第3~4行则是判断如果只有一个类别则信息熵为0;第6~8行是分别遍历么一个类别,然后计算信息熵。值得注意的是,因为同时要计算特征维度的信息熵,而特征是浮点型所以一般不会用==
来判断两者是否相等。
为你认可的知识付费,欢迎订阅本专栏阅读更多优质内容!