棚からパルチャギ

日々の雑記、ニュース拾いとか

2008. 02. 18

PHPでベイジアンフィルタ (実践編)
実践編です。
ベイジアンフィルタを使ったアプリケ-ションの流れは、大きく分けて以下の3段階になります。
  • カテゴリ(クラス)定義
  • パターン学習
  • 文書分類
単純ベイズ分類器(Naive Bayes classifier)ではクラス毎に単語の出現頻度を記憶して、その情報をもとに文書がそれぞれのクラスに属する確率を求めます。 SPAMフィルタなどでは「spam」と「nospam」のように2つのクラスだけで使用されることが多いです。多分。

パターン学習は、特定の文書(単語のセット)がどのクラスに所属するかを指定します。 これにより出現頻度のデータベース(コーパス)が更新されて、次回以降の分類精度を向上させることができます。 通常は、クラスを最初に設定して、以降は学習と分類を繰り返すような感じになると思います。


…ということで、クラスの定義から。
何故かNaiveBayesianStorageには、カテゴリ操作のインターフェースが提供されていないので、手作業で行います。 addCategory()とかdeleteCategory()とか追加してあげると便利なんですが。
mysql> insert into nb_categories (category_id) VALUES ('spam'); mysql> insert into nb_categories (category_id) VALUES ('nospam');


とりあえず一般的な例で、メールの文章を適当に登録してSPAM判定が行えるかどうか試してみます。 クラス毎にパターンを覚えさせる必要があるので、ここではSPAMメールの文章と、普通のメールの文章を各10件ずつ用意して登録します。 NaiveBayesian::train()で登録させるので、登録用のPHPスクリプトなんかを適当に。
$login = 'username'; // MySQL user $pass = 'password'; // MySQL password $db = 'nb'; $server = 'localhost'; include_once 'class.naivebayesian.php'; include_once 'class.naivebayesianstorage.php'; include_once 'class.mysql.php'; include_once 'class.naivebayesian_jp.php'; // NaiveBayesianJP $nbs = new NaiveBayesianStorage($login, $pass, $server, $db); $nb = new NaiveBayesianJP($nbs); $pattern_spam = array( '25歳人妻です旦那との夜の生活が3ヶ月に一度です。新婚の頃は…', '現在、当サイトにご登録されている女性会員様(約48万人)の…', '業界各方面から多大なる絶賛を得ています。過去には無かった体験が…', '人妻が大好き!または人妻に興味がある!という方だけ…', '私は市内の某私立高校に通う女子高生です。実は先日39歳になる母が…', ... ); foreach ($spams as $idx => $doc) { $cat = 'spam'; $docid = $cat .'_'. $idx; if ($nb->train($docid, $cat, $doc)) { $nb->updateProbabilities(); } } // 普通のメールの登録も同様に
NaiveBayesian::train() の $docid には文書に付ける一意のID(登録済みのIDと重複しなければなんでもいいです)を指定します。 $cat にはカテゴリ名、$docには文書を渡します。単語の抽出は自動的に行われます。


で、メインであるところの文書分類。
判定したい文章を渡して NaiveBayesian::categorize() すると各クラスに所属する確率が返る…はず。
$nbs = new NaiveBayesianStorage($login, $pass, $server, $db); $nb = new NaiveBayesianJP($nbs); $text = 'ドスケベな男女に朗報です△今すぐにエッチがしたい!近所で…'; $scores = $nb->categorize($text); while(list($cat,$score) = each($scores)) { echo "$cat : $score\n"; }
出力結果。ちゃんとSPAM判定してくれている模様。
ここで結果が間違っている場合は、上と同じやり方で NaiveBayesian::train() を使って学習させます。
spam : 0.99946305424632 nospam : 0.032765884645883


SPAMフィルタの場合は分類失敗よりも誤検出のほうが被害が大きいので、このときの確率が0.90以上の場合のみSPAM判定するみたいな分類をしたほうがいいかもしれません。 カテゴリが複数存在する場合は、一番確率が高いものを選択すれば良いと思います。


