检查决策树中的歧义

时间:2013-09-08 15:42:30

标签: python machine-learning scikit-learn

我正在使用sklearn的决策树来取代业务规则的混乱和不可持续的实现,作为一个长if-elif-else链。我使用数千个测试用例对所有标签验证树,但有时我用作训练数据的规则的表有错误,有些测试随机失败。

我需要一种方法来验证树,超出结果的测试用例。假设所有叶节点的gini = 0.0,使用不同的随机种子生成的树的分类中没有随机变化,这是正确的吗?如果我需要在我的应用程序上强制执行该操作,在更新培训数据时检查是否合理?

请注意,我的情况不是典型的分类问题,因为我已经在代码中实现了决策树,并且我想使用算法从精心定制的数据生成等效树,而不是真实的数据样本,仅仅因为在我的情况下,使用业务规则维护数据集比维护代码更容易。

因此,在我的数据集中,功能将理想地涵盖所有可能的值范围,并为此提供一个明确的标签。例如,虽然现实世界的训练集可能类似于:

features = [[1], [1.1], [2], [2.3]]
labels = ['sativa', 'sativa', 'indica', 'indica']

一个算法可以随机出现一个tree1,如:

if feature < 1.75:
    return 'sativa'
else:
    return 'indica'

和树2一样:

if feature < 1.55:
    return 'sativa'
else:
    return 'indica'

但是,我的训练集不会出现随机性发生的差距。这就像是:

features = [[1], [1.9], [2], [2.3]]
labels = ['sativa', 'sativa', 'indica', 'indica']

因此,无论初始随机状态如何,树总是(显然忽略低于0.1的差异)​​:

if feature < 1.95:
    return 'sativa'
else:
    return 'indica'

我的问题正是我需要验证训练集是否存在错误,并且存在可能发生随机变化的值的间隙,或者是否将相同的一组要素分配给不同的标签。修复随机状态并不能解决这个问题,只能保证相同的数据始终会生成相同的树。

那么,有没有办法确定这是否发生在树上,除了在生成树之前验证这些问题的数据,或者进行多次大规模的综合测试以排除随机变化?< / p>

1 个答案:

答案 0 :(得分:1)

由于您拥有标签规则并了解功能的可能范围,因此您可以实现目标。

让我们用例子

来形象化

基尼指数

基尼指数是什么意思?它试图使您刚刚制作的树中的训练集合适合,并告诉他们的项目有多么错误。因此,在Tree1和Tree2中,你有gini = 0,因为训练集中的每个例子都会被正确标记。

Tree1和Tree2具有相同的训练集,并且gini = 0.0。但是,如果我们尝试标记x = [1.7],我们将得到不同的结果。

解决方案

由于您已了解将特征集与其相应标签绑定的规则,因此可以确保给定训练集,它将始终生成一个树,输出正确的结果,对于任何可能的特征,如果:

  • 连续值的要素位于范围内,例如。 [2,30]
  • 您可以拥有精确阈值,例如。上面的例子至少以0.1步变化
  • 您可以为每种可能的组合生成示例
  • 你的树有gini = 0.0

(基本上,我们告诉你,因为gini = 0.0,那么如果你给出一个在训练集中的输入,它将被正确标记。这里没有巨大的跳跃结论。)

所以,如果:

   feature1 one of numpy.linspace(1,2,11) = [1., 1.1, 1.2, 1.3, ..., 2]
   feature2 one of True or False

    Your examples have all the possible linear combinations 
    You have sum(all gini nodes) = 0
    The future examples are inside the condition boundaries of the training set

然后你可以肯定:

    You covered all possible examples
    All possible examples are labeled correctly

这样,随机初始化的随机树将具有相同的输出。它们可能仅在训练集范围之外的示例中有所不同,或者具有值不符合阈值规则的值。

猜猜你已经这样做了,但最好是使用测试覆盖率工具创建训练集,以确保创建所有可能的示例。

关于在连续值中使用所有可能值的必要性

当我说你需要拥有连续值的所有可能值时,我都非常小心,比如[1.0,1.1,1.2,...... 1.9,2.0]。如果该功能仅在一个节点中使用,则只能使用边界值(示例中为1.9和2.0)。但是,如果您的if-elses更复杂,我们可能会遇到一些无法预测的复杂场景。在评估特征f1的节点之后,我们稍后可以在左边生成的节点上具有类似(如果f2> 5)的条件,以及右边节点中的a(如果f2&lt; 3),或类似的东西。你可能会得到错误的结果。

如果您的组合太大,那么将功能二值化可能是个好主意。如果你有一个连续的功能,如:

    if f1 > 3: f1 = 'many'
    if 3 <= f1 < 0 = 'little'

使用DictVectorizer对象将其转换为(1 0)和(0 1)。

虽然您正在增加维度,但您的决策树只会为这两个功能创建一个节点。如果它只检查第一个是否为真,则第二个是多余的,因为它们是互斥的。

如果您没有数据边界,这也是一种解决方案。如果你有没有范围的ax特征,你可以像(x <0,0&lt; = x&lt; 5,5&lt; = x)那样二值化,将连续值转换为(1 0 0),(0 1 0)或(0 0 1),允许您评估所有可能的组合。

通过这种方式,您可以从根本上减少组合集的大小。

希望如此。 干杯!