Levenshtein 自动机(拼音纠错)

原文:http://blog.jobbole.com/80659/

 

在上一期的超酷算法中,我们聊到了BK树,这是一种非常聪明的索引结构,能够在搜索过程中进行模糊匹配,它基于编辑距离 (Levenshtein distance),或者任何其它服从三角不等式的度量标准。今天,我将继续介绍另一种方法,它能够在常规索引中进行模糊匹配搜索,我们将它称之为 Levenshtein自动机。

简介

Levenshtein自动机背后的基本理念是:能够构建一个有限状态自动机,准确识别出和某个目标单词相距在给定编辑距离内的所有字符串集合。之 后就好办了,我们可以输入任意单词,自动机能够判断这个单词到目标单词的距离是否大于我们在构建时指定的距离,并选择接收或拒绝。更进一步说,根据FSA 的自然特性,这项工作可以在O(n)时间内完成,取决于测试字符串的长度。与此相比,标准动态编程距离向量算法需要消耗O(mn)时间,m和n分别是两个 输入单词的长度。因此很显然,起码Levenshtein向量机提供了一种更快的方式,供我们针对一个目标单词和最大距离,检查所有的单词,这是一个不错 的改进的开端。
当然,如果Levenshtein向量机只有优点,那这篇文章将会很短。我们将会谈到很多,不过我们先来看一下Levenshtein向量机究竟是何物,以及我们如何建立一个Levenshtein自动机。

构建与评价



 

上图展示了针对单词food的Levenshtein自动机的NFA(译者注:非确定性有限自动机),其最大编辑距离为2。你可以看到,它很普通,构建过程也非常直观。初始状态在左下部分,我们使用ne记法对状态进行命名,n是指到目前为止被处理过的特性的数量,e是指错误的个数。水平线表示没有被修改的特性,垂直线表示插入的值,而两条对角线则分别表示交换(标记a*)和删除。

我们来看一下如何通过一个给定的输入单词和最大编辑距离构建一个NFA,由于整个NFA类是非常标准化的,因此我就不赘述其源码了,如果你需要更多细节,请看Gist。以下是基于Python的相关方法:

def levenshtein_automata(term, k):
  nfa = NFA((0, 0))
  for i, c in enumerate(term):
    for e in range(k + 1):
      # Correct character
      nfa.add_transition((i, e), c, (i + 1, e))
      if e < k:
        # Deletion
        nfa.add_transition((i, e), NFA.ANY, (i, e + 1))
        # Insertion
        nfa.add_transition((i, e), NFA.EPSILON, (i + 1, e + 1))
        # Substitution
        nfa.add_transition((i, e), NFA.ANY, (i + 1, e + 1))
  for e in range(k + 1):
    if e < k:
      nfa.add_transition((len(term), e), NFA.ANY, (len(term), e + 1))
    nfa.add_final_state((len(term), e))
  return nfa

 

这应该很容易实现,基本上我们用了一种最直接了当的方式构建前图中表示的变换,同时也指出了最终正确的状态集。状态标签是元组,而不是字符串,这与我们前面的描述是一致的。

由于这是一个NFA,可以有多个活跃状态,它们表示目前被处理过的字符串的可能解释。举个例子,考虑一下,在处理字符f和x之后的活跃状态:


 

这表明,在前两个字符f和x一致的情况下,会存在若干可能的变化:一次替换,如fxod;一次插入,如fxood;两次 插入,如fxfood;或者一次交换和一次删除,如fxd。同时,这也会引入了一些冗余的情况,如一次删除和一次插入,结果也是fxod。随着越来越多的 字符被处理,其中一些可能性会慢慢消失,而另一些可能性会逐渐产生。如果,在处理完整个单词的所有字符后,在当前状态集中存在一个接收状态(bolded state),那么就表明存在一种方式,能够将通过两次或更少次的变换,将输入单词转化为目标单词,那么我们就可以将该单词视为是有效的。

实际上,要直接评价一个NFA,从计算的角度来讲是极其昂贵的,因为会存在多个活跃状态和epsilon变换(不需要输 入符号的变换),所以通常的做法是首先使用powerset构建法将NFA转换为DFA(译者注:确定性有限自动机)。使用这个算法能够构建出一个 DFA,使每一个状态都对应原来NFA中的一个活跃状态集。在这里我们不会涉及powerset的细节,因为这有点扯远了。以下是一个例子,展示了在一个 容差下,单词food的NFA所对应的DFA:


 

