nltk.NaiveBayesClassifier を用いた文書分類

"nltk.NaiveBayesClassifier mecab" をキーワードに Google 検索しても出てくる件数が少ないから,自分で作ってみた。

# -*- coding: utf-8 -*-

#学習サンプルおよびテストサンプルは以下のページに掲載されていたのを拝借した。
#  機械学習 はじめよう 第3回 ベイジアンフィルタを実装してみよう
#  http://gihyo.jp/dev/serial/01/machine-learning/0003

import MeCab
import nltk

rawTrainingDocuments = [('Python(パイソン)は,オランダ人のグイド・ヴァンロッサムが作ったオープンソースのプログラミング言語。オブジェクト指向スクリプト言語の一種であり,Perlとともに欧米で広く普及している。イギリスのテレビ局 BBC が製作したコメディ番組『空飛ぶモンティパイソン』にちなんで名付けられた。Python は英語で爬虫類のニシキヘビの意味で,Python言語のマスコットやアイコンとして使われることがある。Pythonは汎用の高水準言語である。プログラマの生産性とコードの信頼性を重視して設計されており,核となるシンタックスおよびセマンティクスは必要最小限に抑えられている反面,利便性の高い大規模な標準ライブラリを備えている。Unicode による文字列操作をサポートしており,日本語処理も標準で可能である。多くのプラットフォームをサポートしており(動作するプラットフォーム),また,豊富なドキュメント,豊富なライブラリがあることから,産業界でも利用が増えつつある。','Python'),
                ('Ruby(ルビー)は,まつもとゆきひろ(通称Matz)により開発されたオブジェクト指向スクリプト言語であり,従来 Perlなどのスクリプト言語が用いられてきた領域でのオブジェクト指向プログラミングを実現する。Rubyは当初1993年2月24日に生まれ, 1995年12月にfj上で発表された。名称のRubyは,プログラミング言語Perlが6月の誕生石であるPearl(真珠)と同じ発音をすることから,まつもとの同僚の誕生石(7月)のルビーを取って名付けられた。','Ruby'),
                ('豊富な機械学習(きかいがくしゅう,Machine learning)とは,人工知能における研究課題の一つで,人間が自然に行っている学習能力と同様の機能をコンピュータで実現させるための技術・手法のことである。ある程度の数のサンプルデータ集合を対象に解析を行い,そのデータから有用な規則,ルール,知識表現,判断基準などを抽出する。データ集合を解析するため,統計学との関連も非常に深い。機械学習は検索エンジン,医療診断,スパムメールの検出,金融市場の予測,DNA配列の分類,音声認識や文字認識などのパターン認識,ゲーム戦略,ロボット,など幅広い分野で用いられている。応用分野の特性に応じて学習手法も適切に選択する必要があり,様々な手法が提案されている。それらの手法は, Machine Learning や IEEE Transactions on Pattern Analysis and Machine Intelligence などの学術雑誌などで発表されることが多い。','機械学習')]

mecab = MeCab.Tagger('-Ochasen')

#形態素解析
def morph(document):
    pos = ['形容詞', '形容動詞','感動詞','副詞','連体詞','名詞','動詞']
    words = []
    node = mecab.parseToNode(document)
    while node:
        fs = node.feature.split(",")
        if fs[0] in pos:
            word = (fs[6] != '*' and fs[6] or node.surface)
            words.append(word)
        node = node.next
    return words

# 特徴抽出:引数は「語のリスト」
def extract_features(document):
    documentwords = set(document)
    return dict([('contains(%s)' % word, True) for word in documentwords])

#学習用文書の形態素解析
trainingDocuments = []
for (doc, label) in rawTrainingDocuments:
    words = morph(doc)
    trainingDocuments.append((words,label))
            
# 文書集合に含まれる全ての語を(重複ありで)リストアップ
allWords = []
for (words,label) in trainingDocuments:
    allWords.extend(words)

#文書集合に含まれる異なり語をリストアップ
wordList = nltk.FreqDist(allWords)
keys = wordList.keys()

#学習
trainSet = nltk.classify.apply_features(extract_features, trainingDocuments)
classifier = nltk.NaiveBayesClassifier.train(trainSet)

rawTestDocuments = ['オランダ人のヴァンロッサム氏によって開発されました.', #Python
                    '豊富なドキュメントや豊富なライブラリがあります.', #Python
                    '純粋なオブジェクト指向言語です.', #Ruby
                    'Rubyはまつもとゆきひろ氏(通称Matz)により開発されました.', #Ruby
                    '「機械学習 はじめよう」が始まりました.', #機械学習
                    '検索エンジンや画像認識に利用されています.'] #機械学習

#分類
for testDoc in rawTestDocuments:
    doc = morph(testDoc)
    print classifier.classify(extract_features(doc))

#各クラスへの帰属確率
for testDoc in rawTestDocuments:
    doc = morph(testDoc)
    probs = classifier.prob_classify(extract_features(doc))
    for label in classifier.labels():
        print "%s : %f\t" % (label, probs.prob(label)),
    print

実行結果は以下のとおり:

Python
Python
Ruby
Ruby
機械学習
機械学習
Python : 0.692308	Ruby : 0.230769	機械学習 : 0.076923	
Python : 0.890110	Ruby : 0.010989	機械学習 : 0.098901	
Python : 0.490909	Ruby : 0.490909	機械学習 : 0.018182	
Python : 0.000457	Ruby : 0.999086	機械学習 : 0.000457	
Python : 0.090909	Ruby : 0.090909	機械学習 : 0.818182	
Python : 0.098901	Ruby : 0.010989	機械学習 : 0.890110