2011/07/15からのアクセス回数 5119
ここで紹介したSageワークシートは、以下のURLからダウンロードできます。
http://www15191ue.sakura.ne.jp:8000/home/pub/18/
また、Sageのサーバを公開しているサイト(http://www.sagenb.org/, http://www15191ue.sakura.ne.jp:8000/)にユーザIDを作成することで、ダウンロードしたワークシートを アップロードし、実行したり、変更していろいろ動きを試すことができます。
この企画は、雑誌や教科書にでているグラフをSageで再現し、 グラフの意味を理解すると共にSageの使い方をマスターすることを目的としています。
今回は、 集合知プログラミング の第3章にできてきます似たブログをグルーピイングした図3.3「ブログのクラスタのデンドログラム」 を取り上げます。
sageへの入力:
attach(DATA+'RUtil.py')
以前chasenを使って同じグラフの表示を行った
a href="http://www.pwv.co.jp/~take/TakeWiki/index.php?python%2F%E9%9B%86%E5%90%88%E7%9F%A53%E7%AB%A0">python/集合知3章</a> では、chasenが英語の単語を扱えないため、トリッキーな処理を行いましたが、 MeCabではそのまま英語の単語が扱えるので、すっきりした形になります。
MeCabのインストール方法については、 MeCab を参照してください。
日本語のテキストから分かち書きの単語の内、partsに指定した形容詞、形容動詞、副詞、連体詞、名詞、動詞、未知語を 日本語の単語として抽出することにしました。また、minlenより小さな単語は取り除くようにしました。
pythonようのMeCabは、Taggerメソッドで生成し、parseメソッドで解析するというのが通常ですが、 ここでは単語の品詞と動詞の原形を使用したいので、parseToNodeメソッドでノードに分割した結果を 使って単語抽出を行いました。
sageへの入力:
import sys
import MeCab
import re
# splitの定義
def split(txt, minlen=2):
m = MeCab.Tagger ("-Ochasen")
n = m.parseToNode(txt)
parts = ['^形容詞.*', '^形容動詞.*', '^副詞.*', '^連体詞.*', '^名詞.*', '^動詞.*', '^未知語.*']
ret = []
n = n.next
while n.next != None:
features = n.feature.split(',')
if len(features) > 7:
surface = features[6]
else:
surface = n.surface
feature = features[0]
n = n.next
if len(surface) >= minlen:
for part in parts:
pat = re.compile(part)
if pat.match(str(feature)):
#print surface, feature
ret.append(surface)
return ret
まずは、簡単なテキストを入力して正しく単語が抽出できているか確認してみます。
splitの結果は、単語で区切られた文字列のリストを返すのですが、そのままだと \xnnの形式で表示されてしまうので、1単語ずつ表示してみました。
sageへの入力:
# テスト用のコード
txt = 'オリジナルのソースは、原書著者TobesのページからPCI_Code.zipと してダウンロードできます。'
#print split(txt)
for s in split(txt):
print s
オリジナル ソース 原書 著者 Tobes ページ PCI Code zip する ダウンロード できる
Sageはそのままではunicodeから文字列への変換でエラーが発生します。
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-10: ordinal not in range(128)
これに対する対応としては、Sageのpythonのsite-packagesにsitecustomize.pyを以下のように 作成します。私の場合には、/usr/local/sage/local/lib/python/site-packages/に配置しました。
import sys
sys.setdefaultencoding('utf-8')
配置が完了したら、sageを再起動してください。
splitができたので、htmlから単語のリストを返す getwordsはHTMLからタグをのぞいてsplitを呼び出すだけの処理となります。
sageへの入力:
# 日本語対応のgetwordsのプロトタイプ版
def getwords(html):
ret = []
txt=re.compile(r'<[^>]+>').sub('',html)
return split(txt)
フィードリストは、ワークシートのdataに含まれていますので、 ワークシートの上部のDataプルダウンからfeedlist.txtを選択して 編集することができます。
Sageのワークシートは実行可能なドキュメントですので、 自分の興味のあるブログリストをfeedlistにセットしてその結果を表示することが できます。
sageへの入力:
# 使用するフィードリスト
# printFile("feedlist.txt")
Sageのpythonのデフォルト言語がasciiであるため、そのままでは 日本語のテキストを処理しようとするとエラーになります。
getwords関数を呼び出している部分でstr関数を使ってunicodeを 文字列に変換しています。
sageへの入力:
import feedparser
# strを使ってunicodeから文字列に変換するように修正(Hiroshi TAKEMOTO)
# Returns title and dictionary of word counts for an RSS feed
def getwordcounts(url):
# Parse the feed
d=feedparser.parse(url)
wc={}
# Loop over all the entries
for e in d.entries:
if 'summary' in e:
summary=e.summary
else:
summary=e.description
# Extract a list of words
words=getwords(str(e.title+' '+summary))
for word in words:
wc.setdefault(word,0)
wc[word]+=1
return str(d.feed.title),wc
PILライブラリは、そのままでは日本語を表示できませんが、 ImageFontに日本語のTrueタイプフォントを指定することで 文字化けなしに表示できるようになります。
また、日本語を表示する部分では、unicodeに変換してからtextメソッド に渡す必要があります。
utxt = unicode(labels[clust.id],'utf-8')
draw.text((x+5,y-7),utxt,(0,0,0),font=font)
sageへの入力:
# デンドログラムで日本語を表示するためのトリック
from PIL import Image,ImageDraw,ImageFont
font = ImageFont.truetype('/usr/local/share/Fonts/MS Mincho.ttf', 14)
集合知3章の例題の通り、feedlist.txtに指定されたブログから 単語を抽出してみます。
sageへの入力:
# feedlistにあるブログの単語を抽出し、出現一覧を作成する
apcount={}
wordcounts={}
feedlist=[line for line in file(DATA+'feedlist.txt')]
for feedurl in feedlist:
try:
title,wc=getwordcounts(feedurl)
wordcounts[title]=wc
for word,count in wc.items():
apcount.setdefault(word,0)
if count>1:
apcount[word]+=1
except:
print 'Failed to parse feed %s' % feedurl
wordlist=[]
for w,bc in apcount.items():
frac=float(bc)/len(feedlist)
if frac>0.1 and frac<0.5:
wordlist.append(str(w))
wordlistにはすべてのブログに出現した単語のリストが入っているため、 各ブログの単語の出現頻度を計算する場合、ブログに指定単語が含まれる かをチェックする必要があります。_word関数を以下のように定義して クラスタ分析に渡す、出現頻度マトリックスの作成します。
sageへの入力:
def _word(word, wc):
if word in wc:
return wc[word]
else:
return 0
sageへの入力:
# クラスタ分析用に収集したワードカウントを加工 blognames = [blog for blog,wc in wordcounts.items()] words = wordlist data = [[_word(word, wc) for word in wordlist] for blog,wc in wordcounts.items()]
単語の出現頻度マトリックスdataをhcluster関数に渡してブログのクラスタ分析をします。
その結果をdrawdegrogram関数に渡してデンドログラムを表示します(blogclust.pngにも保存します)。
アメブロの芸能人のブログが固まっていたり、ちょっとお固そうなブログが集まっていたりとそれらしい分類が されているのが見て取れます。
sageへの入力:
attach(DATA+'clusters.py')
sageへの入力:
# ブログのクラスタリング
clust=hcluster(data)
#printclust(clust,labels=blognames)
drawdendrogram(clust,blognames,png=DATA + 'blogclust.png')
showPNG('blogclust.png')
皆様のご意見、ご希望をお待ちしております。