2012-08-25 24 views
60

を見つけるために、私は残念ながら、著者は、実際には2つの文書間の類似性を見つけるために、余弦を使用することを含む最後のセクションのための時間を持っていなかったPart 1 & Part 2で利用できたチュートリアルを以下ました。記事の例を参考にして、stackoverflowのリンクをたどってみました。上記のリンクに記載されているコードを含めるだけで、簡単に答えを出すことができます。私は行列のPython:TF-IDF-余弦:文書の類似性

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]] 

次私は、コサイン類似度を計算するために、この出力を使用するかどうかはわからないしている上記のコードの結果として

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() 

、私は2つのベクトルにコサイン類似点を実装する方法を知っています同様の長さですが、ここでは2つのベクトルを特定する方法がわかりません。

+3

trainVectorizerArrayの各ベクトルに対して、testVectorizerArrayのベクトルとのコサイン類似度を見つける必要があります。 – excray

+0

@excrayありがとう、私はそれを把握するためにあなたの有用な点で、私は答えを入れるべきですか? –

+0

@excrayしかし、私は小さな問題を抱えています。私はマトリックスに示されている最終結果を使用していないので、実際のtf * idf計算にはこれが使用されていません。 –

答えて

13

@ excrayのコメントの助けを借りれば、答えを見つけ出すことができます。列車データとテストデータを表す2つの配列を反復処理する単純なforループを実際に書く必要があります。

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

をそしてちょうどベクトルにを反復するループのための簡単なを書き、ロジックは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]] 
+1

nice ..私は初めから学んでいますし、あなたの質問と回答が一番簡単です。私はあなた自身のロールの代わりにnp.corrcoef()を使うことができると思います。 – wbg

+1

もう一度、あなたのメソッドは任意のノルムを許します... ... – wbg

+1

@spicyramenは小数点以下3桁まで切り上げます –

113

まず第一に、あなたはカウント特徴を抽出し、TF-IDFの正規化と行方向のユークリッド正規化を適用したい場合は、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> 

(例えばデータセットの最初の)とあなただけのfの内積を計算するために必要な他の全て一つの文書のコサイン距離を見つけるためにtfidfベクトルとして他のすべてのものを含む第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-学ぶすでに密集両方のために(機械学習の用語でカーネル別名)その作業をペアごとのメトリックを提供およびベクトルコレクションの疎な表現。この場合、我々はまた、線形カーネルとして知られている内積必要があります。

>>> 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: [email protected] (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 ---- 

二番目に最も類似した文書は、多くの一般的な単語を持っているので、元のメッセージを引用返信です:

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

In article <[email protected]> [email protected] (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    [email protected] 
Physics and Philosophy, Reed College (NeXTmail accepted) 
Artificial Life Project   Reed College 
Reed Solar Energy Project (SolTrain) Portland, OR 
+3

すばらしい答え!おかげでolivier! –

+0

フォローアップの質問:非常に大きな文書数がある場合、ステップ2のlinear_kernel関数は、行数に対して線形であるため、パフォーマンスのボトルネックになる可能性があります。 sublinearにそれを減らす方法についての任意の考えですか? – Shuo

+0

Elastic SearchとSolrの「more like this」クエリを使用して、サブリニアスケーラビリティプロファイルで近似した回答を得ることができます。 – ogrisel

15

私はその古いポストを知っています。私はhttp://scikit-learn.sourceforge.net/stable/パッケージを試しました。ここで私のコードはコサインの類似性を見つけることです。質問は、あなたがこのパッケージにコサイン類似度を計算する方法だったとここでここでクエリがtrain_setとDOC1、DOC2とDOC3の最初の要素であると仮定し、私が欲しいの文書にしていること

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

f = open("/root/Myfolder/scoringDocuments/doc1") 
doc1 = str.decode(f.read(), "UTF-8", "ignore") 
f = open("/root/Myfolder/scoringDocuments/doc2") 
doc2 = str.decode(f.read(), "UTF-8", "ignore") 
f = open("/root/Myfolder/scoringDocuments/doc3") 
doc3 = str.decode(f.read(), "UTF-8", "ignore") 

train_set = ["president of India",doc1, doc2, doc3] 

tfidf_vectorizer = TfidfVectorizer() 
tfidf_matrix_train = tfidf_vectorizer.fit_transform(train_set) #finds the tfidf score with normalization 
print "cosine scores ==> ",cosine_similarity(tfidf_matrix_train[0:1], tfidf_matrix_train) #here the first element of tfidf_matrix_train is matched with other three elements 

ための私のコードですコサインの類似性の助けを借りてランク付けする。私はこのコードを使用することができます。

また、質問に記載されたチュートリアルは非常に便利でした。ここで、以下のように出力がされる

part-III

part-II、それ part-Iためのすべての部分である:ここで1

[[ 1.   0.07102631 0.02731343 0.06348799]] 

クエリ自体と一致する他の3つが一致のスコアであることを表しますそれぞれの文書を照会します。

+1

cosine_similarity(tfidf_matrix_train [0:1]、tfidf_matrix_train)1を千以上に変更するとどうなるでしょうか?どうすればそれを処理できますか? – ashim888

8

これはあなたに役立つでしょう。

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.  ]] 
+3