记住,我们是在一个容差下描述DFA的,因为要找出完全匹配我们提到的NFA所对应的DFA实在是太复杂了!以上DFA 能准确接收与单词food相距一个或更少编辑距离的单词集。试试看,选择任意一个单词,通过DFA跟踪它的路径,如果你最终能到达一个接收状态,则这个单 词是有效的。

我不会把power构建的源码贴在这里,同样的,如果你感兴趣,可以在GIST里找到。

我们暂时回到执行效率的问题上来,你可能想知道Levenshtein DFA构建的效率怎么样。我们可以在O(kn)时间内构建NFA,k是指编辑距离,n是指目标单词的长度。将其变换为DFA的最坏情况需要O(2^n)时 间,所以极端情况下会需要O(2^kn)运行时间!不过情况并没有那么糟糕,有两个原因:首先,Levenshtein自动机并不会充斥着2^n这种最坏 情况的DFA构建;其次,一些智慧的计算机科学家已经提出了一些算法,能够在O(n)时间内直接构建出DFA,甚至还有人[SCHULZ2002FAST]完全避开了DFA构建,使用了一种基于表格的评价方法!

索引

既然我们已经证实可以构建一个Levenshtein自动机,并演示了其工作原理,下面我们来看一看如何使用这项技术高效地模糊匹配搜索索引。第一个观点,同时也是很多论文[SCHULZ2002FAST] [MIHOV2004FAST] 所采用的方法,就是去观测一本字典,即你所要搜索的记录集,它自身可以被视为是一个DFA。事实上,他们经常被存储为一种字典树或有向非循环字图,这两种 结构都可以被视为是DFA的特例。假设字典和标准(Levenshtein自动机)都表示为DFA,之后我们就可以高效地通过这两个DFA,准确地在字典 中找到符合标准的单词集,过程非常简单,如下:

def intersect(dfa1, dfa2):
  stack = [("", dfa1.start_state, dfa2.start_state)]
  while stack:
    s, state1, state2 = stack.pop()
    for edge in set(dfa1.edges(state1)).intersect(dfa2.edges(state2)):
      state1 = dfa1.next(state1, edge)
      state2 = dfa2.next(state2, edge)
      if state1 and state2:
        s = s + edge
        stack.append((s, state1, state2))
        if dfa1.is_final(state1) and dfa2.is_final(state2):
          yield s

 

好了,我们按照两个DFA共有的边界同时进行遍历,并记录遍历的路径轨迹。只要两个DFA处于最终状态,单词在输出集内,我们就将其输出。

如果你的索引是以DFA(或字典树,或有向非循环字图)的形式存储的话,这非常完美,但遗憾的是许多索引并不是:如果在 内存中,它们很可能位于一个排序列表中;如果在磁盘上,它们很可能位于BTree或类似结构中。有没有办法可以让我们修改方案适应这些排序索引,继而继续 提供一种速度极快的方法?事实证明是有的。

这里的关键点在于,根据我们目前以DFA表示的标准,我们可以,对于一个不匹配的输入字符串,找到下一个(按字母排序) 匹配的字符串。凭直觉来说,这相当容易:我们基于DFA去评估输入字符串,直到我们无法进一步处理为止,比如说没有针对下一个字符的有效变换,之后,我们 可以反复遵照字母排序的最小标签的边界,直到到达终态。在这里我们应用了两个特殊事件:首先,在第一次变换中,我们需要遵照按字母排序的最小标签,同时这 些标签要大于在准备步骤中没有有效变换的特性。第二,如果我们达到了一个状态而其没有有效的外边界,那么我们要回溯到之前的状态,并重试。这差不多是解决 迷宫问题的一种“循墙”算法,应用在DFA上。

以此举例,参照food(1)的DFA,我们来思考一下输入单词foogle。我们可以有效处理前4个单词,留下状态3141,这里唯一的外边界是d,下一个字符是l,因此我们可以向前回溯一步,到21303141,现在下一个字符是g,有一个外边界f,所以我们接收这个边界,留下接收状态(事实上,和之前的状态是一样的,只不过路径不同),输出单词为fooh,这是在DFA中按字母排序在foogle之后的单词。

