分割数据集需要对每行数据进行迭代,根据每个数据点相应属性的值与阈值的大小情况将该数据点放到相应的部分(对应树结构中的左叉与右叉)。 如下是一个名为 test_split() 的函数,它能实现上述功能: # Split a dataset based on an attribute and an attribute value def test_split(index, value, dataset): left, right = list(), list() for row in dataset: if row[index] < value: left.append(row) else: right.append(row) return left, right 代码还是很简单的。 注意,在代码中,属性值大于或等于阈值的数据点被分类到了右组中。 2.2.2 评价所有分割点 在基尼函数 gini_index() 和分类函数 test_split() 的帮助下,我们可以开始进行评估分割点的流程。 对给定的数据集,对每一个属性,我们都要检查所有的可能的阈值使之作为候选分割点。然后,我们将根据这些分割点的成本(cost)对其进行评估,最终挑选出最优的分割点。 当最优分割点被找到之后,我们就能用它作为我们决策树中的一个节点。 而这也就是所谓的穷举型贪心算法。 在该例中,我们将使用一个词典来代表决策树中的一个节点,它能够按照变量名储存数据。当选择了最优分割点并使用它作为树的新节点时,我们存下对应属性的下标、对应分割值及根据分割值分割后的两部分数据。 分割后地每一组数据都是一个更小规模地数据集(可以继续进行分割操作),它实际上就是原始数据集中地数据按照分割点被分到了左叉或右叉的数据集。你可以想象我们可以进一步将每一组数据再分割,不断循环直到建构出整个决策树。 如下是一个名为 get_split() 的函数,它能实现上述的步骤。你会发现,它遍历了每一个属性(除了类别值)以及属性对应的每一个值,在每次迭代中它都会分割数据并评估该分割点。 当所有的检查完成后,最优的分割点将被记录并返回。 # Select the best split point for a dataset def get_split(dataset): class_values = list(set(row[-1] for row in dataset)) b_index, b_value, b_score, b_groups = 999, 999, 999, None for index in range(len(dataset[0])-1): for row in dataset: groups = test_split(index, row[index], dataset) gini = gini_index(groups, class_values) if gini < b_score: b_index, b_value, b_score, b_groups = index, row[index], gini, groups return {'index':b_index, 'value':b_value, 'groups':b_groups} 我们能在一个小型合成的数据集上来测试这个函数以及整个数据集分割的过程。 X1 X2 Y 2.771244718 1.784783929 0 1.728571309 1.169761413 0 3.678319846 2.81281357 0 3.961043357 2.61995032 0 2.999208922 2.209014212 0 7.497545867 3.162953546 1 9.00220326 3.339047188 1 7.444542326 0.476683375 1 10.12493903 3.234550982 1 6.642287351 3.319983761 1 (责任编辑:本港台直播) |