如何计算树编辑距离?

时间:2009-06-30 18:34:56

标签: algorithm tree

我需要为我的个人项目计算树之间的编辑距离。 This论文描述了一种算法,但我不能用它做出正面或反面。您是否了解以更平易近人的方式描述适用算法的任何资源?伪代码或代码也会有所帮助。

8 个答案:

答案 0 :(得分:24)

(编辑此答案以链接到tim.tadh给出的当前版本的实现)

这个Python库正确实现了Zhang-Shasha算法 https://github.com/timtadh/zhang-shasha

它最初是作为当前接受的答案(带有tarball链接的答案)中列出的Java源的直接端口,但该实现不正确,几乎不可能完全运行。

答案 1 :(得分:8)

对于树编辑距离算法,这里有一些java source code(底部是gzipped tarball),可能对您有用。

该页面包含参考资料和一些幻灯片,这些幻灯片分步介绍了“张和莎莎”算法以及其他有用的链接,以帮助您加快速度。

编辑虽然这个答案被接受了,因为它指向了Zhang-Shasha算法,但链接中的代码存在错误。 Steve Johnson和tim.tadh提供了working Python code。有关详细信息,请参阅Steve Johnson's comment

答案 2 :(得分:5)

我基于现有的PyGram Python代码(https://github.com/hoonto/jqgram.git)编写了一个实现(https://github.com/Sycondaman/PyGram),以便那些希望在浏览器中使用PQ-Gram算法使用树编辑距离近似的人和/或者在Node.js.中

jqgram树编辑距离近似模块为服务器端和浏览器端应用程序实现PQ-Gram算法; O(n log n)时间和O(n)空间性能,其中n是节点数。请参阅算法所来自的学术论文:(http://www.vldb2005.org/program/paper/wed/p301-augsten.pdf

PQ-Gram近似比通过Zhang&获得真正的编辑距离快得多。 Shasha,Klein或Guha等。 al,提供真正的编辑距离算法,所有这些算法都执行最少的O(n ^ 2)时间,因此通常不适合。

通常在现实世界的应用程序中,如果可以获得多个树与已知标准的相对近似,则不必知道真正的编辑距离。 Javascript,在浏览器中,现在在服务器上,随着Node.js的出现经常处理树结构和最终用户性能,这在算法实现和设计中通常是至关重要的;因此jqgram。

示例:

var jq = require("jqgram").jqgram;
var root1 = {
    "thelabel": "a",
    "thekids": [
        { "thelabel": "b",
        "thekids": [
            { "thelabel": "c" },
            { "thelabel": "d" }
        ]},
        { "thelabel": "e" },
        { "thelabel": "f" }
    ]
}

var root2 = {
    "name": "a",
    "kiddos": [
        { "name": "b",
        "kiddos": [
            { "name": "c" },
            { "name": "d" },
            { "name": "y" }
        ]},
        { "name": "e" },
        { "name": "x" }
    ]
}

jq.distance({
    root: root1,
    lfn: function(node){ return node.thelabel; },
    cfn: function(node){ return node.thekids; }
},{
    root: root2,
    lfn: function(node){ return node.name; },
    cfn: function(node){ return node.kiddos; }
},{ p:2, q:3, depth:10 },
function(result) {
    console.log(result.distance);
});

请注意,lfn和cfn参数指定每个树应如何独立地确定每个树根的节点标签名称和子数组,以便您可以执行诸如将对象与浏览器DOM进行比较等时髦的事情。您需要做的就是提供这些函数以及每个根,jqgram将完成其余的工作,调用您的lfn和cfn提供的函数来构建树。所以从这个意义上来说,(在我看来)它比PyGram更容易使用。另外,它的Javascript,所以使用它客户端或服务器端!

现在你可以使用的一种方法是使用jqgram或PyGram来获取一些接近的树,然后继续对一小组树使用真正的编辑距离算法,为什么要在树上花掉所有的计算呢?已经很容易确定是非常遥远的,反之亦然。所以你也可以使用jqgram来缩小选择范围。

希望代码可以帮助一些人。

答案 3 :(得分:2)

在这里,您可以找到树编辑距离算法的Java实现:

http://www.inf.unibz.it/dis/projects/tree-edit-distance

除了Zhang& Shasha的1989年算法之外,还有更新算法的树编辑距离实现,包括Klein 1998,Demaine等。 2009年,以及Pawlik& Augsten,2011年的鲁棒树编辑距离(RTED)算法。

答案 4 :(得分:1)

如果有兴趣的话,我使用APTEDjpype算法制作了一个简单的python包装器(apted.py):

# To use, create a folder named lib next to apted.py, then put APTED.jar into it

import os, os.path, jpype 

global distancePackage
distancePackage = None

global utilPackage
utilPackage = None

def StartJVM():
  # from http://www.gossamer-threads.com/lists/python/python/379020
  root = os.path.abspath(os.path.dirname(__file__)) 
  jpype.startJVM(jpype.getDefaultJVMPath(), 
  "-Djava.ext.dirs=%s%slib" % (root, os.sep))
  global distancePackage
  distancePackage = jpype.JPackage("distance")
  global utilPackage
  utilPackage = jpype.JPackage("util")


def StopJVM():
  jpype.shutdownJVM()


class APTED:
  def __init__(self, delCost, insCost, matchCost):
    global distancePackage
    if distancePackage is None:
      raise Exception("Need to call apted.StartJVM() first")
    self.myApted = distancePackage.APTED(float(delCost), float(insCost), float(matchCost))

  def nonNormalizedTreeDist(self, lblTreeA, lblTreeB):
    return self.myApted.nonNormalizedTreeDist(lblTreeA.myLblTree, lblTreeB.myLblTree)


class LblTree:
  def __init__(self, treeString):
    global utilPackage
    if utilPackage is None:
      raise Exception("Need to call apted.StartJVM() first")

    self.myLblTree = utilPackage.LblTree.fromString(treeString)

'''
# Example usage:

import apted
apted.StartJVM()
aptedDist = apted.APTED(delCost=1, insCost=1, matchCost=1)
treeA = apted.LblTree('{a}')
treeB = apted.LblTree('{b{c}}')
dist = aptedDist.nonNormalizedTreeDist(treeA, treeB)
print dist


# When you are done using apted
apted.StopJVM()
# For some reason it doesn't usually let me start it again and crashes python upon exit when I do this so call only as needed
'''

答案 5 :(得分:0)

您在http://www.wisdom.weizmann.ac.il/~oweimann/Publications/TEDinTALG.pdf引用了ICALP2007论文的期刊版本 这个版本也有一个伪代码。

答案 6 :(得分:0)

树编辑距离有很多变化。如果您可以使用自上而下的树编辑距离(限制插入和删除叶子),我建议您尝试以下文章:http://portal.acm.org/citation.cfm?id=671669&dl=GUIDE&coll=GUIDE&CFID=68408627&CFTOKEN=54202965。该实现是一个简单的动态编程矩阵,具有O(n2)成本。

答案 7 :(得分:-6)

我认为你只是在寻找两个顶点之间的最短路径。因此,您可以使用Dijkstra's algorithm。 (维基百科页面上有伪代码供你参考。)