以下是python代码,展示了在DFA类上的一个方法。和前面一样,我不会写出整个DFA的样板代码,它们都在这里。

def next_valid_string(self, input):
    state = self.start_state
    stack = []
 
    # Evaluate the DFA as far as possible
    for i, x in enumerate(input):
      stack.append((input[:i], state, x))
      state = self.next_state(state, x)
      if not state: break
    else:
      stack.append((input[:i+1], state, None))
 
    if self.is_final(state):
      # Input word is already valid
      return input
 
    # Perform a 'wall following' search for the lexicographically smallest
    # accepting state.
    while stack:
      path, state, x = stack.pop()
      x = self.find_next_edge(state, x)
      if x:
        path += x
        state = self.next_state(state, x)
        if self.is_final(state):
          return path
        stack.append((path, state, None))
    return None

 

在这个方法的第一部分,我们以常见的方式评价DFA,记录下访问过的状态,这些状态包括它们的路径以及我们尝试寻找遵循 它们的边界。之后,假设没有找到一个准确的匹配项,那么就进行一次回溯,尝试去寻找一个可以到达接收状态的最小变换集。关于这个方法的一般性说明,请继续 阅读……

同时我们还需要一个工具函数find_next_edge,找出一个状态中按字母排序比指定输入大的最小外边界:

def find_next_edge(self, s, x):if x is No

 

def find_next_edge(self, s, x):
    if x is None:
      x = u''
    else:
      x = unichr(ord(x) + 1)
    state_transitions = self.transitions.get(s, {})
    if x in state_transitions or s in self.defaults:
      return x
    labels = sorted(state_transitions.keys())
    pos = bisect.bisect_left(labels, x)
    if pos < len(labels):
      return labels[pos]
    return None
 

 

 

 

经过一些预处理,这可以更高效,打个比方,我们可以对每个字符和第一个大于它的外边界建立一个映射关系,而不是在茫茫大海中进行二进制检索。再强调一次,我会把这些优化工作作为练习题留给读者。

既然我们已经找到了这一过程,那么我们就可以最终描述如何使用这一过程进行索引搜索,算法出人意料的简单:

1. 取得索引中的第一个元素,或者,比索引任意有效字符串更小的一个字符串,将其称之为“当前”字符串。

2. 将“当前”字符串传入我们之前谈到的DFA算法,得到“下一个”字符串。

3. 如果“下一个”字符串和“当前”字符串相等,那么你已经找到了一个匹配,将其输出,再从索引中获取下一个元素作为“当前”元素,重复步骤2。

4. 如果“下一个”字符串和“当前”字符串不相等,那么在你的索引中搜索大于等于“下一个”字符串的第一个字符串,将其作为“当前”元素,重复步骤2。

以下是用Python实现这一过程的代码:

理解这一算法的一种方式是将Levenshtein DFA和索引都视为排序列表,那么以上过程就类似于App引擎中的“拉链合并连接”策略。我们重复地在一侧查找字符串,再跳转到另一侧的合适位置,等等。 结果是,我们省去了大量不匹配的索引实体,以及大量不匹配的Levenshtein字符串,节省了枚举它们的工作量。这些描述表明,这一过程有潜力避免去 评估所有的索引实体,或所有的候选Levenshtein字符串。

补充说明一下,所有的DFA针对任意字符串都可以找到按字母排序的最小后继,这句话是错误的。比如说,考虑一下DFA中 字符串a的后继,识别模式为a+b,答案是没有这样的后继,它必须由无限多的a字符跟随单个b字符构成!不过我们可以基于以上过程做一些简单的修改,比如 返回一个字符串,确保它是DFA可以识别的下一个字符串的一个前缀,这能满足我们的需求。由于Levenshtein DFA总是有限的,因此我们总是会得到一个有限长度的后继(当然,除了最后一个字符串),我们把这样的扩展留给读者作为练习题。使用这种方法,会产生一些 很有意思的应用程序,比如索引化正则表达式搜索。

测试

首先,我们理论联系实际,定义一个简单的Matcher类,其中实现了一个lookup_func方法,它会被find_all_matches方法调用:

记住,在此我们实现一个可调用的类的唯一理由是:我们想要从程序中提取一些信息,比如探针的个数。通常来说,一个常规或嵌套函数已经足够完美,现在,我们需要一个简单的数据集,让我们加载web2字典:

