107

Part 1 & Part 2で利用できるチュートリアルに従っていました。残念ながら、著者には、コサイン類似度を使用して 2 つのドキュメント間の距離を実際に検出するという最後のセクションを行う時間がありませんでした。stackoverflowからの次のリンクの助けを借りて、記事の例に従いました。上記のリンクに記載されているコードが含まれています (生活を楽にするため)。

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from nltk.corpus import stopwords
import numpy as np
import numpy.linalg as LA

train_set = ["The sky is blue.", "The sun is bright."]  # Documents
test_set = ["The sun in the sky is bright."]  # Query
stopWords = stopwords.words('english')

vectorizer = CountVectorizer(stop_words = stopWords)
#print vectorizer
transformer = TfidfTransformer()
#print transformer

trainVectorizerArray = vectorizer.fit_transform(train_set).toarray()
testVectorizerArray = vectorizer.transform(test_set).toarray()
print 'Fit Vectorizer to train set', trainVectorizerArray
print 'Transform Vectorizer to test set', testVectorizerArray

transformer.fit(trainVectorizerArray)
print
print transformer.transform(trainVectorizerArray).toarray()

transformer.fit(testVectorizerArray)
print 
tfidf = transformer.transform(testVectorizerArray)
print tfidf.todense()

上記のコードの結果として、次のマトリックスがあります

Fit Vectorizer to train set [[1 0 1 0]
 [0 1 0 1]]
Transform Vectorizer to test set [[0 1 1 1]]

[[ 0.70710678  0.          0.70710678  0.        ]
 [ 0.          0.70710678  0.          0.70710678]]

[[ 0.          0.57735027  0.57735027  0.57735027]]

コサイン類似度を計算するためにこの出力を使用する方法がわかりません。同様の長さの 2 つのベクトルに関してコサイン類似度を実装する方法は知っていますが、ここでは 2 つのベクトルを識別する方法がわかりません。

4

6 に答える 6

186

まず、カウントの特徴を抽出し、TF-IDF正規化と行ごとのユークリッド正規化を適用する場合は、次の操作を使用して1回の操作で実行できますTfidfVectorizer

>>> from sklearn.feature_extraction.text import TfidfVectorizer
>>> from sklearn.datasets import fetch_20newsgroups
>>> twenty = fetch_20newsgroups()

>>> tfidf = TfidfVectorizer().fit_transform(twenty.data)
>>> tfidf
<11314x130088 sparse matrix of type '<type 'numpy.float64'>'
    with 1787553 stored elements in Compressed Sparse Row format>

ここで、1つのドキュメント(たとえば、データセットの最初のドキュメント)と他のすべてのドキュメントの正弦距離を見つけるには、tfidfベクトルがすでに行正規化されているため、最初のベクトルと他のすべてのベクトルの内積を計算する必要があります。

コメントでChrisClarkが説明しているように、ここではCosineSimilarityはベクトルの大きさを考慮していません。行正規化の大きさは1であるため、類似度の値を計算するには線形カーネルで十分です。

scipyスパース行列APIは少し奇妙です(密なN次元のnumpy配列ほど柔軟ではありません)。最初のベクトルを取得するには、行列を行ごとにスライスして、単一行の部分行列を取得する必要があります。

>>> tfidf[0:1]
<1x130088 sparse matrix of type '<type 'numpy.float64'>'
    with 89 stored elements in Compressed Sparse Row format>

scikit-learnは、ベクトルコレクションの密な表現と疎な表現の両方で機能するペアワイズメトリック(機械学習用語ではカーネル)をすでに提供しています。この場合、線形カーネルとも呼ばれる内積が必要です。

>>> from sklearn.metrics.pairwise import linear_kernel
>>> cosine_similarities = linear_kernel(tfidf[0:1], tfidf).flatten()
>>> cosine_similarities
array([ 1.        ,  0.04405952,  0.11016969, ...,  0.04433602,
    0.04457106,  0.03293218])

したがって、上位5つの関連ドキュメントを見つけるためにargsort、いくつかの負の配列スライシングを使用できます(ほとんどの関連ドキュメントは、最高のコサイン類似度値を持っているため、ソートされたインデックス配列の最後にあります)。

>>> related_docs_indices = cosine_similarities.argsort()[:-5:-1]
>>> related_docs_indices
array([    0,   958, 10576,  3277])
>>> cosine_similarities[related_docs_indices]
array([ 1.        ,  0.54967926,  0.32902194,  0.2825788 ])

最初の結果は健全性チェックです。クエリドキュメントは、コサイン類似度スコアが1で、次のテキストを持つ最も類似したドキュメントであることがわかります。

