スペルチェッカーで提案されるアルゴリズムはどれですか。


114

単語の候補を伴うスペルチェッカーを実装する場合、通常どのようなアルゴリズムが使用されますか?

最初に、入力した新しい単語(辞書に見つからない場合)を、辞書の他のすべての単語からのレーベンシュタイン距離と比較して上位の結果を返すことを確認することは理にかなっていると思いました。ただし、これは非常に効率が悪く、辞書全体を繰り返し評価する必要があるようです。

これは通常どのように行われますか?

回答:


203

スペリングコレクターの実装方法については、ピーターノービッグによる優れたエッセイがあります。これは基本的に、指定された編集距離で候補文字列を試すブルートフォースアプローチです。(ここでは、使用してスペル訂正のパフォーマンス向上させることができますどのようにいくつかのヒントがありブルームフィルタ高速化の候補ハッシュを。)

スペルチェッカーの要件は弱いです。単語が辞書にないことを知るだけでよい。ブルームフィルターを使用して、メモリ消費量の少ないスペルチェッカーを構築できます。古代バージョンは、英語の辞書に64 kbを使用して、Jon Bentleyによって 『Programming Pearls』で説明されています。

A BK-Treeの代替的なアプローチです。素敵な記事はこちらです。

レーベンシュタインの距離は、スペルチェッカーの正確な編集距離ではありません。挿入、削除、置換のみを認識します。転置が欠落しており、1文字の転置に対して2が生成されます(1つの削除と1つの挿入です)。Damerau–Levenshtein距離は、正しい編集距離です。


2
比較的不明なBK-Tree参照の場合は+1。これは、Real-World [TM]の大量のデータを扱うGoogleなどの企業が行っている方法です。
NoozNooz42 2010

2
ここにBK-Treesのより良い説明があります
Ian Boyd

17

私が正常に使用したがどこにも説明されていない提案を生成するためのアプローチは、「悪い」ハッシュ関数を使用して提案を事前に計算することです(辞書を構築するとき)。

アイデアは、ユーザーが行うスペルミスの種類を調べ、正しいスペルと同じバケットに誤ったスペルを割り当てるハッシュ関数を設計することです。

たとえば、よくある間違いは、definiteの代わりにdefinateなどの誤った母音を使用することです。したがって、すべての母音を同じ文字として扱うハッシュ関数を設計します。これを行う簡単な方法は、最初に入力単語を「正規化」し、次に正規化された結果を通常のハッシュ関数で処理することです。この例では、正規化関数はすべての母音を削除する可能性があるため、になります。次に、「正規化された」単語は、一般的なハッシュ関数でハッシュされます。definitedfnt

この特別なハッシュ関数を使用して、すべての辞書の単語を補助インデックス(ハッシュテーブル)に挿入します。この表のバケットは、ハッシュ関数が「悪い」ため、長めの衝突リストを持っていますが、これらの衝突リストは基本的に事前に計算された提案です。

次に、スペルミスのある単語を見つけたら、スペルミスがマッピングされているバケットの衝突リストを補助インデックスで検索します。多田:あなたは提案リストを持っています!あなたがしなければならないすべてはそれに言葉をランク付けすることです。

実際には、転置された文字、単一/二重の文字、さらには音声のスペルミスをキャッチする単純なSoundexのようなエラーなど、他のタイプのエラーを処理するために、他のハッシュ関数を使用したいくつかの補助インデックスが必要です。実際には、単純な発音の発音は長い道のりであり、些細なタイプミスを見つけるために設計された発音の一部は基本的に時代遅れになっています。

したがって、各補助インデックスのスペルミスを調べ、ランク付けの前に衝突リストを連結します。

衝突リストには、辞書にある単語のみが含まれていることに注意してください。(Peter Norvigの記事のように)代替スペルを生成しようとするアプローチを使用すると、最初に辞書に対してフィルタリングする必要がある(数万)数千の候補を取得できます。事前に計算されたアプローチを使用すると、おそらく数百の候補が得られ、それらのスペルがすべて正しいことがわかっているため、そのままスキップしてランキングに進むことができます。

更新:これに似たアルゴリズムの説明であるFAROO Distributed Searchを見つけました。これはまだ編集距離に制限のある検索ですが、事前計算ステップが私の「悪いハッシュ関数」のアイデアのように機能するため、非常に高速です。FAROOは、悪いハッシュ関数という限られた概念を使用しています。