我们也可以使用几个子集测试随着数据规模的变化,会发生什么:

这里,我们看到了实践结果:

大赞啊!在拥有235000个单词的字典中找到了针对nice的23个模拟匹配,需要142个探针。注意,如果我们假设 一个字母表包含26个字母,那么会有4+26*4+26*5=238个字符串在一个Levenshtein距离内是有效的,因此与详尽的测试相比,我们做 出了合理的节省。考虑到有更大的字母表,更长的字符串,或更大的编辑距离,这种节省的效果应该会更明显。如果我们使用不同种类的输入去测试,看一下探针的 个数随着单词长度和字典大小的变化情况,可能会更受启发:

String length

Max strings

Small dict

Med dict

Full dict

1

79

47 (59%)

54 (68%)

81 (100%)

2

132

81 (61%)

103 (78%)

129 (97%)

3

185

94 (50%)

120 (64%)

147 (79%)

4

238

94 (39%)

123 (51%)

155 (65%)

5

291

94 (32%)

124 (43%)

161 (55%)

在这个表中,”max strings”表示与输入字符串在编辑距离内的字符串总数;small,med,full dict表示所有三种字典(包含web2字典的1%,10%和100%)所需要的探针个数。所有对应的行,至少在10个字符以内,都需要与第五行差不多的 探针个数。我们采用的输入字符串的例子是由单词’abracadabra’的前缀构成的。

我们可以立即看出一些端倪:

1. 对于很短的字符串和很大的字典,探针的个数并没有低很多,即使低一些,和有效字符串的最大个数相比也是小巫见大巫,所以这并没有节省什么。

2. 随着字符串越来越长,探针的个数的增长出人意料的比预期结果慢,结果就是对于10个字符,我们仅仅需要探测821中的161个(大约20%)可能结果。对 于一般的单词长度(在web2字典中,97%的单词至少有5个字符长),与朴素的检查每个字符串变化相比,我们已经节省了可观的代价。

3. 虽然样本字典的大小以不同的数量级区分,但是探针的个数增长却不太明显,这是一项令人鼓舞的证据,它表明该方法可以很好的扩展到非常大的索引数量级上。

我们再来看一下根据不同的编辑距离阈值,情况会有何变化,你同样能得到一些启发。下面是相同的表格,最大编辑距离为2:

String length

Max strings

Small dict

Med dict

Full dict

1

2054

413 (20%)

843 (41%)

1531 (75%)

2

10428

486 (5%)

1226 (12%)

2600 (25%)

3

24420

644 (3%)

1643 (7%)

3229 (13%)

4

44030

646 (1.5%)

1676 (4%)

3366 (8%)

5

69258

648 (0.9%)

1676 (2%)

3377 (5%)

前途一片光明:在编辑距离为2的情况下,虽然我们被迫需要加入很多探针,但是与候选字符串的数量相比,仍然是很小的代 价。对于一个长度为5、编辑距离为2的单词,需要使用3377个探针,但是比起做69258次(对每一个匹配字符串)或做234936次(对字典里的每个 单词),这显然少得多了!

我们来做一个快速比较,对于一个长度为5的字符串,编辑距离为1(与上面的例子一样),一个标准的BK树实现,基于相同 的字典,需要检查5858个节点,同时,相同的情况下,我们把编辑距离改为2,则需要检查58928个节点!应当承认,如果结构合理的话,这些节点中很多 都应处于相同的磁盘页,但是依然存在惊人的查找数量级的差异。

最后一点:我们在这篇文章中参考的第二篇论文,[MIHOV2004FAST]描述了一个非常棒的结构:一个广义的Levenshtein自动机。这是一种DFA,它能在线性时间内判断,任意一组单词对互相之间的距离是否小于给定的编辑距离。改造一下我们前面的方案,使其能适应这种自动机,这也是我们留给读者的练习。

Python实战:用Levenshtein库5分钟搞定文本相似度计算(附完整代码) 本文详细介绍了如何使用Python-Levenshtein库快速实现文本相似度计算,包括编辑距离、Jaro-Winkler等核心函数的应用。通过实战案例,如智能纠错、搜索关键词扩展和电商商品标题去重,展示了该库在工程实践中的高效性和灵活性。 阅读详情

相关推荐

