简体   繁体   English

从 C# 中的缩进文件填充二叉决策树

[英]Populate binary decision tree from indented file in C#

I have nested if-else statements generated by the D4.5 algorithm from a dataset in python. I want to transform this into a binary decision tree in Unity C# so I can traverse through it with my NPCs to create simple data-driven AI.我嵌套了由 D4.5 算法从 python 中的数据集生成的 if-else 语句。我想将其转换为 Unity C# 中的二元决策树,以便我可以使用我的 NPC 遍历它来创建简单的数据驱动 AI。

This is my input (currently indented by tabs but I can change it to a sequence of chars or just a number which tells me what level I am currently at):这是我的输入(目前由制表符缩进,但我可以将其更改为一系列字符或只是一个数字,告诉我我目前处于什么级别):

HP is > 0: 
    SeesEnemy is False: 
        HearEnemy is False:
            Idle
        HearEnemy is True:
            Seeking
    SeesEnemy is True:
        EnemyInRange is True:
            Attacking
        EnemyInRange is False:
            Chasing
HP is <= 0:
    Dead

And I want Tree like this with negative child on left and positive on right: Tree我想要这样的树,左边是负孩子,右边是正孩子:

I do not have a problem with the implementation or traversing a tree but with the creation of it from data.我对实现或遍历树没有问题,但对从数据创建它没有问题。

Another variant would be to transform input to this format, which I can deserialize to desired tree: "HP > 0?,Dead,#,#,SeesEnemy?,HearEnemy?,Idle,#,#,Seeking,#,#,EnemyInRange?,Chasing,#,#,Attacking,#,#" Where # means there is no child on left side and #,# means there are no children at all.另一种变体是将输入转换为这种格式,我可以将其反序列化为所需的树:“HP > 0?,Dead,#,#,SeesEnemy?,HearEnemy?,Idle,#,#,Seeking,#,#,EnemyInRange ?,Chasing,#,#,Attacking,#,#" 其中#表示左侧没有孩子,#,#表示根本没有孩子。 This could be ideally done on python side.这可以理想地在 python 端完成。

I tried to read the input line by line while the number of tabs at the start of the line was incrementing like in the Depth-first search.我尝试逐行读取输入,同时行首的制表符数量像深度优先搜索一样递增。 My idea was to create a child of a current node on the left or right side based on false/true (<=/>) and return to the parent when the indentation of the next line was smaller than the previous one and continue with another side.我的想法是根据false/true(<=/>)在左侧或右侧创建当前节点的子节点,并在下一行的缩进小于上一行的缩进时返回父节点并继续下一个边。 But there was a problem with pointing to the current node.但是指向当前节点时出现问题。

I also tried to parse the file in levels (level 0 was "HP is > 0" and "HP is <= 0" etc.) but there were other problems which I could not solve.我还尝试按级别解析文件(级别 0 是“HP > 0”和“HP <= 0”等),但还有其他我无法解决的问题。

I think there is some elegant recursion way to do this but I cannot find it nor figure it out itself.我认为有一些优雅的递归方法可以做到这一点,但我找不到它,也无法自己弄清楚。 Thanks.谢谢。

Instead of building Data Structure Tree and then make a decision traversing, you can build it through expressions.您可以通过表达式构建它,而不是构建数据结构树然后进行决策遍历。 Straight with your boolean conditions and actions and lazy execution of branches.直接使用您的 boolean 条件和操作以及分支的延迟执行。 Just traverse your file and build it through expression tree iterator:只需遍历您的文件并通过表达式树迭代器构建它:

https://learn.microsoft.com/en-us/do.net/csharp/programming-guide/concepts/expression-trees/ https://learn.microsoft.com/en-us/do.net/csharp/programming-guide/concepts/expression-trees/

Then, when you got your final expression you can just invoke (compile and invoke) and it will give you result.然后,当你得到你的最终表达式时,你可以调用(编译和调用)它会给你结果。 I built several DSL on this for my work, which are more complex (with bodies, loops, etc) than your case, so you should be fine.我为我的工作构建了几个 DSL,它们比你的情况更复杂(有主体、循环等),所以你应该没问题。

If you struggle with parsing/traversing you can read more about bottom-up parsing on wiki - https://en.wikipedia.org/wiki/Bottom-up_parsing如果您在解析/遍历方面遇到困难,您可以在 wiki 上阅读更多关于自下而上解析的信息 - https://en.wikipedia.org/wiki/Bottom-up_parsing

To say it simple, you just create stack of simple expressions out of you file (usually constants or simple boolean conditions) and as you go through file, when something complete formed at the tail you transform tail (one or more elements) to next expression, then continue until you parsed entire file.简单来说,您只需从文件中创建一堆简单表达式(通常是常量或简单的 boolean 条件),当您通过文件 go 时,当尾部形成完整的东西时,您将尾部(一个或多个元素)转换为下一个表达式,然后继续,直到您解析了整个文件。

Here is a way to create a tree, using a stack while reading the input string这是一种创建树的方法,在读取输入字符串时使用堆栈

import re

class Node:
    def __init__(self, data, condition=None):
        self.data = data
        self.condition = condition
        self.left = self.right = None

    def add(self, data, test):
        node = Node(data, test)
        if not self.right and self.condition != "False":
            self.right = node
        else:
            self.left = node
        if self.condition in ("False", "True"):
            self.condition = ""
        return node
    
    def preorder(self):
        if self:
            yield self.data + (" " + self.condition if self.condition else "") + ("?" if self.condition is not None else "")
            yield from Node.preorder(self.left)
            yield from Node.preorder(self.right)
        else:
            yield "#"

def tree(s):
    stack = [(-1, Node(None))]
    nodedepth = -1
    for match in re.finditer(r"([ ]*)(\S+)(?: is (.*?):)?[ ]*$", s, re.M):
        depth = len(match[1])
        while depth <= stack[-1][0]:
            nodedepth, node = stack.pop()
        parent = stack[-1][1]
        stack.append((depth, node if nodedepth == depth else parent.add(match[2], match[3])))
    return stack[0][1].right

The tree function makes the tree from a string. tree function 从字符串生成树。 The preorder method can be used to generate the serialized output string in the format you gave (with the hashes). preorder方法可用于以您提供的格式(带有哈希)生成序列化的 output 字符串。

Example run:示例运行:

s = """HP is > 0: 
    SeesEnemy is False: 
        HearEnemy is False:
            Idle
        HearEnemy is True:
            Seeking
    SeesEnemy is True:
        EnemyInRange is True:
            Attacking
        EnemyInRange is False:
            Chasing
HP is <= 0:
    Dead"""

root = tree(s)
print(",".join(root.preorder()))

Output: Output:

HP > 0?,Dead,#,#,SeesEnemy?,HearEnemy?,Idle,#,#,Seeking,#,#,EnemyInRange?,Chasing,#,#,Attacking,#,#

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM