Pythonでいろいろやってみる

Pythonを使った画像処理や機械学習などの簡単なプログラムを載せています。

TF-IDFとコサイン類似度により文書の類似度を判定する

文書の類似度を調べます。関連文献の調査などで「自動で似ている文書を探してくれれば楽なのに」と思うことがありますが、類似度が求められれば自動化の可能性が出てきます。
TF-IDFは文書中に含まれる単語の重要度を評価する手法の1つであり、情報検索などに利用されています。TF(Term Frequency、単語の出現頻度)はそのまま出現頻度を示し、IDF(Inverse Document Frequency、逆文書頻度)は、単語がある文書だけでに現れるのか、多くの文書に現れるのかといった希少度を現します。
TF-IDFはTFとIDFの積であり、出現頻度が大きく(TF大)、特定の文書において現れる(IDF大)場合に大きくなります。例えば「こと」、「ため」といった様々な文書でよく現れる単語についてはTFは大きいですがIDFは小さくなるためTF-IDFが小さくなります。
また、コサイン類似度はベクトルとベクトルの成す角度を用いた類似度の計算手法で、1に近いほど類似、0に近いほど似ていない値になります。TF-IDFによりすべての単語を次元としたベクトルを各文書について生成し、文書のベクトル同士のコサイン類似度を求めます。
モジュールscikit-learnには TF-IDFおよびコサイン類似度のライブラリが含まれておりそれを使用します。

関連記事

N-gramで文章の類似度を調べる

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.7.0
  • scikit-learn 0.19.2
準備

jupyter notebookファイル(***.ipynb)と同じディレクトリにTF-IDFフォルダを作成し、以下の4つのニュース本文をコピー、それぞれ別のテキストファイルとしてTF-IDFフォルダに保存しました。
text1.txtとtext4.txtは同じ逃走事件に関する記事なので類似度が高いことが期待されます。text2.textは年金、text3.textはNBAドラフトの八村選手に関連する記事なので類似度が低いことが期待されます。

知人頼り逃走、潜伏か=女性の車でも移動-元被告の自宅から注射器・神奈川(時事ドットコムニュース)→text1.txt

窃盗や傷害、覚せい剤取締法違反(使用)などの罪で実刑判決が確定した無職小林誠容疑者(43)=公務執行妨害容疑で指名手配=が収容に応じず逃走した事件で、同容疑者の知人が「車で(神奈川県)大和市まで送った」と警察に話していることが21日、分かった。大和市内で別の知人と会っていたといい、県警は知人を頼り逃走、潜伏している可能性があるとみて行方を追っている。
【関連ニュース】実刑確定の男、刃物持ち逃走
 また、横浜地検が20日に小林容疑者の自宅アパートを家宅捜索した際、使用済みとみられる注射器を複数本押収していたことも判明。覚せい剤を使用した可能性もあるとみて鑑定している。
 県警によると、小林容疑者は19日午後1時ごろ、収容のため同県愛川町の同容疑者宅を訪れた横浜地検の職員らに刃物を示しながら小型車で逃走。同日深夜、厚木市内で車を乗り捨てたが、20日早朝、知人女性に同市から10キロほど離れた大和市の知人男性宅付近まで車で送ってもらったという。

「麻生氏「途中の話は分からない」=財政審、年金記述削除で(時事ドットコムニュース)→text2.txt

麻生太郎財務相は21日、財政制度等審議会の建議(意見書)で原案段階にあった年金に関する記述が最終的に削除された問題で、「途中の話は分からない」と明言を避けた。同日の記者会見で語った。
【関連ニュース】老後の備え、2000万円必要?
 19日に麻生氏に提出された建議には、原案に盛り込まれていた「基礎年金給付水準が想定よりも低くなることが見込まれる」との記述がなかった。「老後資金が2000万円不足する」と試算した金融庁審議会の報告書が批判され始めた時期と財政審会合で原案が非公式に提示された時期はほぼ重なる。このため、財政審の事務局を務める財務省が安倍政権に配慮し、原案を変更した可能性がある。
 麻生氏は会見で、報告書が批判を浴びたため、年金記述の削除につながった可能性について、「考えられない」と否定した。

八村、本拠地で実感=ウィザーズから1巡目指名-NBA(時事ドットコムニュース)→text3.txt

【ワシントン時事】米プロバスケットボール協会(NBA)のドラフト会議から一夜明けた21日、ウィザーズから1巡目9位で指名を受けたゴンザガ大の八村塁(21)が、本拠地ワシントンのキャピタルワン・アリーナで記者会見に臨み、「プロになる実感は湧いてきた。しっかり集中できる環境をつくっていきたい」と意気込みを示した。
【特集】八村塁、日本初のNBAドラフト1巡目指名
 アリーナ外にある大型ビジョンには、スーツ姿の八村の写真が映し出され、日本語と英語の両方で「八村塁選手、DCへようこそ」とも。ドラフト会議があったニューヨークから本拠地に到着し、チーム関係者らに盛大な歓迎も受けた。
