web-dev-qa-db-ja.com

2つの文字列がどれほど似ているかを比較するためのアルゴリズムは何ですか?

文字列を比較して、それらが同じものを表すかどうかを判断する必要があります。これは、略語やその他の小さな詳細が異なる場合がある、人間が入力したケースのタイトルに関連しています。たとえば、次の2つのタイトルについて考えます。

std::string first = "Henry C. Harper v. The Law Offices of Huey & Luey, LLP";

とは対照的に:

std::string second = "Harper v. The Law Offices of Huey & Luey, LLP";

人間は、これらがおそらく同じものである可能性が高いとすぐに判断できます。私が取った現在のアプローチは、すべての文字を小文字にし、すべての句読点とスペースを削除して文字列を正規化することです:

std::string firstNormalized = "henrycharpervthelawofficesofhueylueyllp";

そして:

std::string secondNormalized = "harpervthelawofficesofhueylueyllp";

この場合を比較すると、一方は他方のサブシーケンスですが、必ずしも発生するわけではないが、重要なサブシーケンスが共通している他のより複雑なバリエーションを想像できます。また、文字の入れ替わりやスペルミスなど、人の入力ミスが発生する場合があります。

おそらく、ある種の文字差分プログラムが役立つでしょうか?チェックインするコードの違いを比較するための良い行差分プログラムを見てきましたが、文字ベースでそのような何かがありますか?共通の連続文字の数を数え、共有されていない文字の比率を取ることができれば、おそらくそれは良い発見的方法でしょうか?

最後に、それらを同じと見なすかどうかについてブール値の決定が必要です。完全である必要はありませんが、理想的には間違えないことが理想的です。

どのアルゴリズムを使用すると、2つの文字列が互いに類似しているかについて何らかの定量化が得られ、ヒューリスティックな方法でyes/noの答えに変換できますか?

51
WilliamKF

探しているものは String Metric アルゴリズムと呼ばれます。そこには重要な数があり、多くは類似した特性を持っています。より人気のあるものの中で:

  • Levenshtein Distance :1つのWordを別のWordに変更するために必要な単一文字編集の最小数。文字列は同じ長さである必要はありません
  • Hamming Distance :2つの等しい長さの文字列で異なる文字の数。
  • Smith–Waterman :可変サブシーケンスの類似性を計算するための一連のアルゴリズム。
  • Sørensen–Dice Coefficient :隣接する文字ペアの差分係数を計算する類似度アルゴリズム。

トピックの wikiページ でこれらと他をご覧ください。

75
Daniel Frey

Damerau Levenshtein distance は、2つの文字列を比較するための別のアルゴリズムであり、Levenshtein distanceアルゴリズムに似ています。 2つの違いは、文字間の転置も確認できるため、エラー修正の結果が改善される可能性があることです。

例:nightnigthの間のレーベンシュタイン距離は2ですが、nightnigthの間のDamerauレーベンシュタイン距離は1になります。文字のペア。

10
Ankit Chaurasia

そのためにngramを使用できます。たとえば、Wordトライグラム(通常は小文字)の2つの文字列を変換し、互いに等しい割合を比較します。

あなたの課題は、類似性の最小パーセンテージを定義することです。

http://en.wikipedia.org/wiki/N-gram

3
noderman

検討できる別のアルゴリズムは、Simon White Similarityです。

def get_bigrams(string):
    """
    Take a string and return a list of bigrams.
    """
    if string is None:
        return ""

    s = string.lower()
    return [s[i : i + 2] for i in list(range(len(s) - 1))]
def simon_similarity(str1, str2):
    """
    Perform bigram comparison between two strings
    and return a percentage match in decimal form.
    """
    pairs1 = get_bigrams(str1)
    pairs2 = get_bigrams(str2)
    union = len(pairs1) + len(pairs2)

    if union == 0 or union is None:
        return 0

    hit_count = 0
    for x in pairs1:
        for y in pairs2:
            if x == y:
                hit_count += 1
                break
    return (2.0 * hit_count) / union
2

最長共通サブシーケンスの長さを計算するアルゴリズムを使用して、問題を解決できます。両方の入力文字列の最長共通サブシーケンスの長さがいずれかの文字列の長さより短い場合、それらは等しくありません。

ダイナミックプログラミングのアプローチを使用して、最長共通サブシーケンスを把握したくない場合に、問題を解決し、スペースの複雑さを最適化することもできます。

0
nmg_vikas