FaroosのSymSpellアルゴリズムを参照していただきありがとうございます。どちらのアルゴリズムも可能なタイプミスを事前に計算し、ハッシュテーブルを使用して高速ルックアップを行いますが、主な違いは、SymSpellが特定の編集距離までのすべての可能なスペルエラーを検出することを保証することです(この点で、SymSpellはPeter Norvigのアルゴリズムと同等ですが、 3..6桁速くなります)。アルゴリズムは、理論的に考えられるすべてのスペルエラーの限られたサブセットのみを検出するヒューリスティックアプローチを使用しています(そのため、事前計算コストは​​低くなる可能性があります)。
Wolf Garbe 2016年

SymSpellアルゴリズムは可能なタイプミスを明示的に事前計算して保存しますが、私の「悪いハッシュ」スキームはそうではありません。英語の場合、広範囲をカバーする単純な音声ハッシュを1つだけ追加するのは簡単です(たとえば、編集距離が6の「terradacktle」->「pterodactyl」)。確かに、多言語の検索が必要な場合は、はるかに難しいかもしれません。
Adrian McCarthy

絶対に、ありそうなタイプミスに関する経験的知識を活用することで(そしてそれらに制限することにより)、計算前の時間とスペースを節約できます。しかし、すべての可能なスペルエラーをカバーするために、SymSpellはそれらのごく一部のみを事前計算する必要があります。5文字の単語の場合、最大編集距離3以内で約300万のスペルエラーが発生する可能性がありますが、SymSpellを使用すると、事前に計算して保存する必要がある削除は25だけです。これは、経験的知識が存在しない場合のスペル修正以外のあいまい検索/類似検索では重要です。
Wolf Garbe

7

アルゴリズム

  1. スペルが間違っている単語を入力として使用します。
  2. 英語の単語のリストとその頻度をテキストファイルに保存します。
  3. 使用可能なすべての英語の単語(テキストファイルに格納されている)とその頻度(英語で単語が使用される頻度の目安)を3成分検索ツリーに挿入します。
  4. 次に、Ternary Search Treeに沿ってトラバースします-
    • Ternary Search Treeで検出された単語ごとに、スペルが間違っている単語からLevensthein距離を計算します。
    • Levensthein Distance <= 3の場合、単語を優先度キューに格納します。
    • 2つの単語の編集距離が同じである場合、頻度が高い方の単語のほうが大きいです。優先キューから上位10項目を印刷します。

最適化

  1. 現在の単語からの入力単語のサブストリングの編集距離が3よりも大きい場合、現在のノードのサブツリー内の単語を削除できます。
    詳細な説明とソースコードはgithubプロジェクトにあります。

うーん、この場合、「グレーター」から「グレーター」までのレーベンシュタイン距離は十分ではありません。「グレーター」も辞書の単語であるためです。;-)
トニーブラスナス2017年

1
@TonyBrasunas、はい、あなたは正しいです。しかし、プログラムは入力として「grater」の場合、実際には10語のリストを返し、編集距離が0の「grater」と編集距離が1の「greater」を提案します。これは、いくつかの助けになるかもしれません。;)
amarjeetAnand 2017年

1つの候補の距離が2であるが非常に頻度が高く、別の候補の距離が1であるが非常にまれである場合、どのようにして2つをランク付けしますか?上記のアプローチでは、レアアイテムは常に勝つでしょう、これは正しい結果ですか?
スピードプレーン2018年

@speedplaneはい。まれなものが勝つでしょう。そして、それは正しい結果だと思います。入力単語のスペルに基づいて、最も近い単語が期待されるためです。それでも疑問がある場合は、このように考えてください---ユーザーが正しく綴った珍しい単語があるとします。現在、その距離は0ですが、周波数は非常に低くなっています。ここで提案では、この稀な単語(距離0の単語)を上部にリストし(編集距離が最小になるため)、他の単語1-2-3の単語を下にリストします。
amarjeetAnand

3

辞書内の各単語の正確な編集距離を知る必要はありません。制限値に達した後でアルゴリズムを停止し、単語を除外できます。これにより、計算時間を大幅に節約できます。


1

スペルチェッカーは、Unixのスペルプログラムと同様に、非常に簡単に実装できます。ソースコードは公開されています。修正が含まれる場合があります。1つの手法は、編集を行い、この新しい単語が辞書にあるかどうかを再度確認することです。このような新しい編集をグループ化してユーザーに表示できます。

UnixシステムはMc IllRoyによって書かれたプログラムを使用します。別の方法は、巨大なファイルの場合に役立つTrieを使用することです。

UNIXのアプローチは、分散ハッシュアルゴリズムを使用するため、巨大な辞書に必要なスペースが非常に少なくて済みます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.