といった感じで、比較的簡単にベイジアンフィルタが使えそうな感じではあるんですが、たまに確率が1.0を超えたりする場合があって微妙に謎です。 どこかでやり方間違えてるのかなー。
spam : 6.1633758754325E-10 nospam : 1
こんなのとか、こんなのとか。
spam : 1 nospam : 9.547379900121E-13

学習パターン数が少ないと発生しやすいみたいなので、それなりのパターンを登録してあげる必要があるかもしれないですね。 とりあえず10件や20件では全然少ないので、1000件くらいのパターンは欲しいかも。
PHPでベイジアンフィルタ (準備編)
先日のデブサミ2008で、モバゲータウン(DeNA)が悪質な書き込みなんかを形態素解析+ベイジアンフィルタで抽出しているという話をしていたので、 SPAMフィルタ以外にも結構汎用的な文書分類に使えるものかと思い立ったので、ちょと調査。

単純ベイズ分類器と小一時間にらめっこした結果、スポンジ化した脳では理解するのに相当な時間を要すると判断したのでライブラリに頼ってみます。 仕事でも使えるようにとPHPで使えるものを探してみたんですが、これ(↓)しか見つかりませんでした。 CPANのAlgorithm::NaiveBayesを参考に作られたっぽいですね。

…とりあえず、日本語対応。
ライブラリ内に字句解析の処理があるんですが、英文字しか対応していないので日本語は通りません。 MeCabとかを使って単語抽出してあげる必要があるんですが、今回はYahoo!の日本語形態素解析サービスで誤魔化してみました。

PHP4なのをいいことに、NaiveBayesianのサブクラスとして_getTokens()をオーバーライド。 このメソッドで、キーが単語、値が出現回数の連想配列を返せばいいので、助詞・助動詞を除いた単語群を取得して配列にいれてあげます。 あと、日本語だと2文字の単語も多いので $min_token_length は 2 に変更。

$yahoo_appid は各自、Yahoo!で取得したアプリケーションIDを設定します。
class NaiveBayesianJP extends NaiveBayesian { var $min_token_length = 2; var $yahoo_maservice = 'http://api.jlp.yahoo.co.jp/MAService/V1/parse'; var $yahoo_appid = 'xxxxxx'; function _getTokens($string) { $tokens = array(); $result = $this->_yahooMA($string); if ($result && ($xml = simplexml_load_string($result))) { foreach ($xml->uniq_result->word_list->word as $word) { $token = (string)$word->surface; if ((mb_strlen($token) >= $this->min_token_length) && (mb_strlen($token) <= $this->max_token_length)) { $tokens[$token] = (int)$word->count; } } } return $tokens; } function _yahooMA($string) { $params = array( 'appid' => $this->yahoo_appid, 'sentence' => urlencode($string), 'results' => 'uniq', 'response' => 'surface', 'filter' => '1|2|3|4|5|6|7|8|9|10', ); $query_string = ''; foreach ($params as $key => $value) { $query_string .= ($query_string)? '&' : '?'; $query_string .= $key .'='. $value; } return file_get_contents($this->yahoo_maservice . $query_string); } }


あとは、データベースの準備。
デフォルトではMySQLの使用が前提なので、あらかじめインストールするなりして用意します。。 適当な名前でデータベースを作成して、ライブラリ同梱のmysql.sqlを実行。 元のデータベース名が「nb」なので、ここでも同じ名前にしておきます。
mysql> create database nb character set utf8 collate utf8_unicode_ci; mysql> use nb; mysql> source ~/phpnaivebayesian/mysql.sql;

ちなみにデータベースのエンコードをUTF-8にした場合、インデックスのキーサイズが1000bytesを超えてしまうので、以下のようなエラーが発生します。 すみません、先に言えよって感じですね。UTF-8だと1文字3bytes相当で計算するので mysql.sql 内の定義をすべて varchar(250) → varchar(160) くらいにすれば無問題です。
#1071 - Specified key was too long; max key length is 1000 bytes

続きます。
JavaScriptで「SL」
まさかブラウザ上でもこれが見られるなんてw

