Pythonでいろいろやってみる

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

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

文章の類似度を調べる方法の一つ、N-gramを用いて2つの文章の類似度を調べます。N-gramは「隣り合う連続したN文字」の意味で、2文字なら2-gram、3文字なら3-gramとなります。
例えば2-gramは次のように作成します。

【元の文章】群馬県でマイクロバスが崖下に

【2-gram化】'群馬' '馬県' '県で' 'でマ' 'マイ' 'イク' 'クロ' 'ロバ' 'バス' 'スが' 'が崖' '崖下' '下に'

ある文章のN-gramを作成し、別の文章のN-gramに何回出現するかカウントすることで類似度を算出します。
同じニュースに関する記事の類似度、無関係なニュースについての記事の類似度を2-gramで調べます。

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.7.0
準備

以下の3つのニュース本文をコピーし、それぞれ別のテキストファイルとしてNgramフォルダに保存しました。

群馬 マイクロバス転落(TBS NEWS)→text1.txt

群馬県でマイクロバスが崖下に転落した事故で、バスを運転していた男が無許可で運送事業を行っていた可能性のあることがわかりました。この事故は、10日、群馬県南牧村でマイクロバスが突然動き出して崖から転落し、登山客12人が重軽傷を負ったもので、警察は、バスを運転していた海老原功容疑者(66)を逮捕し、12日朝、送検しました。その後の捜査関係者への取材で、バスが運送事業の許可を受けたものではないとみられることがわかりました。海老原容疑者は、登山客の依頼を受けて自分の会社のレンタル用のバスを運転していたということで、警察は、道路運送法違反の可能性もあるとみて、登山客との間で運賃などのやり取りがなかったか調べています。

無許可で客を…白バスか 南牧村バス転落(Livedoor News)→text2.txt

10日、群馬県南牧村で、登山客を乗せたマイクロバスがガケ下に転落し、12人が重軽傷を負った事故で、このバスが無許可で客を乗せるいわゆる「白バス」だった疑いがあることが分かった。この事故は10日、南牧村で、登山客15人を乗せたマイクロバスがガケ下の林に転落し、12人が重軽傷を負ったもの。バスを運転していた海老原功容疑者は業務上過失致傷の疑いで逮捕され、12日、身柄を検察庁に送られた。また、その後の捜査関係者への取材で、このバスが、許可を受けずに料金を受け取って客を乗せるいわゆる「白バス」だった疑いがあることが分かった。警察は11日、海老原容疑者の会社に家宅捜索に入っていて、道路運送法違反の疑いもあるとみて捜査している。

オードリー春日が大安入籍 ラジオ生放送前に2人で婚姻届を提出(Livedoor News)→text3.txt

お笑いコンビ・オードリーの春日俊彰(40)が12日未明、婚約中だった同じ年のドッグカフェ店員・クミさんと入籍した。大安だったことから12日を選んだといい、午前1時からのラジオ生出演の前に、2人で婚姻届を提出。春日は4月18日放送のテレビ番組で、11年前から交際していたクミさんに公開プロポーズをしたが、その直後、写真週刊誌でスキャンダルを報じられていた。波瀾(はらん)万丈の末に夫婦となって、「盛大に求婚させてもらい、世界中に祝福されたにもかかわらず、お騒がせしてしまいましたが、幾千億の『クーちゃん、ごめんね。』と周りの良き人々のおかげさまで、このようなお慶びを迎えられた事に感謝。最高にトゥースな家庭を築く所存」と反省を込めて報告した。

コード

test1.txtとtest2.txtの類似度を2-gramで調べます。

filename1='Ngram/text1.txt'
filename2='Ngram/text2.txt'

#filename1を開きtext1に代入
with open(filename1,mode='r',encoding = 'utf-8-sig') as f:
    text1 = f.read()

#text1を2文字ずつ区切ってリスト化(2-gramの生成)
text1_list =[]
for i in range(len(text1)-1):
   text1_list.append(text1[i:i+2]) 

#filename2を開きtext2に代入
with open(filename2,mode='r',encoding = 'utf-8-sig') as f:
    text2 = f.read()

#text2を2文字ずつ区切ってリスト化(2-gramの生成)
text2_list =[]
for i in range(len(text2)-1):
   text2_list.append(text2[i:i+2]) 

#text1の2-gramをtest2の2-gramと総当たりでチェック
total_check_count = 0
equal_count = 0
for text1_word in text1_list:
    total_check_count = total_check_count+1
    equal_flag = 0
    for text2_word in text2_list:
        if text1_word == text2_word:
            equal_flag = 1
    equal_count = equal_count+equal_flag

#結果の表示
print('一致した単語数  :',equal_count)
print('チェックした単語数:',total_check_count)
print('一致率(類似度)      :',equal_count/total_check_count)
実行結果

58%の2-gramが一致しています。

一致した単語数  : 178
チェックした単語数: 306
一致率(類似度)   : 0.5816993464052288


コード

text1.txtとtext3.txtの類似度を2-gramで調べます。 falename2をtext2.txtからtext3.txtに変更するだけです。

filename2='Ngram/text3.txt'
実行結果

無関係な記事を比べているため一致率は16%と低くなります。

一致した単語数  : 48
チェックした単語数: 306
一致率(類似度)   : 0.1568627450980392

参考文献

クジラ飛行机 「Pythonによるスクレイピング&機械学習 開発テクニック」(ソシム株式会社)

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

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