Clojure/Incanter/clj-mlでデータマイニング入門

概要

Clojureデータマイニングに必要な各手法を解説する記事です。
本記事を読むと、全くClojureを知らない方でも

  1. データ抽出・集計
  2. 可視化
  3. 機械学習(決定木、ランダムフォレスト、k-meansクラスタリング)

Clojureで実行できるようになります。

はじめに

ClojureとはJVM上で動く(つまりOSを問わず沢山の環境で動く上に
Java資産をそのまま使える)Lisp系の言語です。
Clojureではデータマイニングを行う際、
Incanterとclj-mlという2つの便利なツールがあります。
Incanterは統計処理用の専門ライブラリで、
単体で様々な統計分析を行ったり集計を便利にしたりする機能が沢山用意されています。
clj-mlはwekaという機械学習系のツールClojureで簡単に使えるようにしたラッパーで、
決定木やランダムフォレストなどの分類器や
各種クラスタリング手法を利用出来るようになります。
この記事ではClojureからIncanterとclj-mlを用いて
簡単にデータマイニングを行う手順について説明します。
各手法やコードの詳細は追わず、
Clojureで何が出来るのかを俯瞰するための入門記事です。

Clojureとleiningenのインストール

leiningenはClojureの標準的なビルドツールで、
これを入れるとClojure本体から各種ツールのインストール、
プロジェクトの起動やビルドなど様々なことが出来て便利です。
以下のドキュメント通りにすれば簡単にインストール出来ます。
http://marui.hatenablog.com/entry/2014/02/15/113838
http://kaosf.github.io/20140209-clojure-getting-started/#/
特にwindowsでは次のツールを使うと
マウスをぽちぽちしてるだけでインストール完了です。
http://leiningen-win-installer.djpowell.net/

incanterとclj-mlの設定

任意のフォルダに環境を構築します。
ここではwindows, c:\testに今回の環境を作るとします。
cd c:\
lein new test
とするとc:\以下にtestフォルダが生成されているはずです。
そのフォルダにあるproject.cljをエディタで開き、
下記をコピペして下さい。

(defproject test "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [incanter "1.5.5"]
                 [cc.artifice/clj-ml "0.6.0-SNAPSHOT"]])

これは2014/09/02現在最新バージョンのClojureとIncanterとclj-mlを利用する設定です。
この設定が終わった後、
lein deps
とすると設定したライブラリをleiningenが自動で取得してくれます。

incanterを使ってみる

Incanterを利用すると次のようなことが可能となります。

  • データ抽出、各種集計
  • 可視化
  • 各種統計分析(回帰分析や主成分分析など)


まずは便利なデータ操作、各種集計方法を学びましょう。