最近見てないけど、前の会社では開発鯖に仕込まれていたので、数か月に一度くらいはタイピングミスで走らせてしまってました。 「ls」のオプションによって、車両の数とか速度とかが変わった気がしますね。 JavaScriptでF5禁止だの右クリック禁止だのしているサイトも、このくらいユーモアがあればいいんですけどねー。(SL発車!)
ライフハック(笑)じゃなくて
非コミュとかウケミンとか今更どうこうできるようなものでもない気がするけど、 ライフハックとかじゃなくてもっと人生観とか生き方とかをドラスティックに変えるような何かはないかなあ。 このままだと、余命1ヶ月とか言われても、前日までくだらない生活を続けてしまいそうな気がする。
今日の浪費
狼と香辛料〈7〉Side Colors (電撃文庫)
なんというか、この作品の9割はホロの魅力だけで成り立ってると実感させられるようなニヤニヤ短編集。 本編では旅の道連れも増えてこういう掛け合いが少なくなりそうなのは、微妙に残念な感じです。 アニメ版は好評みたいだけど、ずるずると引き延ばしたりしないで綺麗に終わってくれるといいなあ。
ところで、先月発売の新刊は、アニメ放映開始の1月まで引っ張ればよかったのにと思っていたけど、ちゃんと用意してあったあたりは商売上手。


かんなぎ (4) (REX COMICS)
海イベントにスク水幼女とはなんというテコ入れ。 こちらもアニメ化発表てことで、スタッフ見る感じでは少し期待してもよさそうなんですが、 「ペンギン娘」といい手当たりしだいアニメ化している感が拭えない。。。今更かも。

ライトノベルは最近続きものしか買っていなかったけど、今月発売の新人作家作品は結構好評なのが多いですねー。 あと、『ミミズクと夜の王』を書いた紅玉いづき氏の新刊も出ているっぽいので、1作目が結構衝撃的だっただけに、どんな作品なのか楽しみです。 とりあえず、いろいろ買うのはあと1週間我慢…。

2008. 02. 12

NBonline
何故だか頻繁に再ログインを要求する上に、毎回会員情報の登録を経由するという頭のおかしい画面遷移に定評のあるNBonline(日経ビジネスオンライン)なんですが、 いい加減なんとかならないのかと思ってFAQを覗いてみたら…

Q. NBonlineのサイトを見るときの推奨ブラウザは

A. ご利用のパソコンのOSに合わせて、次の各ブラウザのバージョンをご利用の上ご覧ください

<Windows>
Internet Explorer 6.x、FireFox(Mozila)1.x
<Mac>
FireFox(Mozila)1.x、Safari 1.x

なるほど、Firefox 2.xは非推奨だったのかっ。

…というか、各ブラウザともに次のバージョンが控えているので、そろそろ更新してあげてください。 あと、FireFoxという表記は間違いとか小姑っぽく突っ込もうかと思ったけど、原文のFAQからは削除されてるんですね。 そんなことは別に構わないんですが、結局再ログインをなんとかする方法はないみたいです。。。
DoCoMoの割引プラン
今更なんですが、基本使用料半額って新規契約者のみの特典だと思ってたら、継続利用者でも適用できるんですね。 一応、ファミリー割引に入っているのでファミ割★MAX50というやつみたいなんですけど、比較表を見てみると得なのかそうでないのか微妙になってきました。

現在の料金プランはタイプSSで基本使用料は3,780円/月。 メールやネットには別途パケホーダイ(割引対象外)に加入しているので、まず基本使用料を超えることはないです。 継続利用は8年目になるので現在の割引率は47%。 普通に考えれば割引率50%のほうが得なんですが、これって2年間契約必須で、途中解約の場合は期間によらず9,975円の解約金が発生するんですね。 現在の割引プランのまま2年間経過した場合の差額は…
8年目: 3,780 * (0.50 - 0.47) * 12 = 1,368
9年目: 3,780 * (0.50 - 0.48) * 12 = 912
合計で2,280円になります。 割引率50%で2年間解約できない制約を考えると、この差額は保険として支払ってもいいのではないかと思うのです。 DoCoMoは新機種もサービスもいまいちパッとしないし、継続利用の特典が事実上なくなっている以上、他キャリアに乗り換えるのもありなのかなーとか。

