79

Pythonから: tf-idf-cosine: to find document similarity、tf-idf cosine を使用してドキュメントの類似性を計算できます。外部ライブラリをインポートせずに、2 つの文字列間のコサイン類似度を計算する方法はありますか?

s1 = "This is a foo bar sentence ."
s2 = "This sentence is similar to a foo bar sentence ."
s3 = "What is this string ? Totally not related to the other two lines ."

cosine_sim(s1, s2) # Should give high cosine similarity
cosine_sim(s1, s3) # Shouldn't give high cosine similarity value
cosine_sim(s2, s3) # Shouldn't give high cosine similarity value
4

7 に答える 7

174

単純な純粋な Python 実装は次のようになります。

import math
import re
from collections import Counter

WORD = re.compile(r"\w+")


def get_cosine(vec1, vec2):
    intersection = set(vec1.keys()) & set(vec2.keys())
    numerator = sum([vec1[x] * vec2[x] for x in intersection])

    sum1 = sum([vec1[x] ** 2 for x in list(vec1.keys())])
    sum2 = sum([vec2[x] ** 2 for x in list(vec2.keys())])
    denominator = math.sqrt(sum1) * math.sqrt(sum2)

    if not denominator:
        return 0.0
    else:
        return float(numerator) / denominator


def text_to_vector(text):
    words = WORD.findall(text)
    return Counter(words)


text1 = "This is a foo bar sentence ."
text2 = "This sentence is similar to a foo bar sentence ."

vector1 = text_to_vector(text1)
vector2 = text_to_vector(text2)

cosine = get_cosine(vector1, vector2)

print("Cosine:", cosine)

版画:

Cosine: 0.861640436855

ここで使用する余弦公式は、ここで説明されています

これには tf-idf による単語の重み付けは含まれませんが、tf-idf を使用するには、tfidf の重みを推定するためのかなり大きなコーパスが必要です。

また、より高度な方法を使用して、テキストの一部から単語を抽出したり、単語を語幹化したり見出し語化したりして、さらに発展させることもできます。

于 2013-03-02T12:40:22.793 に答える
50

簡単に言えば、「いいえ、リモートでもうまく機能する原則的な方法でそれを行うことは不可能です」です。これは自然言語処理の研究における未解決の問題であり、たまたま私の博士研究の主題でもあります。現在の状況を簡単に要約し、いくつかの出版物を紹介します。

言葉の意味

ここで最も重要な前提は、各単語を表すベクトルを取得できるということです。問題の文で。このベクトルは通常、単語が出現するコンテキストをキャプチャするために選択されます。たとえば、「食べる」、「赤」、「ふわふわ」の 3 つのコンテキストのみを考慮する場合、「猫」という単語は [98, 1 、87]、非常に長いテキスト (今日の標準では数十億語は珍しくありません) を読む場合、「猫」という単語は「ふわふわ」と「食べる」の文脈で非常に頻繁に現れるためです。 、しかし「赤」の文脈ではそれほど頻繁ではありません。同様に、「犬」は [87,2,34] と表され、「傘」は [1,13,0] と表されます。これらのベクトルを 3 次元空間の点としてイメージすると、「猫」は明らかに「傘」よりも「犬」に近いため、「猫」になります。

この一連の作業は 90 年代初頭から調査されており ( Greffenstette によるこの作業など)、驚くほど良い結果が得られています。たとえば、コンピューターでウィキペディアを読み取って最近作成したシソーラスのいくつかのランダムなエントリを次に示します。

theory -> analysis, concept, approach, idea, method
voice -> vocal, tone, sound, melody, singing
james -> william, john, thomas, robert, george, charles

これらの類似した単語のリストは、人間の介入なしで完全に取得されました。テキストをフィードして、数時間後に戻ってきます。

フレーズの問題

「ジンジャー キツネはフルーツが大好き」などの長いフレーズに対して、なぜ同じことをしないのかと疑問に思われるかもしれません。それはテキストが足りないからです。X が何に似ているかを確実に確立するためには、コンテキストで X が使用されている多くの例を確認する必要があります。X が「声」のような 1 つの単語の場合、これはそれほど難しくありません。ただし、X が長くなるにつれて、X の自然発生を見つける可能性は指数関数的に遅くなります。比較のために、Google には「fox」という単語を含む約 10 億ページがあり、「ginger foxes love fruit」を含むページは 1 つもありませんが、それは完全に有効な英文であり、その意味を理解しているにもかかわらずです。

構成

データの希薄性の問題に取り組むために、構成を実行したいと考えています。つまり、実際のテキストから簡単に取得できる単語のベクトルを取得し、その意味を捉える方法でそれらを組み合わせます。悪いニュースは、これまでのところ誰もそれをうまくできていないということです.

最も簡単で明白な方法は、個々の単語ベクトルを加算または乗算することです。これは、「猫が犬を追いかける」と「犬が猫を追いかける」がシステムにとって同じ意味になるという望ましくない副作用につながります。また、乗算する場合は、特に注意する必要があります。そうしないと、すべての文が [0,0,0,...,0] で表されてしまい、ポイントが無効になります。

参考文献

これまで提案されてきた、より洗練された構成方法については説明しません。Katrin Erk の「単語の意味と句の意味のベクトル空間モデル: 調査」を読むことをお勧めします。これは、開始するための非常に優れた高レベルの調査です。残念ながら、出版社の Web サイトでは無料で入手できません。コピーを入手するには、著者に直接電子メールを送信してください。その論文では、より多くの具体的な方法への参照を見つけることができます。よりわかりやすいのは、Mitchel and Lapata (2008)Baroni and Zamparelli (2010)によるものです。


@vpekar によるコメント後の編集: この回答の要点は、素朴な方法(加算、乗算、曲面の類似性など) は存在しますが、これらには根本的な欠陥があり、一般的に優れたパフォーマンスを期待するべきではないという事実を強調することです。彼ら。

于 2013-03-02T11:15:56.773 に答える