MeCabとNLTKを使って最瀕語と共起関係を出力する

MecabとNLTKを使って最瀕語と共起関係を出力するコードを書きました。
Mecabのインストールについては、Windowsなら結構難なく行くようですが、Mac OSX Lionだととても躓きました。
その辺りの経緯は、mecab-pythonをMac OSX 10.7 Lion、Python2.7にインストールする - Men talking over coffee with smoking Ark Royal.を参考にしてください。

まず、このMeCab形態素解析を行うコードですが、以前、『入門ソーシャルデータ』勉強会で、Kenji Koshikawa (Kshi_Kshi)さんに頂いた、mecab_library.pyを元にしています(元のリンクが見つけられませんでした、申し訳ございません)。

mecab_library.py

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

import MeCab

mecab = MeCab.Tagger('-Ochasen')

class Tokens(object):
	"""textの形態素情報を保持"""
	def __init__(self, text):
		self.text = text
		#print mecab.parse(text)
		node = mecab.parseToNode(text)
		self.tokens = []
		while node:
			self.tokens.append(Token(node.surface, *node.feature.split(',')))
			node = node.next


class Token(object):
	"""形態素情報"""
	def __init__(self, surface, *args):
		# Mecab Format
		# 表層形\t品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音
		self.surface = surface	# 表層形
		try:
			self.pos = args[0]	# 品詞
			self.pos_detail1 = args[1]	# 品詞細分類^Z1
			self.pos_detail2 = args[2]	# 品詞細分類^Z2
			self.pos_detail3 = args[3]	# 品詞細分類^Z3
			self.verb_form = args[4]	# 活用形
			self.verb_type = args[5]	# 活用型
			self.basic = args[6]	# 原型
			self.reading = args[7]	# 読み
			self.pronunciation = args[8]	# 発音
			self.type = True # 全ての要素が格納できたとき
		except IndexError:
			self.type = False # 全ての要素が格納できなかったとき

このmecab_library.pyを用いて、tokenize(text, pos_list=["名詞","動詞"])という関数を作りました。ストップワーズは適宜編集してください。
mecab_tokenizer.py

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

import mecab_library
import pickle

# tweets = pickle.load(open("cluster2_tweets.pickle","r"))

def splitStr(str, num):
	l = []
	for i in range(num):
		l.append(str[i::num])
	l = ["".join(i) for i in zip(*l)]
	rem = len(str) % num  # zip で捨てられた余り
	if rem:
		l.append(str[-rem:])
	return l

# pos: 名詞, 動詞, 形容詞, 副詞, 助詞, 接続詞, 助動詞, 連体詞, 感動詞, * 
def classifyPos(words, pos_list=["名詞", "動詞"]):
	
	stop_words = ["@","RT","bit","ly","goo","gl","こと","もの","好き"]
	
	texts = []
	for token in words.tokens:
		if unicode(token.surface, 'utf-8') in stop_words: continue
		elif len(unicode(token.surface, 'utf-8')) == 1: continue # 1文字はスルー
		elif token.pos in pos_list:
			if token.basic == "*":
				texts.append(token.surface)
			else:
				texts.append(token.surface)
	
	return texts

def tokenize(text, pos_list=["名詞","動詞"]):
	sent = text.encode('utf-8')
	if len(sent) > 2000000:
		sents = splitStr(sent, 2000000)
		words = mecab_library.Tokens(sents[0])
		texts = classifyPos(words, pos_list)
		for i in range(1,len(sents)):
			w = mecab_library.Tokens(sents[i])
			texts += classifyPos(w)
			print len(texts)
		return texts
		
	else:
		words = mecab_library.Tokens(sent)
		texts = classifyPos(words)
		return texts

そして、これらを元にNLTKを用いて、最瀕語と共起関係を出力する関数が以下のものです。引数には、unicode型のstrと、閾値頻度を取ります。(共起と最瀕語で閾値を変えたいときは適宜変更してください)

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

import nltk
import mecab_tokenizer

# 共起と最頻語を出力する
def collocations_and_freq_words(text, freq=25):
	tokens = mecab_tokenizer.tokenize(text)
	corpus = nltk.Text(tokens)
	
	print u"-----最頻語(頻度%d回以上)-----" % freq
	
	fdist1 = nltk.FreqDist(tokens)
	saihin1 = fdist1.keys()
	for voc in saihin1:
		if fdist1[voc] >= freq:
			print "%s\t%s" % (voc, fdist1[voc])
	
	print u""
	print u"-----共起関係(共起頻度%d回以上)-----" % freq

	bigrams = nltk.bigrams(corpus)
	cfd = nltk.ConditionalFreqDist(bigrams)
	kyouki = cfd.keys()
	for voc in kouki:
		for (key, value) in list(cfd[voc].viewitems()):
			if value >= freq:
				print "%s\t%s\t%s" % (voc, key, value)

NLTKすごい!ということで。

入門 自然言語処理

入門 自然言語処理