ウィザーズのユニホームを手に、記念写真に納まる八村塁(中央)=21日、ワシントン
 会見には、ブルックス監督と編成の責任者が同席。現地メディアとの質疑応答では、流ちょうな英語でバスケットボールを始めたきっかけなどを話し、笑いを取る場面もあった。
 この日の夜は、人気歌手のコンサートが予定されており、バスケットボールのコートは見られなかったそうだが、「アリーナはいい感じ。落ち着いていて、いいなと思った」と感想を述べた。

実刑確定の逃走男、服着替えか=コンビニ防犯カメラに姿-神奈川(時事ドットコムニュース)→text4.txt

窃盗などの罪で実刑判決が確定した無職小林誠容疑者(43)=公務執行妨害容疑で指名手配=が収容に応じず逃走した事件で、小林容疑者は事件当日の夕方、神奈川県厚木市内のコンビニエンスストアに立ち寄った際、逃走時とは異なる服装だったことが20日、県警への取材で分かった。コンビニの防犯カメラに姿が映っており、県警は同容疑者が発見を恐れて着替えたとみて、行方を追っている。
収監に抵抗、刃物持ち逃走=実刑確定の男
 県警によると、小林容疑者の車は19日午後6時45分ごろ、厚木市のコンビニの駐車場に到着。同容疑者は車から降り、しばらくして車に戻ってコンビニを後にした。逃走した際は白いキャップ帽と白っぽいTシャツ、ハーフパンツ姿だったが、コンビニの映像では、上下黒っぽい服を着ていた。
 これに先立つ同5時55分ごろには、相模原市の量販店に立ち寄っていたことも判明。駐車場でいったん車から降りたが、すぐに戻って立ち去ったという。

コード
from janome.tokenizer import Tokenizer
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.metrics.pairwise import cosine_similarity

# テキストファイルのリスト 
filenames=['TF-IDF/text1.txt','TF-IDF/text2.txt','TF-IDF/text3.txt','TF-IDF/text4.txt']
wakati_list = []

for filename in filenames:
    # テキストファイルを読み出しtextに代入 
    with open(filename,mode='r',encoding = 'utf-8-sig') as f:
        text = f.read()
    
    # 分かち書き
    wakati = ''
    t = Tokenizer() 
    for token in t.tokenize(text):  # 形態素解析
        hinshi = (token.part_of_speech).split(',')[0]  # 品詞情報を取得
        hinshi_2 = (token.part_of_speech).split(',')[1]  # 品詞情報の2項目目を取得
        if hinshi in ['名詞']:  # 品詞が名詞、動詞、形容詞の場合のみ以下実行
            if not hinshi_2 in ['空白','*']:  # 品詞情報の2項目目が空白か*の場合は以下実行しない
                word = str(token).split()[0]  # 単語を取得
                if not ',*,' in word:  # 単語に*が含まれない場合は以下実行
                    wakati = wakati + word +' ' # オブジェクトwakatiに単語とスペースを追加 
    wakati_list.append(wakati) # 分かち書き結果をリストに追加
wakati_list_np = np.array(wakati_list) # リストをndarrayに変換

# vectorizerの生成。token_pattern=u'(?u)\\b\\w+\\b'で1文字の語を含む設定
vectorizer = CountVectorizer(token_pattern=u'(?u)\\b\\w+\\b')
# transformerの生成。TF-IDFを使用
transformer = TfidfTransformer()

tf = vectorizer.fit_transform(wakati_list_np) # ベクトル化
tfidf = transformer.fit_transform(tf) # TF-IDF
tfidf_array = tfidf.toarray()
cs = cosine_similarity(tfidf_array,tfidf_array)  # cos類似度計算
print(cs)
実行結果

文書1と文書2は類似度0.12、文書3は類似度0.08、文書4は類似度0.51となりました。文書4は文書1と同じ逃走犯についての関連ニュースのため類似度が高いのは期待通りです。文書2は年金問題、文書3はNBAドラフトに関するニュースなので類似度が低いのは当然の結果となります。

[[1. 0.12 0.08 0.51]
[0.12 1. 0.05 0.03]
[0.08 0.05 1. 0.06]
[0.51 0.03 0.06 1. ]]

以下のサイトを参考にさせていただきました

Wikipedia >> tf-idf
DevelopersIO >> tf-idfについてざっくりまとめ_理論編
コード7区 >> TF-IDF で文書をベクトル化。python の TfidfVectorizer を使ってみる
オブジェクトの広場 >> はじめての自然言語処理
TF-IDF Cos類似度推定法
いっきのblog>>TF-IDFとコサイン類似度を使って似ている文章を見つける

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村