質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

3816閲覧

pythonで文書間のコサイン類似度を求める

mangopurin

総合スコア12

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/12/06 10:35

前提・実現したいこと

tf-idf法を用いた結果を用いて、文書間のコサイン類似度を求めています。
tf-idfを用いて、テキストの文書ベクトルを求めることは出来ました。
ここから、文書間のコサイン類似を求める方法が分かりません。

今後、多くの文書に対して、コサイン類似度を求めるので、同じコードを書くのではなく、for文でまわしたいと考えています。

御享受、よろしくお願いします。

該当のソースコード

python

1 2import MeCab 3import math 4 5 6 7 8 9 10 11sentence = ["私はみかんを食べました。","私はリンゴを食べました。"] 12print(sentence) 13num = len(sentence) 14result = [] 15print("全文書数") 16print(num) 17 18 19a = [] 20 21 22for i in range(num): 23 tagger = MeCab.Tagger() 24 result.append(tagger.parse(sentence[i])) 25 print("形態素解析した結果 result") 26 print(result) 27 28for i in range(num): 29 for chunk in result[i]: 30 #print(chunk) 31 cols = chunk.split("\t") 32 #print(cols) 33 if len(cols) >= 4: 34 parts = cols[3].split(",") 35 if parts[0].startswith("動詞"): 36 a.append(cols[0]) 37 38print(a) 39#文章を形態素解析して、文章事の単語をリストへ 40wordCount = {}#辞書 41allCount = {} 42sub_tfstore = {} 43tfcounter = {} 44tfstore = {} 45sub_idf = {} 46idfstore = {} 47merge_idf = {} 48tfidf = {} 49merge_tfidf = {} 50wordList = [] 51 52sum = 0 53 54for i in range(num): #resultに形態素解析の結果 55 wordList.append(result[i].split()[:-1:2])#wordListにresultを加える 56 print("単語のみ") 57 print(wordList) 58 59for i in range(num):#iをnum分まわす 60 for word in wordList[i]:#wordをwordList分まわす 61 allCount[i] = wordCount.setdefault(word,0)#wordCountのwordが0 62 wordCount[word]=1 63 allCount[i] = wordCount 64 65 wordCount = {} 66 print("単語の数") 67 print(allCount) 68 69for i in range(num):#tfの分母を計算 70 for word in allCount[i]: 71 sum = sum + allCount[i][word] 72 sub_tfstore[i] = sum 73 sum = 0 74 print(sub_tfstore) 75 76for i in range(num): 77 for word in allCount[i]: 78 tfcounter[word] = allCount[i][word]*1.0/sub_tfstore[i] 79 tfstore[i] = tfcounter 80 print("tfの値") 81 print(tfstore) 82 tfcounter = {} 83 84for i in range(num): 85 for word in wordList[i]: 86 wordCount.setdefault(word,0) 87 for word in allCount[i]: 88 wordCount[word] += 1 89 sub_idf = wordCount 90 print("単語の文章あたりの出現回数") 91 print(sub_idf) 92 93for i in range(num): 94 for word in allCount[i]: 95 idfstore[word] = math.log(1.0*math.fabs(num)/math.fabs(sub_idf[word])) 96 merge_idf[i] = idfstore 97 idfstore = {} 98 print("idfの値") 99 print(merge_idf) 100 101 102#tfidfの計算 103for i in range(num): 104 for word in allCount[i]: 105 tfidf[word] = tfstore[i][word]*merge_idf[i][word] 106 merge_tfidf[i] = tfidf 107 tfidf = {} 108 print("tfidfの値") 109 print(merge_tfidf) 110 111for i in range(num): 112 for word,count in sorted(merge_tfidf[i].items(),key = lambda x:x[1],reverse = True): 113 print('text%d: %-16s %2.3f' % (i+1,word,count)) 114

結果

text1: みかん 0.087
text1: 私 0.000
text1: は 0.000
text1: を 0.000
text1: 食べ 0.000
text1: まし 0.000
text1: た 0.000
text1: 。 0.000
text2: リンゴ 0.087
text2: 私 0.000
text2: は 0.000
text2: を 0.000
text2: 食べ 0.000
text2: まし 0.000
text2: た 0.000
text2: 。 0.000

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

scipyを使うとベクトルの配列→距離行列への変換が容易に行なえます。

python

1from scipy.spatial.distance import pdist, squareform 2 3data = [[1.0, 0.0, 0.5, 0.3, 0.2], 4 [2.3, 3.1, 0.1, 0.3, 0.5], 5 [1.0, 0.5, 0.2, 0.1, 0.1]] 6 7dmat = squareform(pdist(data, metric="cosine")) 8print(dmat) 9""" => 10[[0. 0.44631947 0.14469177] 11 [0.44631947 0. 0.1162559 ] 12 [0.14469177 0.1162559 0. ]] 13"""

余談ですが、tfidfの計算もsklearnで楽に行なえます。分かち書きされた文字列のリストを渡せば良いです。日本語でちゃんと動かすには、analyzerを自分で定義するなどする必要があります。

https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html

python

1from sklearn.feature_extraction.text import TfidfVectorizer 2 3data = ["お腹 が 空い た", 4 "お腹 が いっぱい", 5 "電車 が 空い た", 6 "りんご が いっぱい"] 7 8tfidf = TfidfVectorizer(analyzer=lambda s:s.split()) 9vectors = tfidf.fit_transform(data).toarray() 10print(tfidf.get_feature_names()) 11print(vectors) 12""" => 13['いっぱい', 'お腹', 'が', 'た', 'りんご', '空い', '電車'] 14[[0. 0.53931298 0.35696573 0.53931298 0. 0.53931298 0. ] 15 [0.64043405 0.64043405 0.42389674 0. 0. 0. 0. ] 16 [0. 0. 0.32902288 0.4970962 0. 0.4970962 0.6305035 ] 17 [0.5728925 0. 0.37919167 0. 0.72664149 0. 0. ]] 18"""

特別な理由がなければ自分で書く必要はありません。

投稿2018/12/06 12:10

編集2018/12/06 12:40
hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問