【问题标题】:Efficient way of resolving unknown words to known words?将未知单词解析为已知单词的有效方法?
【发布时间】:2012-06-16 19:06:13
【问题描述】:

我正在设计一个文本处理程序,该程序将从一个长的逐项文本文档中生成一个关键字列表,并为含义相似的单词组合条目。那里有一些指标,但是我遇到了一个新问题,即处理不在我正在使用的字典中的单词。

我目前正在使用 nltk 和 python,但我这里的问题具有更抽象的性质。给定一个不在字典中的单词,将其解析为字典中的单词的有效方法是什么?我目前唯一的解决方案是遍历字典中的单词并从输入的单词中选择具有最短 Levenshtein 距离(编辑距离)的单词。

显然,这是一种非常缓慢且不切实际的方法,我实际上并不需要字典中的绝对最佳匹配,只要它是包含的单词并且非常接近即可。在解决方案中,效率对我来说更为重要,但也需要基本的准确性。

关于如何将一些未知单词通常解析为字典中的已知单词有什么想法吗?

【问题讨论】:

  • 虽然它们都非常酷,而且肯定在正确的轨道上,但我正在寻找不会像 Levenshtein Automata 中那样拒绝任何单词的东西,并且不需要那么大的存储空间BK 树可以。
  • 这是否意味着您想找到与字典任意距离的单词的匹配项? (例如,在supercalifragilisticexpiladocious 中寻找thepneumonoultramicroscopicsilicovolcanoconiosis 仍然应该给出结果?)
  • 听起来很傻,是的。我很可能正在处理我的工作集中的常见单词,这些单词与我的字典相距甚远,我希望它们解析为同一个单词,尽管它们解析为哪个单词并不是很重要。有什么办法可以从激进的词干提取器链接兰开斯特向后工作?
  • 如果您正在寻找具有相似含义的单词,那么您确实需要词库而不是 Levenshtein 距离。或者,Soundex 可能比 Levenshtein 更快,至少在第一次通过时。

标签: python language-agnostic machine-learning nlp oov


【解决方案1】:

看来您需要一个拼写校正器来匹配字典中的单词。 下面的代码有效,直接取自 Peter Norvig 撰写的博客http://norvig.com/spell-correct.html

import re, collections

def words(text): return re.findall('[a-z]+', text.lower()) 

def train(features):
    model = collections.defaultdict(lambda: 1)
    for f in features:
        model[f] += 1
    return model

NWORDS = train(words(file('big.txt').read()))

alphabet = 'abcdefghijklmnopqrstuvwxyz'

def edits1(word):
    splits     = [(word[:i], word[i:]) for i in range(len(word) + 1)]
    deletes    = [a + b[1:] for a, b in splits if b]
    transposes = [a + b[1] + b[0] + b[2:] for a, b in splits if len(b)>1]
    replaces   = [a + c + b[1:] for a, b in splits for c in alphabet if b]
    inserts    = [a + c + b     for a, b in splits for c in alphabet]
    return set(deletes + transposes + replaces + inserts)

def known_edits2(word):
    return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in NWORDS)

def known(words): return set(w for w in words if w in NWORDS)

def correct(word):
    candidates = known([word]) or known(edits1(word)) or known_edits2(word) or [word]
    return max(candidates, key=NWORDS.get)

big.txt 是包含已知单词的字典。

【讨论】:

    【解决方案2】:

    我看不出有理由使用 Levenshtein 距离来查找含义中相似的单词。 LD 查看表格(您想将“bus”映射到“truck”而不是“bush”)。

    正确的解决方案取决于您接下来要做什么。

    除非您真的需要那些未知单词中的信息,否则我会简单地将它们全部映射到一个通用的“UNKNOWN_WORD”项。

    显然,您可以根据上下文和其他特征(例如,它们是否以大写字母开头)对未知单词进行聚类。对于上下文聚类:由于您对含义感兴趣,我会为这些词使用更大的窗口(比如 +/- 50 个词),并且可能使用一个简单的词袋模型。然后,您只需使用一些距离度量(例如,余弦)找到该空间中的向量最接近未知词的已知词。如果您需要更多相关信息,请告诉我。

    【讨论】:

      【解决方案3】:

      希望这个答案不会太模糊:

      1) 听起来您可能需要先查看标记化和短语分块层。这是您应该在将符号短语块提交给任何模糊拼写检查之前丢弃它们的地方。

      2) 我仍然建议编辑距离以在此之后提出任何“拼写错误”标记的替代方案,但这可能会返回一个同样接近的可能性列表。

      3)当您拥有可能的列表后,您可以使用共现算法从该列表中选择最相似的候选者。我只有一些可以提供帮助的软件的 java 示例(http://www.linguatools.de/disco/disco_en.html#was)。您可以提交一个词,这将返回该词的同现词。然后,您可以将此列表与“拼写错误”单词的上下文进行比较,并从所有潜在的编辑距离单词中选择重叠最多的单词。

      【讨论】:

      • 另外,您是否首先查看过基于非字典的方法(例如 DISCO 软件)来查找相似词?
      【解决方案4】:

      您的任务听起来实际上只是非单词拼写纠正,因此相对直接的解决方案是使用现有的拼写检查器(如 aspell)和自定义词典。

      一种快速而肮脏的方法是仅使用变音位之类的语音映射(这是 aspell 使用的算法之一)。对于从您的字典中派生的每个可能的代码,选择一个代表词(例如,组中最常见的词)作为更正建议,并为找不到匹配项的情况选择一个默认更正。但是使用 aspell 可能会得到更好的结果。

      如果您确实想计算编辑距离,您可以通过将字典和可能的编辑操作存储在尝试中来相对快速地完成,请参阅Brill and Moore (2000)。如果你有一个相当大的拼写错误及其更正语料库,并且可以实现 Brill 和 Moore 的整个方法,你可能会比 aspell 好很多,但它听起来像 aspell(或任何可以让你创建自己的字典的拼写检查器) ) 足以完成您的任务。

      【讨论】:

      • 我的任务与拼写更正有很大不同。我选择 Levenshtein 距离只是因为它是一个一致的映射,可能会保留一些含义。我还要处理一些符号文字,所以拼写检查器根本不起作用。
      • 你能举个例子吗?我不知道你所说的“符号写作”是什么意思。如果您对“单词”有一些定义并将未知单词与字典中的单词列表进行比较(希望两者都使用相同的有限符号集),我不明白为什么拼写检查算法不会有帮助。
      • 符号写作,例如“a^2 + 2b + c”,拼写检查算法会很有用,但仅适用于我遇到的一小部分情况,我也需要能够映射根本不在字典中的单词。
      • 好吧,要么你有一本列出所有有效单词/标记的字典,要么你有一个更复杂的问题。非单词拼写检查总是将字典中没有的单词映射到字典中的单词。您想在字典中将“a^2 + 2b + c”映射到什么?我认为您需要更好地描述您的问题或提供更多示例...
      • 我知道这是一个比拼写检查更复杂的问题,这就是我这么说的原因。 “a^2 + 2b + c”映射到什么是无关紧要的,只要它是一致的。所有这些都已经发布了,您只需阅读它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-29
      相关资源
      最近更新 更多