🕌

コサイン類似度を計算して文章を比べてみた

2024/05/21に公開

やること

コサイン類似度によってどれくらい文章が似ているかを試してみました。
参考文献は以下2点の組合せです。
https://www.ohmsha.co.jp/book/9784274229008
https://www.oreilly.co.jp/books/9784873118680/

前提

コサイン類似度とは

2つの単語ベクトルの内積を距離の積で割ったもので2つの単語の似ている度合いを計算することができます。

\text{cosine similarity} = \cos(\theta) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\| \|\mathbf{b}\|} = \frac{\sum_{i=1}^{n} a_i b_i}{\sqrt{\sum_{i=1}^{n} a_i^2} \sqrt{\sum_{i=1}^{n} b_i^2}}

Tf-idfとは

単語の出現頻度(Term Frequency)と逆文書頻度(Inverse Document Frequency)を組み合わせたもので、ある単語の情報量を表します。今回はベクトル化のところでTfidfVectorizerを用いました。きちんとした定義は以下のようになりますが、idfを対数変換して使うこともあるようです。
bow(w, d) = [文書d内の単語wの出現回数】
tf(w, d) = bow(w, d)/[文書d内の単語数】
idf(w) = [全文書数N】/【単語wが含まれる文書数】
tf-idf(w, d) = tf(w, d) * idf(w)
『機械学習のための特徴量エンジニアリング』p.63より

データの準備

日本語フェイクニュースデータセットを用います。

https://github.com/tanreinama/Japanese-Fakenews-Dataset

先頭5行は以下のような感じになっています。

id context isfake nchar_real nchar_fake
000128042337 朝日新聞など各社の報道によれば、宅配便最大手「ヤマト運輸」が日本郵政公社を相手取り、大手コン... 0 541 0
00012b7a8314 11月5日の各社報道によると、諫早湾干拓事業は諫早海人(諫早湾の「海」)に囲まれる大洋に位置... 2 0 385
0005fb48880b 産経新聞、中日新聞によると、2004年から2005年まで、この大会による3年おきの開催を、2... 2 0 255
00087f9e14ab 開催地のリオデジャネイロ市に対して、大会期間中のリオデジャネイロオリンピックに関する公式発表... 1 435 218
000c9ac3d552 毎日新聞・時事通信によると、2006年2月13日には、グッドウィル・グッゲンハイム・アン・ハ... 2 0 248

ベクトル化してコサイン類似度行列を計算

TfidfVectorizerを使ってベクトル化し、cosine_similarityで行列を求めます。

# TF-IDFを使ってベクトル化し、コサイン類似度行列を計算する
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(df['context'])
cos_sim_matrix = cosine_similarity(tfidf_matrix, tfidf_matrix)
pd.DataFrame(cos_sim_matrix).head()
0 1 2 3 4 5 6 7 8 9 ... 13030 13031 13032 13033 13034 13035 13036 13037 13038 13039
0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.002767 0.0 ... 0.000000 0.000 0.0 0.0 0.003669 0.001884 0.0 0.000000 0.0 0.000000
1 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 ... 0.000000 0.000 0.0 0.0 0.000000 0.000000 0.0 0.000000 0.0 0.000000
2 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 ... 0.000000 0.000 0.0 0.0 0.000000 0.000000 0.0 0.002633 0.0 0.008221
3 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.006065 0.0 ... 0.004576 0.003 0.0 0.0 0.000000 0.000000 0.0 0.000000 0.0 0.000000
4 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.007843 0.0 ... 0.000000 0.000 0.0 0.0 0.000000 0.000000 0.0 0.000000 0.0 0.000000

類似するテキストを取得

流れとしては最も近いコサイン類似度を持つインデックスのペアを取得し、その後インデックスと類似度スコアに対応するテキストを取得します。実装は以下のとおりです。

import numpy as np
from pprint import pprint

def get_similar_pair(cos_sim_matrix, value):
    """最も近いコサイン類似度を持つインデックスのペアを取得する"""
    diff_matrix = np.abs(cos_sim_matrix - value)
    # 対角成分を除外
    np.fill_diagonal(diff_matrix, np.inf)  
    pair = np.unravel_index(np.argmin(diff_matrix), cos_sim_matrix.shape)
    return pair

def get_similar_text(df, cos_sim_matrix, pair, label):
    """インデックスと類似度スコアに対応するテキストを取得する"""
    index1, index2 = pair
    similarity_score = cos_sim_matrix[index1, index2]
    text1 = df['context'].iloc[index1]
    text2 = df['context'].iloc[index2]
    result = {
        'label': label,
        'index1': index1,
        'index2': index2,
        'similarity_score': similarity_score,
        'text1': text1,
        'text2': text2
    }

    return result

# 類似度スコアのリスト
values = [0.20, 0.50, 0.80]

# 各類似度スコアについて結果を表示
for value in values:
    nearest_pair = get_similar_pair(cos_sim_matrix, value)
    nearest_result = get_similar_text(df, 
                                      cos_sim_matrix,
                                      nearest_pair, 
                                      label='Nearest Pair (Target: {})'.format(value))

    print(nearest_result['label'] + ":")
    pprint(nearest_result)
    print("\n" + "="*50 + "\n")

Nearest Pair (Target: 0.2)
Index 1: 4092
Index 2: 11129
Similarity Score: 0.1999867493567516

Text 1:
朝日新聞とスポーツニッポンによると、河野氏は神奈川県の程ヶ谷カントリークラブでキャディーとして活動後、1959年にプロゴルファーテストに合格。1967年に関東オープン選手権と日本シリーズに優勝。1968年には日本オープンと日本シリーズ(連覇)を二度制覇している。2001年のドラコン選手権大会で1位、2005年のドラコン選手権大会で1位、2007年のドラコン選手権は準優勝。2008年のドラコン選手権は5位。ドラコン選手権の上位1%未満のメンバーは、2006年、2019年、2020年の大会を勝ち抜き、2020年には8割のメンバーがそれぞれ優勝を果たしている。プロになった後、大学時代のキャリアを活かしてツアーに出演したり、ゴルフにも積極的に挑戦したりしたという。また、ゴルフ解説者としては2005年に来日した。

Text 2:
朝日新聞によると、プロゴルファーで、「リトル河野(コーノ)」の愛称で知られた河野高明(こうの・たかあき)選手が4月22日、肝臓癌で死去した。70歳だった。スポーツニッポンが関係者の話として紹介したところによると、河野氏は1年ほど前に肝臓癌を患って体調を崩し、数日前から秋田県の玉川温泉に療養に出ていたが、吐血してその後仙北市(せんぼくし)にある病院に搬送されていた。朝日新聞とスポーツニッポンによると、河野氏は神奈川県の程ヶ谷カントリークラブでキャディーとして活動後、1959年にプロゴルファーテストに合格。1967年に関東オープン選手権と日本シリーズに優勝。1968年には日本オープンと日本シリーズ(連覇)の2冠を獲得。1969年からは5年連続してマスターズトーナメントに出場し、その最初の年には当時のアジア出身選手最高の13位を記録。160センチの小柄な体格から「リトル河野」の愛称で知られ、また安田春雄、杉本英世両選手らと「和製ビッグスリー」と称えられた。優勝は国外での4勝を含め21勝だった。2003年から2008年まで日本プロゴルフ協会理事を勤めたが、2005年の協会長選挙を巡って暴力団関係者に拉致・監禁される事件もあった。


Nearest Pair (Target: 0.5)
Index 1: 7324
Index 2: 11128
Similarity Score: 0.4998068597859622

Text 1:
イラク独立選挙管理委員会は、憲法草案が承認されたと25日発表した。賛成は78%、反対は21%で、必要とされる過半数の賛成を得た。スンナ派(スンニー派)住民の多い2県では3分の2以上の反対があり草案は否決された。3県以上で3分の2以上の反対票があった場合、草案は否決されることになっていた。アンバール県(右の図13)とサラーフッディーン県(右の図2)では、ほとんどの住民が反対に回った。アンバール県では反対は97%、サラーフッディーン県では82%だった。2州での否決は中間発表時に明らかになっており、スンナ派の住民が多いニーナワー県(右の図14)での投票が注目された。ニーナワー県では反対が55%に達したが、全国で草案を否決するために必要な3分の2の反対には達しなかった。独立選挙管理委員会のファリド・アヤル氏は投票の集計は「100パーセント正しい」とし、「投票結果に影響を与えるような不正はなかった」と語った。いっぽう、スンナ派のサレー・アル・ムトラク氏は、草案の国民投票は「茶番劇」であると述べ、政府は反対の多かった地域の投票箱を盗んだと非難した。国際連合から派遣された選挙監視団はムトラク氏の非難に反論している。選挙監視団のリーダーを務めるカリーナ・ペレッリ氏は、投票結果は正確であり、国連選挙監視団により調査されたと語った。投票者の総数は985万人で、投票率は63%だった。今年1月に行われた移行政府選挙の投票数を100万人上回った。イラク議会は今年12月15日に選挙を行う予定である。英語版ウィキニュースからの翻訳です。

Text 2:
イラク独立選挙管理委員会は、憲法草案が承認されたと25日発表した。賛成は78%、反対は21%で、必要とされる過半数の賛成を得た。スンナ派(スンニー派)住民の多い2県では3分の2以上の反対があり草案は否決された。3県以上で3分の2以上の反対票があった場合、草案は否決されることになっていた。アンバール県(右の図13)とサラーフッディーン県(右の図2)では、ほとんどの住民が反対に回った。アンバール県では反対は97%、サラーフッディーン県では82%だった。2州での否決は中間発表時に明らかになっ、3つの州で反対票が12%に達していた。他に反対が2種類あることを考慮し、両州にはさらなる修正勧告が必要となった。1つは16州で残りの3州で約25%、3州で4%であった。26州では賛成票が21%に達したが、反対票が36%のみだった。全州での棄権は1,345,890票、賛成票は96454票だった。


Nearest Pair (Target: 0.8)
Index 1: 1686
Index 2: 11073
Similarity Score: 0.800273546952605

Text 1:
今回のデング熱流行を受けて、代々木、新宿中央の両公園付近ではイベントの開催中止などが相次いでいる。代々木公園では9月6・7日の「日本・インドネシア市民友好フェスティバル」「美味しいペルー」と、9月13・14日の「ベトナムフェスティバル」の開催を取りやめた。このうち、「美味しいペルー」のイベントは12月に延期するとしている。また9月10日の「TRIGGER FES(トリガー・フェス)」も近くのライブハウスに開催地を変えて行うとしているほか、9月6・7日の「アジアカルチャーフェスティバル」も虫よけスプレーを用意するなどの対策をしたうえで予定通り行う。これらのイベントは、今回の公園閉鎖の対象となっていない、南側のイベント広場や野外ステージで開催される予定だったもので、「来場者の安全・安心を第一に考えた」「出店者らに迷惑になることが起こりうる」として、開催中止や会場の変更を行ったとしている。また20日以後にも5つのイベントの開催が予定されているが、すべての主催者は「今後の事態の推移を見て、開催するかどうかを判断したい」としている。新宿中央公園でも9月5日に開催される予定されていた屋台の食事や酒を楽しむ会の開催が取りやめとなった。このイベントは7月14日から平日夜に毎日開催されてきたもので、9月5日はその最終日の予定になっていた。同公園の今後のイベントについても新宿区は「園内の蚊がウィルスを持っているかどうかなどを踏まえて、開催するかどうかを判断したい」としている。また、東京を修学旅行や社会見学に訪れる予定にしていた学校で、行先の変更なども出ている。千葉市教育委員会によると、同市内の2つの市立小学校が9月8日と12日にそれぞれ予定していたNHKへの見学を、同地から東に約4.5㎞離れた国会議事堂に行先を変更。「子供たちの安全を第一に考えて、代替地を探した」としている。この他、八王子市の市立由井第三小学校も9月30日に予定していたNHK見学と代々木公園での昼食を延期。京都造形芸術大学も港区内にある通信教育部のキャンパスが9月13日に予定していた国立代々木競技場への見学を取りやめて、学内での座学に変更することを決めた。また勝山市の市教委も、同市立勝山北部中学校が9月17-19日に修学旅行で訪れる都内方面で、旅行日程に代々木公園付近の訪問先はないが、自由行動をとる際は「代々木公園に近寄らないように」指導するとしている。

Text 2:
今回のデング熱流行を受けて、代々木、新宿中央の両公園付近ではイベントの開催中止などが相次いでいる。代々木公園では9月6・7日の「日本・インドネシア市民友好フェスティバル」「美味しいペルー」と、9月13・14日の「ベトナムフェスティバル」の開催を取りやめた。このうち、「美味しいペルー」のイベントは12月に延期するとしている。また9月10日の「TRIGGER FES(トリガー・フェス)」も近くのライブハウスに開催地を変えて行うとしているほか、9月6・7日の「アジアカルチャーフェスティバル」も虫よけスプレーを用意するなどの対策をしたうえで予定通り行う。これらのイベントは、今回の公園閉鎖の対象となっていない、南側のイベント広場や野外ステージで開催される予定だったもので、「来場者の安全・安心を第一に考えた」「出店者らに迷惑になることが起こりうる」として、開催中止や会場の変更を行ったとしている。また20日以後にも5つのイベントの開催が予定されているが、すべての主催者は「今後の事態の推移を見て、開催するかどうかを判断したい」としている。新宿中央公園でも9月5日に開催される予定されていた屋台の食事や酒を楽しむ会の開催が取りやめとなった。このイベントは7月14日から平日夜に毎日開催されてきたもので、9月5日はその最終日の予定になっていた。同公園の今後のイベントについても新宿区は「園内の蚊がウィルスを持っているかどうかなどを踏まえて、開催するかどうかを判断したい」としている。また、東京を修学旅行の帰りに訪れる、在校生の卒業生に関しては、9月16日に「卒業生の皆様にご挨拶をさせていただきたい」と話している。

コメントなど

類似度が0.20のときは一見同じようなことを言っていますが、使われている言葉や内容は結構異なる印象です。類似度が0.50以上だと途中まで完全一致しており、後半はデング熱に対する各所の対応という点では内容が似通っています。Text1とText2の長さが違うのはデータセットの性質なのかよくわかりませんでした。

ヘッドウォータース

Discussion