- 2004/12/31-01:
-
Mozillaのハックにはまる。
Thunderbirdのベイジアンフィルタの日本語メールに対する精度が悪いのはなんでかいな、
と調べてみたら、なんと漢字を1文字ごとに分解しているではないか。
そりゃあ悪いわけだ。
せめて単語ごとに分けるぐらいのことはしないと。
- 2005/01/02-03:
-
Thunderbirdと形態素解析プログラムKAKASIとの融合を試みる。
成功したが、なんだかイマイチ感が漂う。
辞書がないとどうしようもないし、辞書に載っていない単語を学習するわけでもない。
ビルドに失敗しまくって発狂しそうになる。
部分再構築の方法もよくわからん。
KAKASI融合版の使い方:
- パッチを当ててビルドする
- Win32用バイナリパッケージのKAKASI(kakasi-2.3.4.zip)をダウンロードして展開する
- libのkakasi.dllをthunderbird.exeと同じフォルダに置く
- share/kakasiのkanwadict, itaijidictをどこか適当なフォルダに置く
- KANWADICTPATH, ITAIJIDICTPATHをそれぞれkanwadict, itaijidictのフルパスに設定する
- プロファイルディレクトリ(*)のtraining.datを削除してからthunderbird.exeを実行する
- 学習してみよう
- spamdump.plで学習結果を試してみよう(!)
(*) WinNTならc:\Document and settings\(username)\Application data\Thunderbird\Profiles\(random)\...
(!) プロファイルディレクトリで perl spamdump.pl < training.dat > a.txt。a.txtはUTF8対応のエディタで開く。
- 2005/01/04-05:
-
苦労して作ったが、KAKASI融合版は放棄することにした。
代わりに、文字をひらがな、カタカナ、漢字、記号の種類に分類して、
文字種が変化するところで分断することにする。
すんごく適当だが、学習数でカバーできるはず。
ようやく安定してビルド出来るようになった。
だがVC++でのビルドにはまだ成功しない。
日本語トークン化版の使い方:
- パッチを当ててビルドする
- プロファイルディレクトリのtraining.datを削除してからthunderbird.exeを実行する
- 学習してみよう
- spamdump.plで学習結果を試してみよう
- 2005/01/05-06:
-
training.datをダンプするXULアプリケーションを作成することにした。
いちいちspamdump.plで確認するのが面倒なので。
既にありそうなものだと思って探し回ったが、なかった。
スクリプトからバイナリファイルにアクセスする方法がなかなかわからない。
文字コードの変換とかも不明。
ドキュメントがあまりにも不整備過ぎる。
最終的にはソースコードを見るしかないのか。
XULエレメントのoutlineで穴に嵌る。
どうやっても表示されないので調べまくったら、
もう2年も前に規格から無かったことにされていた。
Javascript debuggerがchromeに対応していないと思って穴に嵌る。
実はブラウザ関連のファイルを隠す設定になっていた。
その他の色々なトラップにもひっかかりながら、何とか動くものが完成した。
mozilla 1.7.5に日本語トークン化パッチを当てようとして失敗した。
nsBayesianFilter.*が相当変更されている。
files:
- spamdump.xpi training.datを展開して表示するmozilla拡張。thunderbirdにはまだ多分使えない。
URLs:
spamdump extensionの使い方:
- spamdump.xpiをインストールする。chrome/spamdump/にファイルがインストールされる。
- アドレスバーから、chrome://spamdump/content/にアクセスする。
- Startボタンを押すと、プロファイルディレクトリのtraining.datを読み込んで表示する。
- 2005/01/07:
-
spamdump extensionをhttp://www.mozillazine.org/あたりにポストしようと思って、
その前に検索して調べたら、training.datを表示する拡張はやっぱり既にあった。がーん。
でも私の環境ではなんだかうまく動かないし、HTMLで表示する関係上、速度の問題があるらしく、
すべてが表示されるわけではないらしい。
なのでspamdump extensionにも存在価値はあるはず。
編集機能でもつけるか。
XULオーバーレイを使ってツールメニューに表示コマンド('show training.dat')を挿入するようにした。
これでThunderbirdからでも呼び出せるようになるはず。
spamdump extension 0.2の使い方:
- spamdump.xpiをインストールする。chrome/spamdump/にファイルがインストールされる。
- メールクライアントのメニューからツール -> show training.dat と辿る。
- 表示されたウィンドウでStartボタンを押すと、プロファイルディレクトリのtraining.datを読み込んで表示する。
- たぶんウィンドウのサイズが小さいので、適当に引き伸ばす。
- Mozillaなら、アドレスバーからchrome://spamdump/content/でもアクセスできる。
- 2005/01/08:
-
spamdump extensionをさらに改造して、簡易編集機能をつけてみた。
mozdev.orgで探してみるとtraining.datを編集するのがあったが、
これはjavaアプリケーションだった。
いずれにしろtraining.datのファイルフォーマットは、結構適当ぽいから、
そのうち変更されるかもなあ。
プログレスバーを更新する方法が分からない。
valueを変更しただけでは変化しない模様。
ウィジェットを再描画する命令が見つからない。
spamdump extension 0.3の使い方:
- spamdump.xpiをインストールする。chrome/spamdump/にファイルがインストールされる。
Mozillaの場合はブラウザウィンドウにxpiファイルをドラッグ&ドロップ。Thunderbirdの場合はメニューの「ツール」の「拡張機能」から「インストール」。
- ThunderbirdまたはMozillaを再起動する。
- メールクライアントのメニューからツール -> show training.dat と辿る。
- File:のところに学習データのファイル名を入力する。
標準ではtraining.datが指定されている。
- Loadを押すと、データがロードされてリストに表示される。
右上のプログレスメータは何の役にも立たない。
- 一番下のFilter:にキーワードを入力すると、それを含む単語だけがリストに表示される。
入力からフィルタリングの実行まで、0.8秒のディレイがある。
- リストから単語を選択して、Delete selectionを押すと、単語が削除される。
CtrlやShiftキーを押しながら選択することで、複選択をすることが可能。
- Saveを押すと、データが保存される。
保存先のファイルはFile:のところで指定できる。
- 全角スペースをFilter:に入力してから、出てきた検索結果を全削除すると効果的かもしれない。
- 2005/01/08
-
Bugzillaに投稿したパッチに、メールプロジェクトのマスターから返事が届いた。
「パフォーマンスを確認したの?確認のテストケースは確立したの?」と。
ぎゃー。
尤もだ。
ということで、ここ最近のメールをかき集めて確認してみた結果はこんなところ。
うを、かなり成績が良いのではないか?。
before patch:
total success ratio
ham news 582 582 100.0%
private 49 49 100.0%
total 631 631 100.0%
spam news 53 52 98.1%
others 93 30 32.3%
total 146 82 56.2%
after patch:
total success ratio
ham news 582 581 99.8%
private 49 49 100.0%
total 631 630 99.8%
spam news 53 53 100.0%
others 93 80 86.0%
total 146 133 91.1%
パッチ後に間違ってspamと判別された1通は、
フリーWebホストから来たアンケート調査なのでぶっちゃけどうでもいいし、
とり逃したspamのうち半分は文字化けでほとんど読めないメールだった。
しかしBugzillaへの投稿は英語が不自由な身にはつらい。
かといって日本のBugzillaに投稿してもどうしようもないしなあ。
- 2005/01/11
-
Javascriptの限界を見た。
spamdump extensionでちょっと大きいtraining.datを開くとインタプリタが警告を始める。
「ちょっと重いよこれ、いいの?コンピュータ止まっちゃうかもしれないけど、続ける?」
無視してcancelを押しまくると動く場合もあるけど、いくら頑張っても駄目な場合もある。
大体10万トークンを超えたあたりから警告ダイアログが出始めて、
17万トークンを超えるとout of memoryでスクリプトが中断する。
ええい、貧弱なやつめ。
Javascriptのオブジェクトをハッシュマップに使って何が悪い。
重いよ警告は処理途中でメッセージループ(?)に戻ったら誤魔化せるかもしれないが、
out of memoryで止まるのはどうしようも無い。
こうなったらメモリスワップファイルでも実装するか?
それは厭だ。
日本語メールを学習させるとトークン数が一気に跳ね上がるような気がする。
高々1000通程のメールを学習させただけで20万トークンにもなるのは、
英語圏での設計からするとたぶん想定外だと思う。
ジャンクボタンを押すたびにハードディスクがカラカラと音を立てる。
速度パフォーマンス的に良くない。
ひらがなをトークンとしてピックアップするとトークン数が非常に多くなる気がした。
そこでひらがなの前3文字だけを残して後は切り捨てる方法をとってみた。
これなら高々50の3乗程度にしかならないはず。
しかし分類パフォーマンスは低下した。
それよりは、最初からひらがなを全く考慮しない方が良かった。
ひらがなを全てトークンとしてピックアップすると分類パフォーマンスは非常に高くなる。
しかし速度パフォーマンス的に許容できるのかどうか。
ジャンクボタンを押すたびにtraining.datから読み込み/書き込みをしているような気がする。
無駄だと思う。
日本語トークンにいちいちjapanese_token:などと長い名前を付けるのはメモリの無駄なので、
プレフィクスを「JA:」に変更した。
ラテントークンの標準処理では大文字は小文字に変換されるので、
「JA:」を含むのはtokenize_japanese_wordsで拾われた日本語トークンだけだ。
training.datを眺めていると疑問点がちらほら:
message-id:を登録するのはいかがなものか。
何故か登録されないはずの数字トークンが登録されている。
これはI18Nスキャナが拾っているのだと思う。
値札「\1,000」とかが登録されているのはいかがなものか。
- 2005/01/11
-
スパムフィルタの分類パフォーマンス測定メソッドをまとめておく。
シングル・メソッド:
学習用と測定用に同じメールの組を使います。成功率100%を期待してよいはずのテストです。
- ローカルフォルダに、ham(非ジャンク)とspam(ジャンク)フォルダを作成する。
- 受信したメールを読んで分類し、ジャンクメールををspamに、それ以外をhamにコピーする。
- training.datを削除する。
Thunderbirdなら「Junk mail controls...」の「Adaptive Filter」から「Reset training data」を押してOK。
Mozillaなら、Mozillaを完全に終了した状態でプロファイルディレクトリのtraining.datを削除する。
- hamのフォルダを開き、「Ctrl+A」で全選択してから「Shift+J」で非ジャンクにマークする。
これで、このフォルダのメールは非ジャンクとしてtraining.datに登録される。
- 同様にspamのフォルダを開き、「Ctrl+A」で全選択してから「J」でジャンクにマークする。
これで、このフォルダのメールはジャンクとしてtraining.datに登録される。
- hamのフォルダを開き、メニューから「Run junk mail controls on folder」を実行する。
フィルタが実行され、ジャンクマーク状態が変化する。
- 同様にspamのフォルダを開き、メニューから「Run junk mail controls on folder」を実行する。
フィルタが実行され、ジャンクマーク状態が変化する。
- hamとspamでそれぞれジャンクと非ジャンクの数を数えて、分類パフォーマンスを求める。
注意点:
- 学習させるときにツールバーのボタンを使ってはいけない。
このボタンの動作はメールのジャンクマーク状態に依存して変化する。
- View:のフィルタで「非ジャンク」を選択すればフォルダ内の非ジャンクの数が分かる。
ダブル・メソッド:
学習用と測定用に別のメールの組を使います。hamの成功率100%が理想です。
- ローカルフォルダに、trainingとtestフォルダを作成する。
- trainingとtestの各々にham(非ジャンク)とspam(ジャンク)フォルダを作成する。
- 受信したメールを読んで分類し、ジャンクメールをtraining/spamに、それ以外をtraining/hamにコピーする。
- training.datを削除する。
Thunderbirdなら「Junk mail controls...」の「Adaptive Filter」から「Reset training data」を押してOK。
Mozillaなら、Mozillaを完全に終了した状態でプロファイルディレクトリのtraining.datを削除する。
- training/hamのフォルダを開き、「Ctrl+A」で全選択してから「Shift+J」で非ジャンクにマークする。
これで、このフォルダのメールは非ジャンクとしてtraining.datに登録される。
- 同様にtraining/spamのフォルダを開き、「Ctrl+A」で全選択してから「J」でジャンクにマークする。
これで、このフォルダのメールはジャンクとしてtraining.datに登録される。
- test/hamのフォルダを開き、メニューから「Run junk mail controls on folder」を実行する。
フィルタが実行され、ジャンクマーク状態が変化する。
- 同様にtest/spamのフォルダを開き、メニューから「Run junk mail controls on folder」を実行する。
フィルタが実行され、ジャンクマーク状態が変化する。
- test/hamとtest/spamでそれぞれジャンクと非ジャンクの数を数えて、分類パフォーマンスを求める。
注意点:
- 学習させるときにツールバーのボタンを使ってはいけない。
このボタンの動作はメールのジャンクマーク状態に依存して変化する。
- View:のフィルタで「非ジャンク」を選択すればフォルダ内の非ジャンクの数が分かる。
- 2005/01/13
-
spamdump extensionをさらに改造。
いや、面白いからついやってしまう。
トークンのGood+Badの合計を表示できるようにした。
これで参照数の少ないトークンを一括削除できる。
あるいは、参照数の多いトークンをみてにやにやできる。
本当は全て平等に1を引いて、参照数が0になったトークンを削除するべきだと思うが。
データをクリップボードにコピーできるようにした。
これは本当に面白いだけだ。
追加の使い方:
- 範囲を選択して「Copy selection」をクリックすると、
選択したデータがタブ区切りテキスト形式でコピーされる。
このときコピーしたトークンの数がボタンに1秒間表示される。
Total列はコピーされない。
- タブを含むトークンがある場合、コピー先で列がずれることもある。
本来はタブを含むトークンなど存在しないはずだが……。
- トークンを削除したときに確率が再計算されるようにした。
- トークンを削除したときに再ソートするようにした。
- 2005/01/13
-
数字トークンを除く全てのトークンを無差別に受け入れることにした。
ぱっと見だが、分類性能はこちらのほうが良いような気がする。
辞書が大きくなると学習時の時間は長くなるけれども、実行時の時間はそれほど変わらない。
将来的にファイルを閉じたり開いたりする回数を減らせば問題は無くなるだろう。
予想どおり、句点、読点、が、は、を、に、の、がかなり多く辞書に登録されるなあ。
メール中のURLなんてのは決定的な手懸かりになると思うんだけど、
現在の実装ではピリオドがトークンのセパレータに使われるため、
「http://www」だけが登録されている、なんてことになっている。
HTMLのタグも手懸かりになると思う。
今はHTMLのタグを全て消去してから処理しているようだ。
たぶん一文字ごとに規格外のタグを入れてフィルタを回避する手法に対応した為なんだと思うけど、
それはタグ部分とテキスト部分を別々に処理すれば良いことだと思う。
語順は関係ないのだし。
まあ、ベイジアンフィルタの場合は、合理的だと思うサンプリング手法を使っても、
やってみると予想どおりの性能が出ないという事が良くあるみたいですけど。
- 2005/01/15
-
継続して取り組んでくれてアリガトウ、ところで、else忘れてんじゃないの?と言われた。
おお、その通りだ。
ちゃんと見てるんだ、ということに感激。
褒めて伸びる人なので。
もっともっと。
ベイジアンフィルタ関連の機能については、どうやらmail.dllだけ交換すればよい模様。
使いたい人柱の人は、上のフルセットのcomponents/mail.dllを上書きして使って欲しい。
日本語トーカナイザがちゃんと働くことにはもう何の疑問もないので、デバッグ出力の部分をばっさり切った。
そうすればデバッグのためだけに依存していたuconvをMakefile.inから外すことができるので。
ShiftJIS判別コードの最適化手法を参考に、若干クレイジーな最適化を行った。
文字種の判別はクリティカルパスなので。
まだできるような気がする。
でもまだそんな段階じゃない。
- 2005/01/17
-
spamdump extensionで、フィルタに否定と正規表現を使えるようにした。
当然ながら、正規表現はJavascript形式の正規表現に限る。
これってKAKASIにするとどうなるのかいな?
という好奇心旺盛な方々の為にKAKASI融合版mail.dllを置いておきます。
パッチの当ててない生のThunderbird 1.0 + spamdump extension 0.5も一緒に置いておきます。
一応、KAKASI融合版にも全角スペース変換を組み込んだ。
本来はスペースクラスに属する文字コードをすべて変換するべきだろうけど。
XORオペによる文字コード範囲の移動はパズルに似た面白さがある。
だが、色々考えたけれども、結局XORはビットのon/offを切り替えるだけなので、
どんな操作をしても、差が偶数個の場合は隣り合わせることが出来ないことがわかった。
たとえば、0x0001と0x0003はいかなるXORによっても、隣り合わせることが出来ない。
追加の使い方:
- filter:に「not 検索文字列」と入力すると、検索文字列を含まない結果だけが表示されるようになります。
- filter:に「regexp 正規表現」と入力すると、正規表現にマッチする結果だけが表示されるようになります。
- filter:に「not regexp 正規表現」と入力すると、正規表現にマッチしない結果だけが表示されるようになります。
- notとregexpは大文字と小文字を区別せず、順不同です。
- 2005/01/20
-
パッチが組み込まれたので最新のツリーを持ってきた。
今後はこれで作業しようかしら。
前まで何故か成功せずにもがき苦しんだVC++6でのビルドにあっさりと成功。
でもバージョンダイアログではバージョンが0.6+とかって出てる。
いいのかな。
ただの飾りかな。
ちょっと使ってみたが、バグだらけでまともに作業ができない。
エクステンションが入らない。
spamdump extensionを手動で組み入れてみたが、なぜかtreeが表示されない。
というわけでまたThunderbird 1.0に戻すことにした。
おそるおそるVC++6でビルドしたら、なぜか一発で成功した。
特に設定は変えてないはずなのに。
でもたぶん変えてたんだろう。
よくわからん。
初回起動時にエラーが出るのはなんでかな。
ユーザーフォルダのエクステンションか設定ファイルかが関係しているような気がする。
二回目以降はなぜかきちんと動くので、まあいいや。
Enigmailも動いた。
自分で自分にメール送信のテスト。
暗号化されているメールはたぶん学習の対象にはならないよなあ。
署名付きでスパムを送るのもないだろうけど。
- 2005/01/22
-
SubjectのMIMEデコードと日本語トークン化を適用してみた。
かなり良いのではないかと思われる。
また、ヘッダの内、x-mozilla-status、x-mozilla-status2、x-uidlは破棄するようにした。
日本語メールとそれ以外の言語のメールを別々の辞書で解析するようにしてみた。
ちょっとやってみただけなので、許せないぐらい酷いパッチになっている。
ugly workaround.
nsBayesianFilterに日本語専用の辞書(Tokenzier)と日本語専用のカウンタを追加して、
日本語メールの場合だけ特別にそちらを使うようにした。
mGoodTokens、mBadTokens、mGoodCount、mBadCountに対して、それぞれ、
mGoodTokensJ、mBadTokensJ、mGoodCountJ、mBadCountJを追加した。
無茶苦茶だよこれ。
このままBugzillaにポストしたらバッシング必至だな。
日本語辞書もラテン辞書も両方まとめてtraining.2.datに保存する。
ヘッダは仮に0xFACE0000へと変更し、spamdump extensionでも読み込めるようにした。
ただしこの場合の確率計算は正しくなくなる。
成績はかなり良くなった模様。
当然ながら、英語メール500通学習後でも全く成績が落ちない。
では書き直すとするか。
- 2005/01/22
-
Bugzillaにベイズフィルタをジャンクメールコントロールの他にも応用するパッチがあった。
もう2年も前からあるのに、なんで統合されてないんだろ。
有用なのは確実なのに。
これが統合されていれば、辞書を別に持つようなトリックもいらないと思う。
ヘッダからmessage-idを破棄するようにした。
あとは何が要らない?
spamdump extension 0.6で0xFACE0000形式のトレーニングファイルを読み込み、
さらに保存した場合は0xFEEDFACE形式に変換されてしまうので、注意が必要。
要するに、保存は出来ない。
- 2005/01/24
-
tokenizeHeadersをさらに修正。
これで不要なヘッダは全て刎ねたはず。
日本語メールのトークンを別辞書に載せるパッチで、フィルタの精度が劇的に向上したような気がする。
学習数は3万トークン弱しかないが、再帰テスト(フィルタに学習させたメールを再度フィルタに分類させる)では成功率100%だし、
新しく来るメールにしても、偽陽性は0、偽陰性が英語でいくつかある程度。
もう行くところまで行ったと思う。
個人的には満足。
目的は達成した。
自分ビルドでも実用上特に問題ない。
ということでBugzilla投稿用のパッチを書くモチベーションががた落ち。
まあ将来のThunderbirdリリースごとにパッチを当て直してビルドする手間を考えたら、
ここでアピールしてオフィシャルのツリーに組み込んでもらう価値はあるんだけれども。
- 2005/01/24
-
Visual Studioなしでmsvcビルドに挑戦。
cygwin + Toolkit 2003 + .NET SDK + Platform SDK + MASM32を使う。
そこかしこの穴という穴に落ちまくったが、なんとか駆け抜けた。
- 2005/01/27
-
ヘッダのトークン化の所を微修正。
referenceヘッダを登録しないように変更。