web-dev-qa-db-ja.com

文字列類似性スコア/ハッシュ

文字列の一般的な「類似性スコア」のようなものを計算する方法はありますか? 2つの文字列を一緒に比較するのではなく、各文字列の数値(ハッシュ)を取得することで、2つの文字列が類似しているかどうかを後で知ることができます。 2つの類似した文字列は、類似した(近い)ハッシュを持つ必要があります。

これらの文字列とスコアを例として考えてみましょう:

Hello world                1000
Hello world!               1010
Hello earth                1125
Foo bar                    3250
FooBarbar                  3750
Foo Bar!                   3300
Foo world!                 2350

Hello world!Hello worldは似ており、スコアは互いに近いことがわかります。

このように、特定の文字列に最も類似する文字列を見つけるには、特定の文字列スコアを他のスコアから減算し、それらの絶対値を並べ替えます。

47
Josef Sábl

あなたが探しているものは Locality Sensitive Hash と呼ばれていると思います。ほとんどのハッシュアルゴリズムは、入力の小さな変化が出力の大きな変化を引き起こすように設計されていますが、これらのハッシュはその逆を試みます。入力の小さな変化は、比例して小さな出力の変化を生成します。

他の人が述べたように、多次元マッピングを2次元マッピングに強制することには固有の問題があります。これは、地球の平らな地図を作成することに似ています...平らな表面に球体を正確に表すことはできません。最善の方法は、文字列が「類似」しているかどうかを判断するために使用している機能に最適化されたLSHを見つけることです。

24
DougW

レベンシュタイン距離またはその導関数は、必要なアルゴリズムです。指定された文字列を辞書の各文字列と照合します。 (ここで、最も類似した文字列の固定数のみが必要な場合は、min-heapを使用することをお勧めします。)辞書のすべての文字列に対してLevenstein距離を実行するのが高すぎる場合は、最初に、遠すぎる単語を除外する大まかなアルゴリズムを使用します。候補者のリスト。その後、左の候補者に対してレベンシュタイン距離を実行します。


離れた単語を削除する1つの方法は、n-gramにインデックスを付けることです。各単語をn-gramのリストに分割して、辞書を前処理します。たとえば、n = 3を考えます。

(0) "Hello world" -> ["Hel", "ell", "llo", "lo ", "o w", " wo", "wor", "orl", "rld"]
(1) "FooBarbar" -> ["Foo", "ooB", "oBa", "Bar", "arb", "rba", "bar"]
(2) "Foo world!" -> ["Foo", "oo ", "o w", " wo", "wor", "orl", "rld", "ld!"]

次に、nグラムのインデックスを作成します。

" wo" -> [0, 2]
"Bar" -> [1]
"Foo" -> [1, 2]
"Hel" -> [0]
"arb" -> [1]
"bar" -> [1]
"ell" -> [0]
"ld!" -> [2]
"llo" -> [0]
"lo " -> [0]
"o w" -> [0, 2]
"oBa" -> [1]
"oo " -> [2]
"ooB" -> [1]
"orl" -> [0, 2]
"rba" -> [1]
"rld" -> [0, 2]
"wor" -> [0, 2]

特定の文字列に対して最も類似した文字列を見つける必要がある場合は、特定の文字列をn-gramに分割し、一致するn-gramが少なくとも1つある単語のみを辞書から選択します。これにより、候補の数が適切な量に減り、左側の候補のそれぞれに与えられた文字列をレベンシュタインマッチングで処理することができます。


文字列が十分に長い場合は、min-hashingテクニックを使用してインデックスサイズを小さくすることができます。n-gramごとに通常のハッシュを計算し、K個の最小ハッシュのみを使用します。他のハッシュは破棄されます。

追伸 このプレゼンテーション は、問題の良い導入のようです。

12
gudok

文字列間の編集距離のセットが metric space を形成するため、これは一般的に不可能ですが、次元が固定されているものはできません。つまり、文字列と整数の間の距離測定値を保持するマッピングを提供することはできません。

たとえば、次の3つのフレーズに番号を割り当てることはできません。

  • 一二
  • 一六
  • 二六

数字が3つのフレーズすべての違いを反映するように。

11
Nick Johnson

アイデアは非常に甘いようですが...私はこれについて聞いたことがありません。

私は、スペル修正/タイプミス修正の主題に関する技術、論文、科学に関する多くの論文を読みましたが、最速の提案は、インデックスとレーベンシュタイン距離を中心に展開しています。

私が現在取り組んでいるかなり複雑な技術が組み合わされています:

  • コンパクトなレベルのバーストトライ
  • レーベンシュタイン・オートマトン

これは、スコアを取得することが「不可能」であるという意味ではありませんが、そのような「スコアリング」メソッドが効率的であることが証明された場合、文字列比較に関する最近の研究はそれほど多くないでしょう。

あなたがそのような方法を見つけたなら、私は非常に興味があります:)

4
Matthieu M.

境界のない問題では、考えられる単語のシーケンス、または考えられる文字のシーケンスを、局所性を表す単一の数値に変換できるソリューションはありません。

キャラクターレベルでの類似性を想像してください

stops
spots

hello world
world hello

どちらの例でもメッセージは異なりますが、メッセージ内の文字は同じであるため、メジャーは位置の値と文字の値を保持する必要があります。 (char 0 == 'h'、char 1 == 'e' ...)

次に、以下の同様のメッセージを比較します

hello world
Ello world

2つの文字列は似ていますが、最初または最後で異なる可能性があるため、位置によるスケーリングが問題になります。