>>> print twenty.data[0]
From: lerxst@wam.umd.edu (where's my thing)
Subject: WHAT car is this!?
Nntp-Posting-Host: rac3.wam.umd.edu
Organization: University of Maryland, College Park
Lines: 15

 I was wondering if anyone out there could enlighten me on this car I saw
the other day. It was a 2-door sports car, looked to be from the late 60s/
early 70s. It was called a Bricklin. The doors were really small. In addition,
the front bumper was separate from the rest of the body. This is
all I know. If anyone can tellme a model name, engine specs, years
of production, where this car is made, history, or whatever info you
have on this funky looking car, please e-mail.

Thanks,
- IL
   ---- brought to you by your neighborhood Lerxst ----

2番目に類似したドキュメントは、元のメッセージを引用する返信であるため、多くの一般的な単語が含まれています。

>>> print twenty.data[958]
From: rseymour@reed.edu (Robert Seymour)
Subject: Re: WHAT car is this!?
Article-I.D.: reed.1993Apr21.032905.29286
Reply-To: rseymour@reed.edu
Organization: Reed College, Portland, OR
Lines: 26

In article <1993Apr20.174246.14375@wam.umd.edu> lerxst@wam.umd.edu (where's my
thing) writes:
>
>  I was wondering if anyone out there could enlighten me on this car I saw
> the other day. It was a 2-door sports car, looked to be from the late 60s/
> early 70s. It was called a Bricklin. The doors were really small. In
addition,
> the front bumper was separate from the rest of the body. This is
> all I know. If anyone can tellme a model name, engine specs, years
> of production, where this car is made, history, or whatever info you
> have on this funky looking car, please e-mail.

Bricklins were manufactured in the 70s with engines from Ford. They are rather
odd looking with the encased front bumper. There aren't a lot of them around,
but Hemmings (Motor News) ususally has ten or so listed. Basically, they are a
performance Ford with new styling slapped on top.

>    ---- brought to you by your neighborhood Lerxst ----

Rush fan?

--
Robert Seymour              rseymour@reed.edu
Physics and Philosophy, Reed College    (NeXTmail accepted)
Artificial Life Project         Reed College
Reed Solar Energy Project (SolTrain)    Portland, OR
于 2012-08-26T08:45:15.370 に答える
24

@excray のコメントの助けを借りて、答えを見つけ出すことができました。実際に必要なのは、トレーニング データとテスト データを表す 2 つの配列を反復処理する単純な for ループを作成することです。

最初に単純なラムダ関数を実装して、余弦計算の式を保持します。

cosine_function = lambda a, b : round(np.inner(a, b)/(LA.norm(a)*LA.norm(b)), 3)

次に、単純な for ループを記述して to ベクトルを反復処理します。ロジックは、「trainVectorizerArray の各ベクトルについて、testVectorizerArray のベクトルとのコサイン類似度を見つける必要があります。」

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from nltk.corpus import stopwords
import numpy as np
import numpy.linalg as LA

train_set = ["The sky is blue.", "The sun is bright."] #Documents
test_set = ["The sun in the sky is bright."] #Query
stopWords = stopwords.words('english')

vectorizer = CountVectorizer(stop_words = stopWords)
#print vectorizer
transformer = TfidfTransformer()
#print transformer

trainVectorizerArray = vectorizer.fit_transform(train_set).toarray()
testVectorizerArray = vectorizer.transform(test_set).toarray()
print 'Fit Vectorizer to train set', trainVectorizerArray
print 'Transform Vectorizer to test set', testVectorizerArray
cx = lambda a, b : round(np.inner(a, b)/(LA.norm(a)*LA.norm(b)), 3)

for vector in trainVectorizerArray:
    print vector
    for testV in testVectorizerArray:
        print testV
        cosine = cx(vector, testV)
        print cosine

transformer.fit(trainVectorizerArray)
print
print transformer.transform(trainVectorizerArray).toarray()

transformer.fit(testVectorizerArray)
print 
tfidf = transformer.transform(testVectorizerArray)
print tfidf.todense()

出力は次のとおりです。

Fit Vectorizer to train set [[1 0 1 0]
 [0 1 0 1]]
Transform Vectorizer to test set [[0 1 1 1]]
[1 0 1 0]
[0 1 1 1]
0.408
[0 1 0 1]
[0 1 1 1]
0.816

[[ 0.70710678  0.          0.70710678  0.        ]
 [ 0.          0.70710678  0.          0.70710678]]

[[ 0.          0.57735027  0.57735027  0.57735027]]
于 2012-08-25T19:27:53.153 に答える
14

これはあなたを助けるはずです。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity  

tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(train_set)
print tfidf_matrix
cosine = cosine_similarity(tfidf_matrix[length-1], tfidf_matrix)
print cosine

出力は次のようになります。

[[ 0.34949812  0.81649658  1.        ]]
于 2014-04-04T18:29:28.053 に答える