查找Damerau-Levenshtein编辑距离算法检测到的错误

如何解决查找Damerau-Levenshtein编辑距离算法检测到的错误

我正在创建一个拼写校正工具,并希望使用贝叶斯定理实现一个嘈杂的频道。为此,我需要计算概率P(X | W),其中X是给定(拼写错误)的单词,W是可能的校正。通过从混淆矩阵中获取一个值来给出概率,该值取决于知道发生了哪种类型的错误,这意味着,例如,如果X =“ egh”和W =“ egg”,则编辑距离将为1,并且错误将是字符2发生的替换错误。

我正在尝试找到一种方法来获取错误“类型”及其发生的字符,但似乎无法使其正常工作。 我尝试过创建TreeMap并在检测到错误时插入i / j值,但这没有用。

我可以假设只有一个错误,这意味着编辑距离恰好是1。

这是我的代码:

public static int DLD(String s1,String s2) {
    if (s1 == null || s2 == null) {  // Invalid input
        return -1;
    }

    if (s1.equals(s2)) {  // No distance to compute
        return 0;
    }

    // The max possible distance
    int inf = s1.length() + s2.length();

    // Create and initialize the character array indices
    HashMap<Character,Integer> da = new HashMap<>();
    for (int i = 0; i < s1.length(); ++i) {
        da.put(s1.charAt(i),0);
    }
    for (int j = 0; j < s2.length(); ++j) {
        da.put(s2.charAt(j),0);
    }

    // Create the distance matrix H[0 .. s1.length+1][0 .. s2.length+1]
    int[][] distances = new int[s1.length() + 2][s2.length() + 2];

    // initialize the left and top edges of H
    for (int i = 0; i <= s1.length(); ++i) {
        distances[i + 1][0] = inf;
        distances[i + 1][1] = i;
    }

    for (int j = 0; j <= s2.length(); ++j) {
        distances[0][j + 1] = inf;
        distances[1][j + 1] = j;

    }

    // fill in the distance matrix H
    // look at each character in s1
    for (int i = 1; i <= s1.length(); ++i) {
        int db = 0;

        // look at each character in s2
        for (int j = 1; j <= s2.length(); ++j) {
            int i1 = da.get(s2.charAt(j - 1));
            int j1 = db;

            int cost = 1;
            if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                cost = 0;
                db = j;
            }

            distances[i + 1][j + 1] = min(
                    distances[i][j] + cost,// substitution
                    distances[i + 1][j] + 1,// insertion
                    distances[i][j + 1] + 1,// deletion
                    distances[i1][j1] + (i - i1 - 1) + 1 + (j - j1 - 1));

        }

        da.put(s1.charAt(i - 1),i);
    }

    return distances[s1.length() + 1][s2.length() + 1];
}

任何解决此问题的提示/方向将不胜感激。

谢谢!

编辑1: 尽管我不确定100%,但我想出了一些办法,它似乎可以正常工作。我用以下代码替换了使用min()方法的代码段:

int sub = distances[i][j] + cost;
int ins = distances[i + 1][j] + 1;
int del = distances[i][j + 1] + 1;
int trans = distances[i1][j1] + (i - i1 - 1) + 1 + (j - j1 - 1);

distances[i + 1][j + 1] = min(sub,ins,del,trans);

if ((distances[i][j] == 0 || distances[i - 1][j] == 0 || 
     distances[i][j - 1] == 0 || distances[i + 1][j + 1] == trans) &&
                    distances[i + 1][j + 1] == 1) {
                
    TreeMap<String,Integer> error = mappingTermAndError.getOrDefault(s2,null);
    if (error != null) {
        error.clear();
    } else {
        error = new TreeMap<>();
    }

    if (distances[i + 1][j + 1] == trans) {
        error.put("trans",i - 2);

    } else if (distances[i + 1][j + 1] == del) {
        error.put("del",i - 1);

    } else if (distances[i + 1][j + 1] == ins) {
        error.put("ins",i - 1);

    } else {  // distances[i + 1][j + 1] == sub
        error.put("sub",i - 1);
    }
    mappingTermAndError.put(s2,error);
}