どのように長さを取得しますか? – spicyramen

12

は、私はあなたに私が書いた別のチュートリアルを挙げてみましょう。あなたの質問に答えるだけでなく、なぜ私たちがいくつかのことをやっている理由を説明します。私もそれを簡潔にしようとしました。

したがって、list_of_documentsは文字列の配列で、documentは単なる文字列です。そのような文書は、documentと最も類似しているlist_of_documentsから検索する必要があります。

さんは一緒にそれらを結合してみましょう:documents = list_of_documents + [document]

はの依存関係を見てみましょう。なぜ私たちがそれぞれを使うのかは明らかになります。用途可能なアプローチの

from nltk.corpus import stopwords 
import string 
from nltk.tokenize import wordpunct_tokenize as tokenize 
from nltk.stem.porter import PorterStemmer 
from sklearn.feature_extraction.text import TfidfVectorizer 
from scipy.spatial.distance import cosine 

一つは、私たちは他人の文書から独立に各単語を治療し、ちょうど大きな袋に一緒にそれらのすべてを投げるbag-of-wordsアプローチ、です。ある観点から見ると、(言葉のつながり方などの)多くの情報が失われますが、別の観点からはモデルが単純になります。

英語やその他の人間言語では、「a」、「the」、「in」のような多くの「役に立たない」言葉があり、それは非常に共通して多くの意味を持たない。それらはstop wordsと呼ばれ、削除することをお勧めします。誰かが気付くことができるもう一つのことは、「分析する」、「分析者」、「分析」のような言葉は本当に似ているということです。彼らは共通の根を持ち、すべてがただ一つの単語に変換することができます。このプロセスはstemmingと呼ばれ、速度、攻撃性などが異なる複数のステマーが存在します。そこで、各文書をストップワードのない単語のリストに変換します。また、すべての句読点を破棄します。

porter = PorterStemmer() 
stop_words = set(stopwords.words('english')) 

modified_arr = [[porter.stem(i.lower()) for i in tokenize(d.translate(None, string.punctuation)) if i.lower() not in stop_words] for d in documents] 

この単語の袋はどのように役立ちますか?我々は3つのバッグ:[a, b, c][a, c, a]および[b, c, d]を想像してください。それらをvectors in the basis[a, b, c, d]に変換できます。だから我々はベクトルで終わる:[1, 1, 1, 0][2, 0, 1, 0][0, 1, 1, 1]。同様のことは私たちの文書にあります(ベクトルだけが長くなるでしょう)。今度は、多くの単語を削除し、他の単語も削除してベクトルのサイズを小さくしていることがわかります。ここに興味深い観察があります。ドキュメントが長くなるほど、要素が短くなるよりも肯定的な要素を持つようになります。そのため、ベクトルを正規化するのがいいです。これは用語頻度TFと呼ばれ、人々はまた、単語が他の文書でどのくらいの頻度で使用されているかに関する追加情報を使用しました - 逆文書頻度IDF。一緒に私たちはメートル法TF-IDF which have a couple of flavorsを持っています。これは実際にベクトライザーallows to do a lot of thingsストップワードと小文字を取り除くよう

modified_doc = [' '.join(i) for i in modified_arr] # this is only to convert our list of lists to list of strings that vectorizer uses. 
tf_idf = TfidfVectorizer().fit_transform(modified_doc) 

:-) sklearnに1行で達成することができます。私はsklearnに英語以外のストップワードがないので、別のステップでそれらを実行しましたが、nltkは持っています。

ベクトルを計算しました。最後のステップは、最後のステップに最も類似するものを見つけることです。これを達成するにはさまざまな方法がありますが、その1つはユークリッド距離であり、理由はdiscussed hereでそれほど大きくありません。別のアプローチはcosine similarityです。

l = len(documents) - 1 
for i in xrange(l): 
    minimum = (1, None) 
    minimum = min((cosine(tf_idf[i].todense(), tf_idf[l + 1].todense()), i), minimum) 
print minimum 

今すぐ最小最高のドキュメントとそのスコアについての情報を持っています:私たちはすべての文書と文書の間で計算するコサイン類似度と、最後の1を繰り返します。

+2

Signこれは、オペアンプが求めていたものではありません。コーパス内の "最高のドキュメント"ではなく、最適なdocを検索します。しないでください、私のようなpplは、opタスクのためにあなたの例を使用しようとして時間を無駄にし、行列の大きさを変える狂気にドラッグされます。 – minerals

+0

どう違うのですか?アイデアはまったく同じです。フィーチャを抽出し、クエリとドキュメント間の余弦距離を計算します。 –

+0

これは等しい形状の行列でこれを計算しています。サイズが違うクエリマトリックス、opの列セットとテストセットを持っている別の例を試してみてください。私はそれが動作するようにあなたのコードを変更することができませんでした。 – minerals

関連する問題