やぐブロ

yag + programming + hateblo

Clojureでナイーブベイズ分類器(多変数ベルヌーイモデル)

Clojureの練習としてナイーブベイズ分類器を実装してみることに.
まずは,言語処理のための機械学習入門 (自然言語処理シリーズ)のP.105の例題4.1を解いてみました.

参考にしたサイト

非常に参考になりました.というか殆ど写しました.ありがとうございます.

実装

(def text_classified_p '(["good" "bad" "good" "good"]
                            ["exciting" "exciting"]
                            ["good" "good" "exciting" "boring"]))
(def text_classified_n '(["bad" "boring" "boring" "boring"]
                           ["bad" "good" "bad"]
                           ["bad" "bad" "boring" "exciting"]))


(defn train [features]
  (reduce (fn [model f] (assoc model f (get model f 1))) {} features))

(defn count-wordset [training-data]
  (apply merge-with + (map train training-data)))

(defn mBm-MLestimate [documents datasets]
  (* (/ (count datasets) (count (concat text_classified_p text_classified_n)))
     (apply * (map #(/ % (count datasets))
                   (vals (select-keys (count-wordset datasets) documents))))
     (apply * (map #(- 1 (/ % (count datasets)) )
                   (vals (apply dissoc (count-wordset datasets) documents))))))


(defn classify [d]
  (sorted-map
   :positive (mBm-MLestimate d text_classified_p)
   :negative (mBm-MLestimate d text_classified_n)))

結果

実際にclassifyを実行してみると

> (classify ["good" "good" "bad" "boring"])
{:negative 2/27, :positive 1/81}

このように確率の高い順に結果が出力されるので「"good" "good" "bad" "boring"」と発言したのはn氏,という感じで分類できます.


注意

この実装では例題4.2が解けません!!!今度直します...

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

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


(追記:2012/01/26)
例題4.2に対応できるようにアドホックに改良.あと,classifyでソート出来ていなかったので,その部分も少し変更.

(defn mBm-MLestimate [documents datasets]
  (* (/ (count datasets) (count (concat text_classified_p text_classified_n)))
     (apply * (map #(/ % (count datasets))
                   (vals (select-keys (count-wordset datasets) documents))))
     (apply * (map #(- 1 (/ % (count datasets)) )
                   (vals (apply dissoc (count-wordset datasets) documents))))
     (if (some nil? (map #(find (count-wordset datasets) % ) documents )) 0 1 )))

(defn classify [d]
  (sorted-map-by >
                 (mBm-MLestimate d text_classified_p) :positive
                 (mBm-MLestimate d text_classified_n) :negative))