Python-MeCabでtf-idf法の実装
こんにちは。
今回はMeCabで形態素解析をした後に、tf-idf法で文章の特徴語検出をする方法を紹介します。
tf-idf法についてWikipediaより引用します。
tf-idfは、文書中の単語に関する重みの一種であり、主に情報検索や文章要約などの分野で利用される。
tf-idfは、tf(単語の出現頻度)とidf(逆文書頻度)の二つの指標にもとづいて計算される。
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を使いました。
WikipediaのPythonの記事からテキストをとりだそうと思います。
#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
センテンスから名詞のみ抽出するプログラムを書きました。
実行結果 きのこ 帝国 日本 オルタナティヴ・ロックバンド
名詞のみ抽出できました
(「きのこ帝国」のような固有名詞は正しく認識されない場合が多いですが...)
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