NINのブログ

主に機械学習とか統計モデリングとか金融とか

Python-MeCabでtf-idf法の実装

こんにちは。
今回はMeCab形態素解析をした後に、tf-idf法で文章の特徴語検出をする方法を紹介します。

tf-idf法についてWikipediaより引用します。
tf-idfは、文書中の単語に関する重みの一種であり、主に情報検索や文章要約などの分野で利用される。
tf-idfは、tf(単語の出現頻度)とidf(逆文書頻度)の二つの指標にもとづいて計算される。
f:id:RYNIN:20140804174516p:plain
n_{i,j} は単語iの文書jにおける出現回数、 |D| は総ドキュメント数、|{d: d ∋ ti }|は単語iを含むドキュメント数である。そのため、idfは一種の一般語フィルタとして働き、多くのドキュメントに出現する語(一般的な語)は重要度が下がり、特定のドキュメントにしか出現しない単語の重要度を上げる役割を果たす。

それでは実装します。

#coding:utf-8

import MeCab
import math

sentence = ["えびを食べる","えびがえびを食べる","朝食を食べる"]

num = len(sentence)
result = []

for i in range(num):         #文章の分解
    tagger = MeCab.Tagger()
    result.append(tagger.parse(sentence[i]))


wordCount = {}
allCount = {}
sub_tfstore = {}
tfcounter = {}
tfstore = {}
sub_idf = {}
idfstore = {}
merge_idf = {}
tfidf = {}
merge_tfidf = {}
wordList = []
sum = 0

for i in range(num):
    wordList.append(result[i].split()[:-1:2])    #wordListに分解された単語要素のみを格納

for i in range(num):
    for word in wordList[i]:
        allCount[i] = wordCount.setdefault(word,0)
        wordCount[word]+=1
    allCount[i] = wordCount       #単語出現回数を文章ごとに格納。tfの分母に相当
    wordCount = {}

for i in range(num):                             # tfの分母を計算
    for word in allCount[i]:
        sum = sum + allCount[i][word]
    sub_tfstore[i] = sum
    sum = 0

for i in range(num):                     # tf値を計算し文章ごとに辞書に格納
    for word in allCount[i]:
        tfcounter[word] = allCount[i][word]*1.0/sub_tfstore[i]
    tfstore[i] = tfcounter
    tfcounter = {}

for i in range(num):
    for word in wordList[i]:
        wordCount.setdefault(word,0)
    for word in allCount[i]:
        wordCount[word] += 1
    sub_idf = wordCount                  #ある単語の文章あたりの出現回数を辞書に格納

for i in range(num):
    for word in allCount[i]:
        idfstore[word] = math.log(1.0*math.fabs(num)/math.fabs(sub_idf[word]))
    merge_idf[i] = idfstore
    idfstore = {}

for i in range(num):           #tfidfの計算
    for word in allCount[i]:
        tfidf[word] = tfstore[i][word]*merge_idf[i][word]
    merge_tfidf[i] = tfidf
    tfidf = {}

for i in range(num):          #降順に出力する
    for word,count in sorted(merge_tfidf[i].items(),key = lambda x:x[1],reverse = True):
        print 'text%d: %-16s %2.3f' % (i+1,word,count)
実行結果
text1: えび           0.135
text1: を              0.000
text1: 食べる        0.000
text2: が              0.220
text2: えび           0.162
text2: を              0.000
text2: 食べる        0.000
text3: 朝食           0.366
text3: を              0.000
text3: 食べる        0.000

3つのセンテンスの特徴が捉えられていますね!

Pythonでスクレイピング

今回はPythonスクレイピングをします。
モジュールとしてBeautifulSoupを使いました。
WikipediaPythonの記事からテキストをとりだそうと思います。

#coding:utf-8

import urllib2
from bs4 import BeautifulSoup

u = "http://ja.wikipedia.org/wiki/Python"
opener = urllib2.build_opener()
html = opener.open(u).read()  #htmlの取得
soup = BeautifulSoup(html)
text = soup.findAll("p") #<p>タグを全て取り出す
for sub in text:
    print sub.get_text() #<p>タグ内のテキストのみprintする

BeautifulSoupはとても便利!!

実行結果
■カテゴリ / ■テンプレート
Python(パイソン)は、広く使用されている汎用のスクリプト言語である。コードのリーダビリティが高くなるように言語が設計されていると主張され、その構文のおかげで、Cなどの言語に比べて、より少ないコード行数でプログラムを表現することができる[11][12]と主張されている。小規模なプログラムから大規模なプログラムまで、さまざまなプログラムをクリアに書けるように、多くのコードが提供されている[13]。
Pythonは複数のプログラミングパラダイムをサポートしており、オブジェクト指向、命令型、関数型、手続き型などのスタイルでプログラムを書くことができる。動的型付けである。参照カウントベースの自動メモリ管理(ガベージコレクタ)を持つ。さまざまな領域をカバーする大規模な標準ライブラリを提供している[14]。

以下続く...

このような形で簡単に実装できます!!

引き続き形態素解析

前回に引き続き形態素解析です。
今回は、形態素解析した後に目的の品詞のみ、抽出する方法を紹介します。

#coding:utf-8
import MeCab

sentence = "きのこ帝国とは日本のオルタナティヴ・ロックバンド。"

tagger = MeCab.Tagger()
result = tagger.parse(sentence)

wordList = result.split()[:-1:2]
speechList = result.split()[1:-1:2]

wordDict = {}
for i in range(len(wordList)):
    wordDict[wordList[i]] = speechList[i].rsplit(",")[0]

for word in wordDict:
    if wordDict[word] == "名詞":
        print word

センテンスから名詞のみ抽出するプログラムを書きました。

実行結果
きのこ
帝国
日本
オルタナティヴ・ロックバンド

名詞のみ抽出できました
(「きのこ帝国」のような固有名詞は正しく認識されない場合が多いですが...)


きのこ帝国 - 海と花束 (MV) - YouTube

Pythonで形態素解析

今回はPython形態素解析をする方法を紹介します!
モジュールとしてMeCabを使います。

#coding:utf-8
import MeCab

sentence = "すもももももももものうち" 
tagger = MeCab.Tagger()
result = tagger.parse(sentence)
print result


すもももももももものうち」が正しく分類されるでしょうか?

実行結果
すもも	名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も	助詞,係助詞,*,*,*,*,も,モ,モ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
も	助詞,係助詞,*,*,*,*,も,モ,モ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
の	助詞,連体化,*,*,*,*,の,ノ,ノ
うち	名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS

正しく分類されました…!!
形態素解析アルゴリズムとして最も有効なのは隠れマルコフモデルらしいです。

#coding:utf-8
import MeCab

sentence = "すもももももももものうち"

tagger = MeCab.Tagger()
result = tagger.parse(sentence)

wordCount = {}
wordList = result.split()[:-1:2]
for word in wordList:
    wordCount.setdefault(word,0)
    wordCount[word]+=1

for word,count in wordCount.items():
    print '%-16s %i' % (word, count)

単語の出力回数をまとめました。

実行結果
も              2
もも           2
の              1
すもも        1
うち           1