stringmatch-automaton:与Levenshtein自动机的字符串匹配

字符串匹配自动机 基于有限状态自动机的字符串匹配。 它使用Levenshtein距离找到近似匹配。 仅使用插入,删除和替换。 可以增加换位。 使它运行的参数: 1:文件位置2:要匹配的图案3:K编辑距离(理想情况下为1..4)4:要显示的结果(1:是/ 0:否) ./fsa / use / share / dict / words木2 0

Lucene5学习之FuzzyQuery使用

     接着学习MultiTermQuery下的另一个Query子类FuzzyQuery,它用于模糊相似度查询,那这里说的相似度是如何判定的?用到的是Damerau-Levenshtein算法,具体这个算法的原理我也不是很清楚,只知道个大概,Levenshtein中文一般翻译为编辑距,何为编辑距?即两个字符串有一个转变成另一个所需要的最小的操作步骤,这里说的操作步骤指的是插入一个字符或修改一...

嘿↗你的益达 5191

快速单词拼写检错程序(字典树实现)

java是实现的快速单词检错程序,内部算法使用字典树匹配。 开发环境netbeans

php levenshtein,php levenshtein 算法原理

[php]代码库//Levenshtein算法,用于计算两个字符串之间的Levenshtein距离。而Levenshtein距离又称为编辑距离,是指两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。function _levenshtein($src, $dst){if (empty($src)) {return $...

weixin_29197699的博客 219

NeuralKG的安装及简单demo使用(浙江大学开源知识图谱表示学习工具)

记录NeuralKG的安装和使用,以及解决windows系统下的运行demo.py出现的问题。

m0_46621271的博客 1397

Unity中USD场景导入与工业级协作实战指南

USD(Universal Scene Description)是一种面向复杂三维场景的结构化数据模型,其核心在于分层描述、变体管理与非破坏性组合,本质是支持多团队并行协作的场景协议。它不同于传统模型格式,强调运行时可编辑性与版本可控性,技术价值体现在跨软件资产一致性、零拷贝动态叠加及内存中实时合成。典型应用场景包括建筑BIM实时漫游、汽车多配置仿真、影视级灯光材质协同等工业管线。在Unity中,USD已深度集成于URP/HDRP管线,通过原生USD Importer、Runtime与Exporter三组件

weixin_32073537的博客 299

Solr进阶之拼写纠错功能的实现基础拼音

思路: 1.当汉字个数小于等于三个汉字时,使用单个词库进行匹配(最大匹配法) 将汉字转为同音字,查询单个词库中的数据,选出音一样的词语列表,加上最小距离算法(保证至少一个汉字一样),得出一个列表,按照一定的算法排序后,选出最好的那个词语. (词语库中词语定时更新,索引对应词语的查询结果) 2.当汉字个数在4到6个数目时,使用最大匹配切词法进行切词处理,切分为单个最大词后,使用1中的排序法则

筑梦者 3234

物联网组网技术优缺点对比:蓝牙、LoRa、wifi、NB-IoT、ZigBee等

1.前言 最近对物联网产品自组网技术选型,找到合适的组网技术,让产品自行组网并完成数据的传输。 2.参数对比

谁念西风独自凉 4万+

超酷算法:Levenshtein自动机

本文由伯乐在线-Justin Wu翻译,黄利民校稿。未经许可,禁止转载! 英文出处:blog.notdot.net。欢迎加入翻译小组。 http://blog.jobbole.com/80659/ 在上一期的超酷算法中,我们聊到了BK树,这是一种非常聪明的索引结构,能够在搜索过程中进行模糊匹配,它基于编辑距离(Levenshtein dista...

weixin_30553777的博客 307

RoboMaster电控入门:手把手教你用STM32CubeMX配置大疆C板CAN总线驱动GM6020电机

本文详细介绍了如何使用STM32CubeMX配置大疆C板CAN总线驱动GM6020电机,适用于RoboMaster电控入门。从硬件准备到CubeMX工程初始化,再到CAN过滤器配置和电机控制协议解析,手把手教你避开常见配置陷阱,实现精准控制。

weixin_42524762的博客 267

openvpn 安装 (Alibaba Cloud Linux release 3 (Soaring Falcon))

