我有一个二元决策树。它将输入作为一个浮点数组,每个分支节点在输入索引和值上分割,最终将我带到一个叶子。
我在这棵树上执行了大量的查找(根据性能分析大约有17%的执行时间(编辑:已经优化了其他区域,现在几乎达到了40%)),我想知道我是否可以/应该使用不同的数据结构来提高查找速度。
某些哈希表不能使用,因为输入不直接映射到叶节点,但我想知道是否有人建议我可以用来代替树的方法和数据结构(或者以及?)以提高查找速度。
记忆是一个问题,但不是速度而是关注。
代码目前用C#编写,但显然可以应用任何方法。
编辑: 发布的代码太多了,但我会提供有关树的更多细节。
树是使用信息增益计算生成的,它并不总是50/50分割,分割值可以是任何浮点值。单个输入也可以多次拆分,从而提高该输入的分辨率。
我在这里发布了一个关于迭代器性能的问题:
Micro optimisations iterating through a tree in C#
但我认为我可能需要查看数据结构本身以进一步提高性能。
我的目标是尽可能提高性能。我正在研究一种新的机器学习方法,树使用反馈循环自我增长。对于我正在研究的过程,我估计它将运行几个月,所以在这里节省了几个百分点。最终目标是在不使用太多内存的情况下提高速度。
答案 0 :(得分:2)
如果我理解正确,您的浮点范围必须映射到决策。像这样:
x <= 0.0 : Decision A
0.0 < x <= 0.5 : Decision B
0.5 < x <= 0.6 : Decision C
0.6 < x : Decision D
二叉树是处理它的一种非常好的方法。只要树平衡良好且输入值在范围内均匀分布,就可以预期O(log 2 n)比较,其中n是可能决策的数量。
如果树不平衡,那么你可能会进行比必要更多的比较。在最坏的情况下:O(n)。所以我会看看树木,看看它们有多深。如果一次又一次地使用同一个树,那么一次重新平衡所花费的成本可能会在许多查找中分摊。
如果输入值未均匀分布(并且您提前知道),那么您可能希望特殊情况下比较的顺序,以便尽早检测到最常见的情况。您可以通过操作树或在实际检查树之前在代码中添加特殊情况来完成此操作。
如果您已经用尽了算法改进并且仍然需要优化,那么您可能会研究一种比一般二叉树具有更好局部性的数据结构。例如,您可以将分区边界放入连续的数组中并对其执行二进制搜索。 (并且,如果数组太长,您甚至可能尝试对数组进行线性搜索,因为它可能对缓存和分支预测更友好。)
最后,我考虑构建一个粗略索引,使我们能够了解树(或数组)。例如,使用输入值的一些最重要的位作为索引,看看是否可以切断树的前几层。这可能比您想象的更有帮助,因为跳过的比较可能很难获得正确的分支预测。
答案 1 :(得分:1)
假设决定有50/50的机会:
想象一下你有两个二元决策;可能的路径是00,01,10,11
想象一下,你有一个有四个结果的数组而不是树;你可以将你的浮点数组变成一个二进制数,它将成为这个数组的索引。