它的基本作用是获取每种错误类型的值,然后计算最小值。 如果新的最小值为1(因此这是第一个错误),并且距离矩阵中的先前单元格也为0(表示存在一条没有错误的路径导致该点),或者错误是转置的(我们可以仅在知道我们已经出了一个错误之后才知道),然后我用新的错误替换了先前注册的错误,并获得了与该错误所针对的字符相对应的'i'。

我知道此解决方案非常丑陋,而且效率可能不高,因此,如果有人对如何进行改进有任何想法,那就太好了。

解决方法

所涉及的错误类型和字符必须存储在某个地方。您可以将它们放在单独的数据结构中,也可以将它们封装在对象中。

这就是使用对象的样子。为简单起见,我仅实现Levenshtein距离,但是我相信您可以轻松地将该技术应用于Damerau–Levenshtein。

首先,您需要定义一个类,其中封装了有关编辑的信息:成本,父项以及任何其他信息,例如类型(替换,插入,删除)或涉及的字符。为了简单起见,我为这个额外的信息保留了一个名为“ type”的字符串,但是您可能想为错误的类型,字符索引等添加单独的字段。您甚至可能希望使用继承来创建不同的字段具有不同行为的编辑的子类型。

class Edit implements Comparable<Edit> {
    int cost;
    Edit parent;
    String type;

    public Edit() {
        // create a "start" node with no parent and zero cost
    }

    public Edit(String type,Edit parent,int cost) {
        this.type = type;
        this.cost = parent.cost + cost;
        this.parent = parent;
    }

    @Override
    public int compareTo(Edit o) {
        return Integer.compare(this.cost,o.cost);
    }

    @Override
    public String toString() {
        return type;
    }
}

然后,您可以使用此类而不是仅将int用于距离表。在0,0处有一个特殊的起始节点,没有父节点。在其他所有点上,您都需要根据到达该节点所需的最低成本来选择具有一个父节点或另一个父节点的节点。为了更加灵活,让我们从editDistance方法中拆分出矩阵的构建:

Edit[][] buildMatrix(String s1,String s2) {
    Edit[][] distance = new Edit[s1.length() + 1][s2.length() + 1];

    distance[0][0] = new Edit();
    for (int i = 1; i <= s1.length(); i++) {
        distance[i][0] = new Edit("-" + s1.charAt(i - 1),distance[i - 1][0],1);
    }
    for (int j = 1; j <= s2.length(); j++) {
        distance[0][j] = new Edit("+" + s2.charAt(j - 1),distance[0][j - 1],1);
    }

    for (int i = 1; i <= s1.length(); i++) {
        for (int j = 1; j <= s2.length(); j++) {
            int replaceCost = s1.charAt(i - 1) == s2.charAt(j - 1) ? 0 : 1;
            distance[i][j] = Collections.min(List.of(
                // replace or same
                new Edit(s1.charAt(i - 1) + "/" + s2.charAt(j - 1),distance[i - 1][j - 1],replaceCost),// delete
                new Edit("-" + s1.charAt(i - 1),distance[i - 1][j],1),// insert
                new Edit("+" + s2.charAt(j - 1),distance[i][j - 1],1)));
        }
    }

    return distance;
}

然后,“编辑距离”功能仅需承担最后一个节点的费用:

int editDistance(String s1,String s2) {
    Edit[][] distance = buildMatrix(s1,s2);
    return distance[s1.length()][s2.length()].cost;
}

但是由于有了“父”指针,您还可以轻松构建将一个字符串更改为另一个字符串(也称为“ diff”)所需的编辑列表:

List<Edit> diff(String s1,s2);
    List<Edit> diff = new ArrayList<>();
    Edit edit = distance[s1.length()][s2.length()];
    while (edit != distance[0][0]) {
        diff.add(edit);
        edit = edit.parent;
    }
    Collections.reverse(diff);
    return diff;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res