の場合

spots
stops

単語は文字の位置によってのみ異なるため、何らかの形の位置が重要です。

次の文字列が類似している場合

 yesssssssssssssss
 yessssssssssssss

次に、パラドックスの形があります。 2つのs文字を2番目の文字列に追加する場合、最初の文字列からの距離を共有する必要がありますが、異なる必要があります。これを繰り返して、徐々に長い文字列を取得することができます。すべての文字列は、それらよりも短い文字列と長い文字列に近い必要があります。これを実現する方法がわかりません。

一般に、これは多次元問題として扱われます-文字列をベクトルに分解します

[ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' ]

しかし、ベクトルの値は

  • 固定サイズの数値で表される、または
  • 良い品質の差の尺度を与えます。

単語数または文字列の長さが制限されている場合は、コーディングの解決策が考えられます。

境界値

算術圧縮のようなものを使用して、単語のシーケンスを、シーケンスを表す浮動小数点数に変換できます。ただし、これにより、シーケンスの最初のアイテムがシーケンスの最後のアイテムよりも重要なものとして扱われます。

データマイニングソリューション

問題が高次元であることを受け入れる場合は、文字列をメトリックツリーに保存できます wikipedia:metric tree 。これは、「単一の数」の解を解決しない一方で、検索スペースを制限します。

そのようなコードは github:clustering にあります

互いに接近しているアイテムは、ツリーの一部に一緒に格納する必要がありますが、実際には保証されません。サブツリーの半径は、検索スペースを削減するために使用されます。

距離またはレーベンシュタイン距離を編集

これは、類似性検索を実行するためにsqlite拡張機能で使用されますが、単一の数値ソリューションではなく、1つの文字列を別の文字列に変更する編集数を計算します。これにより、類似性を示すスコアが得られます。

2
mksteve

Levenshtein distance は効果的ですか?

2
Karl Knechtel

あなたのアイデアは オントロジー のように聞こえますが、フレーズ全体に適用されます。 2つのフレーズが類似しているほど、それらはグラフで近くなります(重み付けされたエッジを使用している場合)。逆もまた同様です。類似していないフレーズは互いに非常に離れています。

別のアプローチは、フーリエ変換を使用して、特定の文字列の「インデックス」の種類を取得することです(単一の数値ではありませんが、常に)。 この論文 でもう少し見つけるかもしれません。

そして、もう1つのアイデアは、レーベンシュタイン距離に基づいています。2つの指定されたフレーズの類似性インデックスを提供するNグラムを比較できます。それらが類似しているほど、値は1に近くなります。これは、グラフ。数年前にこれについて論文を書きました。もしあなたがそれを共有したいのであれば。

とにかく、私は正確な解決策を知りませんが、あなたが思いつくものにも興味があります。

1
Przemek Kryger

たぶん [〜#〜] pca [〜#〜] を使用できます。ここで、行列は文字列と固定アルファベットの違いのリストです(àABCDEFGHI ...)。答えは、単に主成分の長さです。

ただのアイデア。

C#ですぐに実行できるPCA

1
smirkingman

2つのフレーズからかなり小さい数が得られる可能性は低く、比較すると、最初のフレーズの類似性の適切な指標が提供されます。
理由は、フレーズが長さと強さの2次元で進化しているのに対して、数値は1次元で指標を与えるためです。

数値はintensityのように長さも同様に変化する可能性がありますが、多くの助けになるとは思いません。

2次元では、マトリックスをよりよく見ることができます。これは行列式(マトリックスの一種の導関数)のようないくつかのプロパティは、フレーズトレンドの大まかなアイデアを与えることができます。

0
Ring Ø

Natural Language Processingでは、Minimum Edit Distance(thing =レーベンシュタイン距離として知られています)
基本的には、string1をstring2に変換するために必要な最小量の操作として定義されます
含まれる操作挿入、削除、置換、各操作には、距離に追加するスコアが与えられます
問題を解決するためのアイデアは、選択した文字列から他のすべての文字列までMEDを計算し、そのコレクションを並べ替えて、n番目に小さい距離の文字列を選択することです
例えば:

{"Hello World", "Hello World!", "Hello Earth"}
Choosing base-string="Hello World"  
Med(base-string, "Hello World!") = 1  
Med(base-string, "Hello Earth") = 8  
1st closest string is "Hello World!"

これにより、文字列コレクションの各文字列にスコアが多少付けられました
C#の実装(追加1、削除1、置換2)

public static int Distance(string s1, string s2)
{
    int[,] matrix = new int[s1.Length + 1, s2.Length + 1];

    for (int i = 0; i <= s1.Length; i++)
        matrix[i, 0] = i;
    for (int i = 0; i <= s2.Length; i++)
        matrix[0, i] = i;

    for (int i = 1; i <= s1.Length; i++)
    {
        for (int j = 1; j <= s2.Length; j++)
        {
            int value1 = matrix[i - 1, j] + 1;
            int value2 = matrix[i, j - 1] + 1;
            int value3 = matrix[i - 1, j - 1] + ((s1[i - 1] == s2[j - 1]) ? 0 : 2);

            matrix[i, j] = Math.Min(value1, Math.Min(value2, value3));
        }
    }

    return matrix[s1.Length, s2.Length];
}

複雑さO(n x m)ここで、n、mは各文字列の長さ
最小編集距離の詳細については、こちらをご覧ください こちら

0
rocketspacer

私はこのようなことを考えています:

  1. word以外の文字をすべて削除する
  2. 適用 soundex
0
alpha-mouse