; ■Incanter動作確認
; まずuse関数で各種機能を読み込みます。
; charts: 描画
; stats: 統計分析
; datasets: サンプルデータセット
(use '(incanter core charts stats datasets)) 

; サンプルデータセットからirisを読み込み、
; irisという名前に束縛します
(def iris (get-dataset :iris))

; irisの中身を見てみます。
; Excelライクな画面が立ち上がります
; これで一度irisがどのようなデータか確認してください
(view iris)

; ■各種データ抽出
; データマイニングをする場合はデータを様々な角度から眺めるのが肝要です。
; 同じデータでも切り口を変えると見え方が変わってきて、
; 今まで気づかなかった特徴を見出すことがあります。
; ある条件を満たしたデータだけを抽出する方法を説明します。

; irisデータからSpecies列がsetosaの行だけ取得
($where {:Species "setosa"} iris)
; :Petal.Width列が>2の行だけ取得
($where {:Petal.Width {:$gt 2}} iris);
; 指定列で昇順(asc)/降順(desc)。asc, desc省略不可
($order :Petal.Width :asc iris)
; 上記組合せ。
($order :Petal.Width :desc ($where {:Petal.Width {:$gt 2.2}} iris))
; 指定列を取得
($ :Sepal.Length iris)

; ■データから要約統計量を得る
; Incanterには各種要約統計量を算出する関数が揃っています。

; 指定列の算術平均
(mean ($ :Sepal.Length iris)) ; 5.843333333333335
(mean ($ :Petal.Length iris)) ; 3.7580000000000027

; 指定列の標準偏差
(sd ($ :Sepal.Length iris)) ; 0.8280661279778632
(sd ($ :Petal.Length iris)) ; 1.7652982332594656

; データ全体からではなくグルーピングして要約統計量を得る
; ここではirisからSpeciesごとに各種要約統計量を得る
; $rollup関数は第一引数にどのような処理するかオプションか関数を指定
; 第二引数で列指定
; 第三引数でグルーピングする列を指定
; 第四引数でデータを指定
($rollup :mean :Sepal.Length :Species iris)
;|   :Species |     :Sepal.Length |
;|------------+-------------------|
;|  virginica | 6.587999999999998 |
;| versicolor |             5.936 |
;|     setosa | 5.005999999999999 |
($rollup :count :Sepal.Length :Species iris)
($rollup :max :Sepal.Length :Species iris)
($rollup :min :Sepal.Length :Species iris)

; $rollupのオプションに無い集計をしたい場合は
; 第一引数に任意の関数を放り込めばよい
($rollup median :Sepal.Length :Species iris)
($rollup variance :Sepal.Length :Species iris)

; ある程度集計済みのデータに対し、
; 更に条件加えて集計するにはgroup-byが便利
(with-data (get-dataset :hair-eye-color)
  ($group-by [:hair :eye]))
;{{:eye "green", :hair "black"}
;| :hair |  :eye | :gender | :count |
;|-------+-------+---------+--------|
;| black | green |    male |      3 |
;| black | green |  female |      2 |
;, {:eye "hazel", :hair "red"}
;| :hair |  :eye | :gender | :count |
;|-------+-------+---------+--------|
;|   red | hazel |    male |      7 |
;|   red | hazel |  female |      7 |
;...

次にデータを可視化してみます。
詳細については下記を参照してください。
http://liebke.github.io/incanter/charts-api.html

(def iris (get-dataset :iris))
; 棒グラフ bar-chart
(view (bar-chart :Species :Sepal.Length :data iris))
; 折れ線グラフ line-chart
(def airline (get-dataset :airline-passengers))
(def years (sel airline :cols 0))
(def months (sel airline :cols 2))
(def passengers (sel airline :cols 1))
(view (line-chart months passengers :group-by years :legend true))

f:id:AntiBayesian:20140216020547p:plain

; ヒストグラム
(view (histogram :Sepal.Width :data iris))

f:id:AntiBayesian:20140216020531p:plain

; 箱ひげ図
(view (box-plot :Sepal.Width :group-by :Species :legend true :data iris))

f:id:AntiBayesian:20140216020557p:plain

; 散布図 scatter-plot
(view (scatter-plot :Sepal.Length :Sepal.Width :data iris))
; 散布図にgroup-byオプションを用いてSpecies毎に色分け表示
(view (scatter-plot :Sepal.Length :Sepal.Width :data iris
                              :group-by :Species))
; 散布図行列 scatter-plot-matrix
(view (scatter-plot-matrix iris :nbins 20 :group-by :Species))

f:id:AntiBayesian:20140216020611p:plain

; QQプロット
(view (qq-plot :Sepal.Length :data iris))

f:id:AntiBayesian:20140216020802p:plain

clj-mlで機械学習

clj-mlはwekaをClojureから簡単に使えるようにしたものです。
詳細は下記を参照してください。
https://github.com/joshuaeckroth/clj-ml
wekaはデータマイニング業界で結構古くから使われているツールで、
各種機械学習の手法が利用できます。
今回はよく使われる分類器である決定木とランダムフォレスト、
非階層型クラスタリング手法であるk-meansを紹介します。

(use 'clj-ml.classifiers 'clj-ml.utils 'clj-ml.io 'clj-ml.data)

; weka特有のデータ形式arffを利用します。
(def iris  (-> (load-instances :arff "http://repository.seasr.org/Datasets/UCI/arff/iris.arff") (dataset-set-class :class)))
; CSV形式を読み込む場合は次のようにします。
;(def iris  (-> (load-instances :csv "iris.csv") (dataset-set-class :class)))

; ■決定木
(def decision-tree (-> (make-classifier :decision-tree :c45) (classifier-train iris)))
; 作成した決定木の中身を見てみます
decision-tree
;petalwidth <= 0.6: Iris-setosa (50.0)
;petalwidth > 0.6
;|   petalwidth <= 1.7
;|   |   petallength <= 4.9: Iris-versicolor (48.0/1.0)
;|   |   petallength > 4.9
;|   |   |   petalwidth <= 1.5: Iris-virginica (3.0)
;|   |   |   petalwidth > 1.5: Iris-versicolor (3.0/1.0)
;|   petalwidth > 1.7: Iris-virginica (46.0/1.0)
;Number of Leaves  :     5
;Size of the tree :      9

;クロスバリデーションに掛けてみます
(def decision-tree-evaluation (classifier-evaluate decision-tree :cross-validation iris 10))
;クロスバリデーションの結果を確認します
(println (:summary decision-tree-evaluation))
;Correctly Classified Instances         143               95.3333 %
;Incorrectly Classified Instances         7                4.6667 %
;Kappa statistic                          0.93
;Mean absolute error                      0.0393
;Root mean squared error                  0.1755
;Relative absolute error                  8.8447 %
;Root relative squared error             37.2333 %
;Total Number of Instances              150

(println (:confusion-matrix decision-tree-evaluation))
;=== Confusion Matrix ===
;  a  b  c   <-- classified as
; 49  1  0 |  a = Iris-setosa
;  0 47  3 |  b = Iris-versicolor
;  0  3 47 |  c = Iris-virginica
; ■ランダムフォレスト
; 見ればわかりますが、make-classifierのオプションを
; :c45 -> :random-forestに変更するだけです
(def random-forest (-> (make-classifier :decision-tree :random-forest) (classifier-train iris)))
random-forest
(def random-forest-evaluation (classifier-evaluate random-forest :cross-validation iris 10))
(println (:summary random-forest-evaluation))
(println (:confusion-matrix random-forest-evaluation))
; ■k-means
(use 'clj-ml.clusterers)
; そもそもspeaciesがあればクラスタリングする必要無いので一旦外します
(def iris  (-> (load-instances :arff "http://repository.seasr.org/Datasets/UCI/arff/iris.arff") (dataset-remove-attribute-at 4)))
(def k-means (make-clusterer :k-means {:number-clusters 3}))
(clusterer-build k-means iris)
k-means
;Number of iterations: 6
;Within cluster sum of squared errors: 6.998114004826762
;Missing values globally replaced with mean/mode
;Cluster centroids:
;                           Cluster#
;Attribute      Full Data          0          1          2
;                   (150)       (61)       (50)       (39)
;=========================================================
;sepallength       5.8433     5.8885      5.006     6.8462
;sepalwidth         3.054     2.7377      3.418     3.0821
;petallength       3.7587     4.3967      1.464     5.7026
;petalwidth        1.1987      1.418      0.244     2.0795

終わりに

随分駆け足ではありましたが、Clojureを用いたデータマイニングを俯瞰しました。
簡単にデータマイニング出来そう、やってみたい!と感じ取って頂ければ幸いです。
今回はざっとした紹介を行うだけで
各手法の詳細やコードの説明を行いませんでしたが、
今後詳細についても解説していきたいと思います。
皆さんもぜひClojureデータマイニングしましょう!

Clojureマイニング関連資料

Incanterを今からはじめるなら
http://marui.hatenablog.com/entry/2014/02/15/113838
統計解析アプリ「Incanter」入門
http://antibayesian.hateblo.jp/entry/20111128/1322494688
Clojure/lucene-kuromojiでテキストマイニング入門 ~形態素解析からワードカウントまで~Add Star
http://d.hatena.ne.jp/Kazuhira/20130911/1378914422
Clojure/kuromojiでテキストマイニング入門 ~形態素解析からワードカウントまで~
http://antibayesian.hateblo.jp/entry/2013/09/10/231334
Web系女子がLispと出会って統計学に目覚めるまでのお話
http://antibayesian.hateblo.jp/entry/20121210/1355152537
Incanter API
http://liebke.github.io/incanter/index.html


■追記
clojure, Incanter, clj-mlのバージョンアップに伴い、
project.cljの内容を2014/09/02最新版に変更しました。