私は次の2つの文字列を持っています:
String A: Manchester United
String B: Manchester Utd
どちらの文字列も同じ意味ですが、異なる値が含まれています。
これらの文字列を比較して「一致スコア」を得るにはどうすればよいですか。最初の単語が「マンチェスター」と似ていて、2 番目の単語に似た文字が含まれているが、適切な場所にない場合です。
2 つの文字列を指定した後に「一致スコア」を返す単純なアルゴリズムはありますか?
2つの文字列間のレーベンシュタイン距離を計算できます。それが(定義する必要のある)値よりも小さい場合は、それらがかなり近いと見なすことができます。
私はこのようなことをする必要があり、レーベンシュタイン距離を使用しました。
100 万を超える行 (および最大 6 または 7 語のテキスト) を持つクエリで使用されている SQL Server UDF に使用しました。
各単語を個別に比較すると、アルゴリズムがより高速に実行され、「類似度インデックス」がより正確になることがわかりました。つまり、各入力文字列を単語に分割し、1 つの入力文字列の各単語を他の入力文字列の各単語と比較します。
レーベンシュタインが差を与えることを忘れないでください。それを「類似度指数」に変換する必要があります。距離を最長の単語の長さで割ったようなものを使用しました(ただし、いくつかのバリエーションがあります)
次のことも考慮する必要があります。
これに応じてアルゴリズムが変わります。たとえば、単語数が異なる場合、最初のルールを適用すると非常に高速です。そして、2 番目のルールは、特に比較されるテキストに多くの単語がある場合に、比較の数を減らします。これについては、後で例を挙げて説明します。
また、グローバルな類似性インデックスを取得するために、短い単語よりも長い単語に重みを付けました。私のアルゴリズムは、比較されたペアの 2 つの単語のうち最長のものを使用し、短い単語のペアよりも長い単語のペアに高い重みを与えますが、ペアの長さに正確に比例するわけではありません。
この例では、異なる数の単語を使用しています:
両方の入力の単語の順序が同じであることが保証されている場合は、これらのペアを比較する必要があります。
Manchester United
Manchester Utd FC
(マンチェスター、マンチェスター) (ユナイテッド、ユナイテッド) (FC: 比較なし)
Manchester United
Manchester Utd FC
(マンチェスター,マンチェスター) (ユナイテッド: 比較なし) (ユナイテッド,FC)
Machester United
Manchester Utd FC
(マンチェスター: 比較なし) (マンチェスター、Utd) (ユナイテッド、FC)
明らかに、最高のスコアはペアの最初のセットになります。
単語を同じ順序で比較する。
単語数が多い文字列は固定ベクトルであり、この例では A、B、C、D、E として示されています。ここで、v[0] は単語 A、v[1] は単語 B などです。
単語数が少ない文字列については、最初のセットと比較できるインデックスのすべての可能な組み合わせを作成する必要があります。この場合、単語数の少ない文字列は a,b,c で表されます。
単純なループを使用して、比較するペアを表すすべてのベクトルを次のように作成できます。
A,B,C,D,E A,B,C,D,E A,B,C,D,E A,B,C,D,E A,B,C,D,E A,B,C,D,E
a,b,c a,b, c a,b, c a, b,c a, b, c a, b,c
0 1 2 0 1 3 0 1 4 0 2 3 0 2 4 0 3 4
A,B,C,D,E A,B,C,D,E A,B,C,D,E A,B,C,D,E
a,b,c a,b, c a, b,c a,b,c
1 2 3 1 2 4 1 3 4 2 3 4
サンプルの数値は、単語の最初のセットのインデックスを持つベクトルであり、最初のセットのインデックスと比較する必要があります。つまり、v[0]=0 は、ショート セット (a) のインデックス 0 をロング セット (A) のインデックス 0 と比較することを意味し、v[1]=2 は、ショート セット (b) のインデックス 1 をインデックス 2 と比較することを意味します。ロングセット(C)など。
このベクトルを計算するには、単純に 0,1,2 から始めます。移動できなくなるまで、移動可能な最新のインデックスを右に移動します。
最後の 1 つを移動して開始します。
0,1,2 -> 0,1,3 -> 0,1,4
No more moves possible, move the previous index, and restore the others
to the lowest possible values (move 1 to 2, restore 4 to 3)
最後のものがそれ以上移動できない場合は、最後の 1 つ前に移動し、最後のものを可能な限り近い場所にリセットします (1 は 2 に移動し、4 は 3 に移動します)。
0,2,3 -> 0,2,4
No more moves possible of the last, move the one before the last
最後の前のものをもう一度移動します。
0,3,4
No more moves possible of the last, move the one before the last
Not possible, move the one before the one before the last, and reset the others:
前のものを移動します。
1,2,3 -> 1,2,4
等々。写真を見る
可能な組み合わせがすべて揃ったら、定義されたペアを比較できます。
最小の類似性に達したときに比較を停止: 実行したい内容に応じて、しきい値に達したときにペアの比較を停止するしきい値を設定できます。
しきい値を設定できない場合でも、少なくとも単語のペアごとに 100% の類似性が得られればいつでも停止できます。これにより、多くの時間を割くことができます。
場合によっては、類似度が少なくとも 75% 程度の場合は、単純に比較を停止することができます。これは、ユーザーが提供したものに類似したすべての文字列をユーザーに表示する場合に使用できます。
順序が変わる可能性がある場合は、最初のセットの各単語と 2 番目のセットの各単語を比較し、すべての順序で並べられた最短のペアのすべての単語を含む結果の組み合わせに対して最高スコアを取得する必要があります。 2番目のペアの異なる単語と比較して、可能な方法。このために、(n X m) 要素の行列の上または下の三角形にデータを入力し、行列から必要な要素を取得できます。
次のように、比較する前に単語を正規化する必要もあります。
手順を最適化するために、可能なものは何でもキャッシュしました。つまり、A のベクトル 0,1,2-0,1,3,-0,1,4-0,2,3 のような異なるサイズの比較ベクトルです。 ,B,C,D,E から a,b,c への比較の例: 長さ 3,5 のすべての比較は、最初の使用時に計算され、着信する 3 語から 5 語までのすべての比較で再利用されます。
ハミング距離を試してみましたが、結果はあまり正確ではありませんでした。
セマンティック比較、音声比較、いくつかの文字がまったく同じであると見なすなど、はるかに複雑なことを行うことができます(スペイン語などのいくつかの言語では と のようb
にv
、区別はありません)。これには、実装が非常に簡単なものもあれば、非常に難しいものもあります。
注: レーベンシュタイン距離の実装は含めませんでした。さまざまな言語で実装されていることが簡単にわかるからです。
この記事を見てください。この記事では、その方法を説明し、サンプルコードも提供しています:)
アップデート:
これは、2つの文字列をパラメーターとして受け取り、2つの文字列の「レーベンシュタイン距離」を計算するメソッドコードです。
public static int Compute(string s, string t)
{
int n = s.Length;
int m = t.Length;
int[,] d = new int[n + 1, m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
for (int i = 0; i <= n; d[i, 0] = i++)
{
}
for (int j = 0; j <= m; d[0, j] = j++)
{
}
// Step 3
for (int i = 1; i <= n; i++)
{
//Step 4
for (int j = 1; j <= m; j++)
{
// Step 5
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
// Step 6
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
// Step 7
return d[n, m];
}
重複の検出は、レーベンシュタイン距離の計算よりも「少し」複雑な場合があります。次の例を検討してください。
1. Jeff, Lynch, Maverick, Road, 181, Woodstock
2. Jeff, Alf., Lynch, Maverick, Rd, Woodstock, NY
この重複は、複雑なクラスタリング アルゴリズムによって照合できます。
詳細については、「大規模データベースでの重複検出のための効果的な増分クラスタリング」などの研究論文を確認してください。
(例は論文より)
探しているのは、文字列の類似度です。これには複数の方法があります。
一般的に、オプション #2 が実装が最も簡単であることがわかります。文字列がフレーズである場合は、単語境界で単純にトークン化できます。上記のすべてのケースで、トークン化する前にまずストップ ワード (and、a、the などの一般的な単語) を削除することをお勧めします。 更新:リンク
C# で Naive Similarity エンジンを実装する*警告: 恥知らずな自己宣伝