1.错误:configure: error: libnl-genl-3.0 package not found or too old. Is the development package and pkg-config (/usr/bin/pkg-config) installed?# ta.key在/etc/openvpn/server/目录下可以如下配置,否则需要写完整路径。# 配置账号密码登录客户端需要ca证书(可选)# 证书校验算法 配置上面生成的完整路径。# ca证书 配置上面生成的完整路径。

dubhe_zhao的博客 2148

【nlp】query纠错的笔记

背景:用户输入query的时候有时会出现手误的情况,这时就需要给与正确的纠正,来提高用户体验。如下图所示:用户搜索“周杰仑”会直接显示“周杰伦”的搜索结果并提升用户是否仍然搜索“周杰仑”。 中文纠错: 中文纠错与英文的构成区别很大,通常中文词语往往比较短,通常一个词的编辑距离会产生大量的候选集。由于拼音打字法的普及几乎所有的字都是通过拼音打字出来的,因此中文字的错误其实可以归结到拼音构成的...

小屋 2464

利用正射影像对斜射图像进行反向投影

因此,RANSAC算法可以通过计算inliners和outliers的数量来评估估计关键点的质量,确保与其他点不一致的点不会在Homography矩阵中被估计。然后,它通过考虑关键点周围区域中图像的梯度大小和方向来计算每个提取的关键点的方向。由于单应性矩阵的计算可能会受到两个图像中异常值的存在的影响,这将导致矩阵的不正确估计并导致沿图像的对准和映射不良。FLANN匹配器的方法基于K近邻搜索的概念,即从图像中找到k个近邻。找到相机在正射影像坐标系中的位置并在正射影像上绘制重叠区域的边界框。

gis收藏家的博客 1510

Levenshtein编辑距离实战:从字符串纠错到毫秒级自动补全

Levenshtein距离是衡量两个字符串差异的基础算法,其核心原理是通过插入、删除、替换三种单字符操作计算最小变换步数。该算法虽源于动态规划理论,但在搜索推荐、输入法纠错、IDE智能提示等工程场景中承担着关键的语义相似性量化任务。它并非万能——原始距离缺乏长度归一化、无法区分前缀匹配与中间错拼、对人类拼写规律(如ie/ei、邻键错误)不敏感。因此,工业级应用必须完成三重升级:引入键盘距离加权提升纠错合理性,结合Trie树实现O(m)前缀检索以支撑实时补全,再融合词频与规则引擎增强语言感知能力。本文聚焦真实

weixin_34379433的博客 392

使用C# HslCommunication库实现三菱PLC通信(含完整代码示例)

在工业自动化开发中,上位机与PLC的通信是关键环节。HslCommunication库是一个开源的.NET工业通信库,支持三菱、西门子、欧姆龙等多个品牌PLC的通信协议。本文将演示如何通过库实现C#程序与三菱PLC的通信,并提供完整的代码示例。

StevenChen的博客 2287

X-AnyLabeling-main标注YOLO关键点POSE

同一物体的框和点的 群组编号 要相同。代表这些点和方框是同一物体上的。标注方框之后记得把后面的。顺序要和你标注的顺序一致。写入1,而且之后的点的。配置导出文件.yaml。

qq_53545309的博客 2101

智能术语纠错器:基于HanLP的高效精准纠错方案

本文提出了一种基于HanLP和编辑距离的智能术语纠错器TermCorrectorFinal。该工具通过HanLP分词划定候选区域,结合编辑距离模糊匹配和智能大小写保留策略,实现了高效精准的术语纠正。核心设计包括:利用分词结果限定纠错范围、内存词典分桶存储、最大编辑距离为1的模糊匹配以及大小写保留机制。系统采用轻量级纯内存架构,支持线程安全集成,特别适用于医学术语、产品名称等专业领域的文本纠错。实验表明,该方法能有效处理拼写错误、同音错别字及大小写变体问题,相比传统词典映射方法具有更高的灵活性和准确性。

杨海吉 446

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

别再用模糊匹配了!用Python-Levenshtein库5分钟搞定文本查重与纠错

本文介绍了如何使用Python-Levenshtein库快速实现文本查重与纠错,通过编辑距离算法智能匹配相似文本,提升电商搜索、用户反馈处理等场景的效率。相比传统模糊匹配,编辑距离能量化文本相似性,准确识别简繁体、拼写错误和同义词差异。

weixin_30919429的博客 331

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

