HaskellとMecabで長門に関してのテキストをを判別してみた

前々からちょこちょこやっていたのがやっと一応の完成を見ました。

なにこれ

戦艦長門長門有希と戦艦長門(艦これ)についての文章を判別することを目的にナイーブベイズな分類器をHaskell+MeCabで実装したやつです。

中身

言語処理のための機械学習入門 (自然言語処理シリーズ)

言語処理のための機械学習入門 (自然言語処理シリーズ)

この本読みながら実装しました。一応この本で言う117ページとかそこら辺の多項モデルでMAP推定な感じです

動作

Windowsコマンドプロンプト文字化けしたので外部ファイルから読み込むようになりましたけど……
一応全部学習用のデータとは別のテキストを放り込みました。
f:id:haru2036:20140104212307p:plain
(艦これの長門)
f:id:haru2036:20140104212316p:plain
(長門有希)
f:id:haru2036:20140104212319p:plain
(戦艦長門、結果が間違って長門有希になってるけど)

まとめ

なんか最後の戦艦長門だけ何故か艦これじゃなくて長門有希に間違われてるけど他にもいろいろ放り込んだ分にはあらかたイケてる印象、これほんとに全部のアイテムを対象にやっちゃってるけど正規化とかしたらもっといい感じになりそう

追記:
リポジトリ
haru2036/nagato · GitHub

Haskell触ってみる(2)

というわけで結構ヤバいのではと思いつつ触ってます。

正直言って寝起きなので変なこと書きまくってるかもしれない。
リポジトリはここでやってるのでツッコミをいただけるとありがたかったり。
haru2036/learnHaskell · GitHub
なんとかそれぞれの要素に対しての出現頻度を数えることができるようになりました。
ただなんか実行結果がfromListって関数が帰ってきてるようにしか見えないのでなんか違う感があったりする。

ソース:

import Data.List
import Data.HashMap.Lazy

searchAndCountWords :: String -> [String] -> Int
getUnigramFrequency :: [String] -> HashMap String Int

getUnigramFrequency sList = fromList [(a, searchAndCountWords a sList) | a <- nub sList]

searchAndCountWords key items = length $ Data.List.filter (==key) items

main = return $ getUnigramFrequency ["a", "a", "ba", "bb", "ab", "a"]

実行結果:

fromList [("bb",1),("ba",1),("ab",1),("a",3)]

HashMap使うためにはパッケージ追加でインストールしないといけないのねとか。
あと、Data.HashMap.LazyとData.HashMap.Strictってどっち使えばいいのかわからないし英語読めないので辛いし英語も勉強しないとヤバいのではってなってる

Haskellを触って見る続き

とりあえずさしあたっての目標に前のエントリに書いたようにラボユース成果物(haru2036/laboyouth · GitHub)をHaskellに移植することを設定したので、とりあえずモデルの生成部分からやっていこうと思ってます。まあいきなりtrigramの数え上げやったら死ぬと思ったので、さしあたりunigramの数え上げからやっていこうと思ってます。
そんなこんなでとりあえず一つの単語に付いて何回出現するかを調べる関数を作ったのですが、なんかよくわからんことに。

countUnigram :: String -> [String] -> Int

countUnigram key items = length $ takeWhile (==key) items

main = return $ countUnigram "a" ["a", "a", "ba", "bb", "ab", "a"]

こんなコードを書いて実行すると

2

とか出てきました。ひとつ足りなくね?と思って検索対象(一つ目の引数)を"ab"にしたところ0と……じゃあ存在しない場合どうするのよと思って"cc"をしても0が帰ってきます、どういうこっちゃ。takeWhileがそういう感じなのかそれとも……

(たぶん)つづきます

    • 追記--

ありがたいことにTwitterですぐツッコミをもらったので。


とのことでtakeWhileをfilterに置き換えたらうまくいきました。
当初参考にしていたページ
Haskell のリスト操作 : tnomuraのブログ
にもtakeWhileとfilter両方乗ってたけどうっかりfilterを見落として書いてしまってたみたいで。
そこをもう一度見たら

条件に合う要素をリストの先頭から取り出す。条件が合わなくなったところで処理は終了する。
Hugs> takeWhile (<4) [1,2,3,4,5]

てて書いてありました。さいしょのa2つの次にbaが入ってたのでそこで終了しちゃってたみたいな。
ありがとうございます!

つづきました