そんなわけで、割引プランの変更は保留にしました。 当面乗り換えの予定はないですけど、2年以内には携帯業界にもいろいろと大きな動きがきそうな気もするので。 端末としては、WILLCOMのXPLATEみたいなコンパクトな形状で、ブラウザとカメラとBluetooth搭載だったら完璧なんですが、どこか発売してくれないでしょうか。
最近の浪費
嘘つきみーくんと壊れたまーちゃん 3 死の礎は生 (電撃文庫 い 9-3)
今読んでます。 p.182の「借金による地下暮らしのススメ」はカイジな気がするけど、「多重人格になった場合、如何にして手に職をつけるかの入門本」って元ネタなんだろう…。

少女には向かない職業 (創元推理文庫)
文庫化されていたので。 桜庭一樹は他に「推定少女」と「砂糖菓子の弾丸は撃ちぬけない」しか読んでいないんですが、砂糖菓子のほうは結構印象深かったけど、いまだに評価をしかねる難しい作家さんですね。 読んでいるときは特に違和感はないんですが、読後がいつも微妙な感じ。 とりあえず文庫待たないで「赤朽葉家の伝説」読むかなー。

永遠の存在者
発売は結構前だけど、pigstarのアルバム。 ピリオド主題歌のために買ったけど、他の曲も良作揃いでした。 来期はアニメのOPも歌うみたいだし、彼らはもっと評価されるべき。

2008. 02. 11

Linuxカーネル2.6系にroot権限を奪われる脆弱性
おお…これは危険すぎる。
自宅のFedora 8で試してみたけど、普通にexploitコードでrootになれますね。 外部から攻撃される類のものではないとはいえ、社内サーバでもレンタルサーバでも、シェルログインを許可しているところだと誰に何されるか分かりません。 カーネルリビルドとか運用環境で絶対やりたくないんですけど…。そもそもvmsplice()って無効にしてもいいんでしょうか???
最近の無限ループ
ミンサガやったことないけど、異常にツボに入ったので連休中ずっと無限ループしてました。

もともとは、MEIKOの調整っぷりが素晴らしい【MEIKO】熱情の律動【ミンサガ】を聴いたのがきっかけだったんですが、この曲はヤバイ。 自分の場合、普段から音楽はあまり聴かないほうなんですが、気に入ったものがあると同じ曲を平気で1週間とか聴いてしまったりすることが多いので、もうイヤホンしたまま寝ながらも聴いてましたw

この曲CD欲しいけど、サントラよりも廉価版のゲーム(本編)のほうが安いのでちょっと迷いますね。
雑記
会社変わると更新止まるというのは、前回と同じパターンな気がしてきた。 なんとなく生活のリズムが整うまでとか思ってたら、ずるずると何もしなくなってしまうので、今年はちゃんと生きます。 とりあえずRuby覚えます。

転職して3週間ばかし。ようやく慣れて落ち着いてきた感じです。 新しい会社は職場環境とか勤務形態とか通勤時間とかいろいろと快適なんですが、 自分よりも若くてスキルのあるエンジニアが多いので、いい刺激になりますね。

新生活の唯一の不満は、通勤経路上に大型書店がなくなってしまったこと。 毎日帰り際にふらりと寄っては新刊チェックしたり技術書を物色したりする、あの楽しみがなくなってしまったのは寂しいです。 ただでさえ最近は経済的な理由で買い控えているから、月末になったら数か月分の衝動を解き放つ勢いで散財したいですねー。 (まともにという意味では)約半年ぶりの給料日まであと2週間!まだ結構あるっ><
最近の浪費
わたしたちの田村くん 3 (電撃コミックス)」。
次巻完結っていろいろ未消化だなーと思ったら、ガオ休刊なんですね。 漫画版は作家買いしてみたけど、原作読むほどかと思うと微妙に悩みます。 同じ作者なら「とらドラ!」のほうが評判いいから、そっちからかなあ。 それにしても、中古価格の暴落が酷過ぎる

GA 芸術科アートデザインクラス (2) (まんがタイムKRコミックス)」。
絵を見て思い出したけど、DS買ったら『ユグドラ・ユニオン』やるつもりだったのに無期限で本体を貸してしまったですよ。 こないだ新キャラとか追加のPSP版が発売されたみたいだから、そっちを買うべきなのか。