数据对齐-编辑距离算法详解(Levenshtein distance)

总结一句话:编辑距离就是从一个字符串变到另外一个字符串所需要最小的步骤 一:简介 在信息论、语言学和计算机科学中,Levenshtein distance是用于测量两个字符串之间差异的字符串度量。非正式的说就是两个单词之间的Levenshtein distance是将一个单词更改为另一个单词所需的单字符编辑(插入,删除或替换)的最小步骤。 它以苏联数学家弗拉基米尔·莱文斯坦(Vladimir Le...

weixin_34015860的博客 761

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

中文术语纠错追踪系统详解

本文介绍了一个带追踪功能的中文医学术语纠错与归一化引擎。该工具能自动修正文本中的错别字术语(如"心机梗塞"→"心肌梗塞"),并记录修改详情,包括原始词、修正词、位置和编辑距离。核心功能包括轻量分词(基于FMM算法)、模糊纠错(基于编辑距离)和过程追踪。系统架构包含分词器、术语词典和纠错追踪模块,输出修正后文本和详细修改记录。文章还提供了性能优化建议(如使用HanLP分词器、BK-Tree算法)和扩展方案(支持拼音纠错等)。该工具适用于医疗文本处理、电子病历质控等场景,

杨海吉 393

纠错

1.百度中文纠错技术 百度中文纠错一方面需要支持多种类型的错误识别,另一方面需要支持不同模态的输入数据,同时还需要提供快速的场景迁移以及深度定制能力。 2.基于语言模型的拼写纠错 给定一个自然语言的句子,识别出其中出错的汉字或词语,并对其进行纠正 3.美团BERT的探索和实践 模型优化 ...

u012606924的博客 374

Levenshtein距离及其python实现

概念      Levenshtein距离,又称L氏编辑距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。原子编辑操作包括增、删、改,即插入一个字符,删除一个字符,将一个字符替换成另一个字符。一般来说,Levenshtein距离越小,两个串的相似度越大。Levenshtein 距离已经在DNA分析、拼音纠错、命名实体抽取、实体共指、机器翻译等方面有广泛应用。

SYP'S Blog 5664

字符串相似度处理(python Levenshtein和jellyfish)

是两个常用的库,用于计算字符串之间的相似度或距离(如编辑距离、语音匹配等)。它们在自然语言处理(NLP)、数据清洗、模糊匹配等场景中非常有用。:提供多种字符串匹配算法,包括编辑距离、语音编码(Soundex、Metaphone)、拼音匹配等。(编辑距离),即通过插入、删除、替换操作将一个字符串转换成另一个字符串所需的最少步骤。如果有具体的使用场景,可以进一步讨论最佳实践!:快速计算字符串之间的。在 Python 中,

cambriannn的博客 641

探析搜索引擎纠错机制:技术演进与实践案例

• 案例:用户输入“how to book a hotel in Beijing”,但误写“book”为“booK”,必应搜索不仅纠正拼写,还会识别“book a hotel”与“预订酒店”的语义等价性,同时返回中英文预订信息。典型应用:Google Search的“语义纠错”功能,能将“谁是相对论的创始人”的误写“谁是相对轮的创始人”,通过理解“相对论”的学科背景完成纠正。局限:无法处理未收录的新词(如“共享单车”早期误写),且对语义理解为零,曾出现过将“钓鱼岛”误纠为“钓鱼道”的争议案例。

2501_91651657的博客 642

搜索引擎纠错机制中的算法与模型解析

当算法不仅能识别“写错字”,还能理解“说反话”“打比方”甚至“欲言又止”时,纠错机制将真正成为连接人类表达与信息世界的“智能桥梁”——或许某天,我们对着搜索引擎说出“我想要那个能拍照的、薄薄的、苹果家的东西”,即便用词模糊,系统也能精准递上最新款iPhone,这便是算法与模型共同编织的智能未来。例如用户输入“我需要预订明天去北京的fei机”,模型结合“预订”“北京”“明天”的语境,将“fei机”纠正为“飞机”,而非“肥鸡”。• 应用场景:在分词纠错中,识别“西湖措鱼”的“措”为错误字。

2501_91651657的博客 614
上一篇: BK-Tree算法(模糊匹配)
下一篇: float的存储方式
eric509
博客等级 码龄19年 8粉丝 170原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值