#freeze [[FrontPage]] #contents 2009/02/01からのアクセス回数 &counter; ** はじめに [#g49145b4] 集合知の3章(一部欠損)を[[Googleのブック検索>http://books.google.com/books?id=-SqPR4iFWD8C&pg=PA49&lpg=PA49&source=web&ots=8u31im4WnN&sig=lp1mG2ZyAGCZ5pGf3EIofR9F8OU&hl=ja&sa=X&oi=book_result&resnum=8&ct=result#PPA31,M1]] から閲覧することができます。 また、なぜか[[原書のPDF>http://1a26.com/pdf/Programming/Programming%20Collective%20Intelligence.pdf]] がアップされています。 オリジナルのソースは、[[原書著者Tobesのページ>http://blog.kiwitobes.com/?p=44]]から[[PCI_Code.zip>http://kiwitobes.com/PCI_Code.zip]]と してダウンロードできます。 ** 日本語の分かち書き [#w2a4133c] ブロガーのフィードの単語を処理するには、日本語の形態素解析を行う必要があり、 まずはchasenを使うことにします。 *** chasenのインストール [#l20a0d93] chasenは、MacPortを使って #pre{{ $ sudo port install chasen }} でインストールしました。 python_chasenで、Shift_JISと想定しているため、/opt/local/etc/chasenrcをchasenrc-Shift_JISの内容で 上書きします。 #pre{{ $ cd /opt/local/etc $ cp chasenrc-Shift_JIS chasenrc }} chasenの起動オプション - chasen -i s を指定します。((Tigerでは、実行結果が文字化けで表示されます)) 動作確認のため、1.txtというファイル(文字コードはShift_JIS)に #pre{{ オリジナルのソースは、原書著者TobesのページからPCI_Code.zipと してダウンロードできます。 }} を入れ、chasenを実行 #pre{{ $ chasen -i s <1.txt >1.out }} とすると1.outには、以下のような出力がでます。 #pre{{ オリジナル オリジナル オリジナル 名詞-一般 の ノ の 助詞-連体化 ソース ソース ソース 名詞-一般 は ハ は 助詞-係助詞 、 、 、 記号-読点 原書 ゲンショ 原書 名詞-一般 著者 チョシャ 著者 名詞-一般 T ティー T 記号-アルファベット o オー o 記号-アルファベット ... 途中省略 ... でき デキ できる 動詞-自立 一段 連用形 ます マス ます 助動詞 特殊・マス 基本形 。 。 。 記号-句点 EOS }} 画面に表示するには、nkfでシステムの文字コードに変換します。 - Leopardでは、UTF-8なので、nkf -w - Tigerでは、Shift_JISなので、nkf -s を指定します。 #pre{{ $ chasen -i s <1.txt | nkf -w }} *** python_chasenのインストール [#fdf57b8d] [[python_chasen-0.2>http://www.domen.cx/yusei/pub/python_chasen-0.2.tar.gz]]を使ってPythonからchasenを使います。ダウンロードして、~/localに展開します。 #pre{{ $ cd local $ tar xzvf python_chasen-0.2.tar.gz $ cd python_chasen }} Tigetでは、-i sオプションが必要なので、chasen.cを変更します。52行を #pre{{ char *opt[] = { "chasen", "-i", "s", NULL}; }} とします。 次に、以下の手順でbuild, installをします。 #pre{{ $ python setup.py build_ext --include-dirs=/opt/local/include --library-dirs=/opt/local/lib/ $ sudo python setup.py install }} *** 分かち書き処理(split.py) [#n69b149a] 準備ができたので、分かち書き処理を行うsplit.pyを作成します。 日本語の処理をスムーズに行うために以下のPythonスクリプトはすべてUTF-8でencodeされたファイルに記述し、先頭に以下のコードを追加します。 #pre{{ # -*- coding: utf-8 -*- import japanese }} japanese.pyは、 #pre{{ import sys import codecs # if you use the jython, comment out next line. sys.stdout = codecs.getwriter('utf_8')(sys.stdout) }} 分かち書き処理では、 - 形容詞、形容動詞、副詞、連体詞、名詞、動詞、未知語 のオリジナル形を単語とするようにします。 split.pyは、以下のようになります。 #pre{{ # -*- coding: utf-8 -*- import japanese import re from chasen import sparse def split(txt): text = sparse(txt.encode('shift_jis', 'replace')).decode('shift_jis', 'replace') ret = [] lines = text.splitlines() parts = [u'^形容詞.*', u'^形容動詞.*', u'^副詞.*', u'^連体詞.*', u'^名詞.*', u'^動詞.*', u'^未知語.*'] for line in lines: words = line.split('\t') if len(words) >= 4: if len(words[2]) > 0: surface = words[2] else: surface = words[0] feature = words[3] for part in parts: pat = re.compile(part) if pat.match(feature): ret.append(surface) return ret # テスト用のコード txt = 'オリジナルのソースは、原書著者TobesのページからPCI_Code.zipと してダウンロードできます。' for word in split(txt): print word }} chasenのsparseに渡すときに、コードをshift_jisにencodeし、戻り値は、shift_jisからdecodeとして処理します。 未知語の場合、オリジナル形がないので、surfaceは単語そのものとしました。 テスト用のコードを実行すると以下の出力がでます。 #pre{{ オリジナル ソース 原書 著者 ページ から する ダウンロード できる }} 英語の単語がすべて消えていることにお気づきでしょうか。 これは、chasenを使った場合の欠点ですが、後述する方法にこの問題を回避しました。 ** フィードを探す [#a8e0a53e] ブログのフィードとして、多岐にわたる有名人のブログを見つけるのに苦労しました。 [[有名人のブログ一覧>http://memoryocean.la.coocan.jp/wiki/blog/index.php]]から有名人の フィードを使わせてもらいました。 *** 単語切りの修正 [#n40cbd18] getwordは、オリジナルのままでは、日本語を処理できないので、以下のように修正しました。 #pre{{ # -*- coding: utf-8 -*- import japanese import feedparser import re from split import split def getwords(html): ret = [] txt=re.compile(r'<[^>]+>').sub('',html) # Split words by all non-alpha characters words=re.compile(r'[^A-Z^a-z]+').split(txt) ret = [word.lower() for word in words if word!=''] txt = re.compile(r'[A-Za-z0-9,;:.!@#$%^&*()+|~/?]+').sub('', txt) return ret + split(txt) }} - 最初に英語の単語のみを切り出し、 - 日本語の単語を切り出したリストを追加 します。 これに、getwordcounts, feedlistの処理、 wordlistの処理を追加し、test_ch3-1.pyとしました。 以下に「フィードの単語を数える」に使用したファイルをリストアップします。 - &ref(japanese.py); - &ref(split.py); - &ref(test_ch3-1.py); - &ref(feedlist.txt); *** フィード中の単語集計結果 [#w1fee934] test_ch3-1.pyの結果には、1カ所問題があります。 原因は定かではありませんが、先頭にフィードタイトルが空文字のページがあるのです。 これを除いたファイルを&ref(blogdata1.txt);として使用します。 ** デンドログラムを描く [#f7576242] 次にデンドログラムを表示する部分ですが、ここも日本語の文字化けが発生しました。 そこで、以下の処理を先頭に追加します。 #pre{{ # -*- coding: utf-8 -*- import japanese from PIL import Image,ImageDraw,ImageFont font = ImageFont.truetype('/Users/take/Library/Fonts/MS Mincho.ttf', 14) }} これで、日本語を処理するfontがセットされますので、drawnodeのテキスト表示を 以下のように修正します。 - PILは、UTF-8の日本語を処理できないので、unicodeに変換します。 - draw.textにfont=fontを渡して呼び出します。 #pre{{ # If this is an endpoint, draw the item label utxt = unicode(labels[clust.id],'utf-8') draw.text((x+5,y-7),utxt,(0,0,0),font=font) }} また、私の環境の問題でjpegで画像を保存できなかったので、PNGで処理するように変更 しました。 最終のソースは、&ref(test_ch3-2.py);です。 *** 描画結果 [#e9de6e31] 作成されたデンドグラムは、以下の通りです。((オリジナルサイズは、blogclust.jpgです。)) &ref(blogclust_small.jpg); 意図したわけではありませんが、お堅いページが &ref(お堅いページ.jpg); とアイドル系のページ &ref(アイドル系.jpg); に別れています。うまくいったのかと思ったら、アイドル系は同じサイトのブログなので、「著作権保護のため、記事の一部のみ表示されております。」が強調されているみたです。残念! ** コメント [#tbf261fc] この記事は、 #vote(おもしろかった[3],そうでもない[0],わかりずらい[0]) #vote(おもしろかった[4],そうでもない[0],わかりずらい[0]) 皆様のご意見、ご希望をお待ちしております。 - chasenの文字コードは、/opt/local/etc/chasenrcで指定することを追記した。 -- [[竹本 浩]] &new{2009-03-25 (水) 17:38:47}; #comment_kcaptcha