1. ホーム
  2. nlp

[解決済み】2つのテキスト文書間の類似性を計算する方法は?

2022-04-16 15:10:31

質問

私はNLPプロジェクトに携わっています。プログラミング言語は問いません(ただし、Pythonを希望します)。

2つの文書を取り出して、どの程度似ているかを判断したいのですが。

どのように解決するのですか?

一般的な方法は、文書をTF-IDFベクトルに変換し、その間の余弦類似度を計算することである。情報検索(IR)の教科書には必ず載っています。特に参照。 情報検索入門 は、無料でオンライン公開されています。

一対の類似性を計算する

TF-IDF(および類似のテキスト変換)は、Pythonパッケージで実装されています。 ジェンシム scikit-learn . 後者のパッケージでは,cosine の類似性を計算するのは次のように簡単です.

from sklearn.feature_extraction.text import TfidfVectorizer

documents = [open(f).read() for f in text_files]
tfidf = TfidfVectorizer().fit_transform(documents)
# no need to normalize, since Vectorizer will return normalized tf-idf
pairwise_similarity = tfidf * tfidf.T

または、ドキュメントがプレーンな文字列である場合。

>>> corpus = ["I'd like an apple", 
...           "An apple a day keeps the doctor away", 
...           "Never compare an apple to an orange", 
...           "I prefer scikit-learn to Orange", 
...           "The scikit-learn docs are Orange and Blue"]                                                                                                                                                                                                   
>>> vect = TfidfVectorizer(min_df=1, stop_words="english")                                                                                                                                                                                                   
>>> tfidf = vect.fit_transform(corpus)                                                                                                                                                                                                                       
>>> pairwise_similarity = tfidf * tfidf.T 

しかし、この種のタスクには Gensim の方がより多くのオプションがあるかもしれません。

参照 この質問 .

[免責事項: 私は scikit-learn TF-IDF の実装に携わりました].

結果の解釈

上から pairwise_similarity はScipyの スパースマトリックス は正方形で、行と列の数はコーパスの文書数と同じである。

>>> pairwise_similarity                                                                                                                                                                                                                                      
<5x5 sparse matrix of type '<class 'numpy.float64'>'
    with 17 stored elements in Compressed Sparse Row format>

スパース配列をNumPyの配列に変換するには、次のようにします。 .toarray() または .A :

>>> pairwise_similarity.toarray()                                                                                                                                                                                                                            
array([[1.        , 0.17668795, 0.27056873, 0.        , 0.        ],
       [0.17668795, 1.        , 0.15439436, 0.        , 0.        ],
       [0.27056873, 0.15439436, 1.        , 0.19635649, 0.16815247],
       [0.        , 0.        , 0.19635649, 1.        , 0.54499756],
       [0.        , 0.        , 0.16815247, 0.54499756, 1.        ]])

最終的な文書、"The scikit-learn docs are Orange and Blue"に最も近い文書を探したいとします。 このドキュメントのインデックス4は corpus . 最も似ているドキュメントのインデックスは、次のようにして見つけることができます。 その行の argmax を取ります。しかし、まず各文書のそれ自身に対する類似度を表す 1 をマスクする必要があります。 . 後者は、以下の方法で行うことができます。 np.fill_diagonal() で、前者は np.nanargmax() :

>>> import numpy as np     
                                                                                                                                                                                                                                  
>>> arr = pairwise_similarity.toarray()     
>>> np.fill_diagonal(arr, np.nan)                                                                                                                                                                                                                            
                                                                                                                                                                                                                 
>>> input_doc = "The scikit-learn docs are Orange and Blue"                                                                                                                                                                                                  
>>> input_idx = corpus.index(input_doc)                                                                                                                                                                                                                      
>>> input_idx                                                                                                                                                                                                                                                
4

>>> result_idx = np.nanargmax(arr[input_idx])                                                                                                                                                                                                                
>>> corpus[result_idx]                                                                                                                                                                                                                                       
'I prefer scikit-learn to Orange'

注意:疎な行列を使う目的は、大きなコーパスと語彙のために(かなりの量の)スペースを節約することです。 NumPyの配列に変換する代わりに、こうすることもできます。

>>> n, _ = pairwise_similarity.shape                                                                                                                                                                                                                         
>>> pairwise_similarity[np.arange(n), np.arange(n)] = -1.0
>>> pairwise_similarity[input_idx].argmax()                                                                                                                                                                                                                  
3