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最新版に変更しました。

エンジニアのためのデータ可視化実践入門という本を書いた

2014/10/14 追記
本書87ページに「母数」という単語が複数回出てきますが、
これは全て「分母」とすべきでした。*1
通常、統計学の文脈では、母数は各確率分布を特徴付ける変数を指す単語であり、
例えば正規分布は平均と分散という二つの母数によって形状が決定されます。
決して母数と分母(あるいは全数)と誤解してはなりません。
しかし母数と分母を混同することは本当によくあることで、
本書はこのような頻出する誤解を訂正し、
皆様が統計を用いる際の失敗を一つでも減らす
という目的で執筆に至ったにも拘らず、
まさか本書でこのような重大な失敗をしてしまったことに対し
心からお詫び申し上げ訂正させて頂きます。
なお、問題個所の記述は共著者の森藤氏ではなく
私が記述したものであり、全責任は私にあります。

本を書くに当たり、誤字脱字や言い回しの不備は出来る限り無くすべきですが、
人間であるためミスをすることは仕方ない部分もあるとは思います。
ですが、本書のこの記述は誤字という程度の話ではなく、
巷の統計に関する誤解を助長する悪しき行為であります。
一般に抱かれがちな統計に関する誤解・誤謬を訂正し、
皆様が正しく統計を用いられるよう尽力することが統計屋の勤めでありますが、
統計屋を名乗っておいてこのような失態を犯したことに対して慙愧に堪えません。
取り急ぎ、本ブログで訂正致しますとともに、出来る限り出版社にサポート
電子書籍版の訂正、サポートページに正誤表付与。
大変申し訳ないのですが書籍に対しての訂正は困難だと思われます)
を依頼する予定です。

末尾になって恐縮ですが、ご指摘頂いた@abiko_ushi様には心より感謝致します。


エンジニアのための データ可視化[実践]入門 ~D3.jsによるWebの可視化 (Software Design plus)

エンジニアのための データ可視化[実践]入門 ~D3.jsによるWebの可視化 (Software Design plus)

電子書籍
https://gihyo.jp/dp/ebook/2014/978-4-7741-6372-7

本の紹介

概要

1.D3を使った可視化入門書です。
D3全然知らない方でも、本書を読めば基本的な可視化が可能になります。
本書のソースコードは下記サポートページでDL可能です。
http://gihyo.jp/book/2014/978-4-7741-6326-0/support

2.可視化に関する統計基礎を平易に解説しています。
円グラフはなぜダメなの?
どうして棒グラフの縦軸は省略してはいけないの?
KPIを可視化するっていうけど、
そもそもKPIってどんなのがあってどうやって決めればいいの?
などなどについて解説しています。

対象読者

・Webのデータを可視化したいけど可視化手法ってどんなのあるか知らない
・KPIとかどう決めていいのかよくわかんない、何をどう可視化していいかわからない
・D3を全然知らない
って感じの方です。

おすすめポイント

この本は「綺麗な何とかグラフを描くにはどうすれば良いか?」
を伝える本ではありません。
「なぜ、なんのために可視化するか、
可視化することによってどのようなメリットがあるか、
知りたいこととその可視化はマッチしているか」
を考えるための本です。
手元にあるデータを闇雲に可視化しても何も得るものはありません。
すべき可視化とそうでない可視化を選別すること、
また、すべき可視化でもより良い可視化をするにはどうすれば良いか、
そういったことについて書いています。

例えば「棒グラフの縦軸を省略してはいけない」のはなぜでしょうか?
棒グラフは各データの比の関係を見るためのグラフです。
データが[10, 15, 20]だったとしましょう。
各データの比は[1 : 1.5 : 2]ですね*2
これを縦軸を省略せず棒グラフにするとこうなります。
f:id:AntiBayesian:20140216235145j:plain
しかしここで縦軸を省略してしまうと次のようになります。
f:id:AntiBayesian:20140216235152j:plain
縦軸が省略されていきなり9から始まってますね。
この場合各データから9引いた値の比、
つまり[1 : 6 : 11]という先ほどの棒グラフとは全く違う印象を与えてしまいます。
これでは正しい比の関係が取れません。

可視化はデータを把握しやすくするものですが、
使い方を誤ると間違った印象を植え付けてしまう場合もあります。
状況認識を誤ったまま経営判断などを行うことは避けねばなりません。
「目的に応じて適切な可視化手法を使い分けるにはどうすれば良いか」
を説明するのが本書の目的です。

また、本来可視化はケースバイケースなことが多いのですが、
「可視化手法をたくさん紹介します、
どういう時に何を使うべきかはケースバイケースなので
各自で適切なのを選択するように、以上」
というのは、確かに誤ってはいませんが、
それでは入門者にとって益が無いと思います。
そもそも入門者は何が適切かを選択できるような体系的な知見がないからです。
本書では誤解を恐れず
「このようなケースでは9割方これを使えば良い(あるいは使うべきではない)」
という形で各手法を推薦・禁止しています
中には本書の記述が不適切な場合もあるでしょう。
本書の統計的な記述は基本的に私が行いました。
もし「この場合にこの手法推薦するのはおかしい!」
という箇所ありましたら、その責は全て私が負うものです。
ご指摘いただけますと幸いです、私の方で個別に対応させて頂きたいと思います。

Q&A

皆さんが関心あるだろう点について。

金について

一冊売れると50円くらい私のポッケに入る。
初版5000部刷ってる。
売れ残ると次の出版話がし辛いので皆さん20冊くらい購入して下さい。

書いた経緯は?

共著者の森藤氏から
「3D円グラフを殺しましょう!!!!!」
と口説かれたので速攻承諾しました。
今まで色んな口説き文句を聞きましたが、
これほど胸が熱くなる口説き文句は過去に無かった。
「ついでに結婚しましょう」
と言われたらそのまま押印してた勢いである。

始めは出版社が森藤氏に話を持ち掛け、
その後森藤氏が統計周りの記述する共著者探してたそうな。
私と森藤氏は特に知合いでは無かったけど、
なんかの勉強会でお会いした時に
「3D円グラフを殺す!!!!!!」
とか言ってた私が目についたらしい。
ありがたいことですね。
皆さんも「○○を殺す」って言いまくりましょう。

本書くの大変?

ブログで記事書くのと変わるところは特にない。
出版社のやりとりが多少面倒だけど、
相手はプロなので良いようにして下さる。
今回の担当者の方も色々便宜図って下さったので大変良かった。
あと私は筆が速い気がしてたが実際速かった。
どんどん本書けるマンなので

で本を出す企画があれば是非お声掛けください。
また、リアルにSNS企業で解析しているため、
事例紹介や現場で利用しやすい手法に絞った解説本なども執筆可能です。

本書くの楽しい?

ブログでいいんでない感ある。
ただ、書籍化すると普段Webではリーチしない人にも届くので、
入門書の類は書籍化したい面もあります。
専門書は普通リサーチするだろうからブログでもいいかなと思います。

どれくらい売れる見込みなの?

個人的には3000部くらい売れて欲しいという、
見込みではなく期待がある。

本書くの儲かるの?

全然。レジでも打ってたほうが儲かる。
専門書、キャッチ―ではない入門書を書くのは
社会貢献の一種だと思う。

どういう目的で書いたの?

既存の可視化周りの本を読むと、各可視化手法をカタログのように
紹介しているものがよく目につきます。
また、どの可視化手法を使うべきか、使ってはならないかについては
「各自適宜相応しいモノを適切に選択すべし」的な記述が多く、
「それを読んでも初心者は一体何が適切かわからないんだから
意味ないだろう」と憤ってました。
そういう殺意を合法的に昇華する為に書きました。

どれくらいの期間で書いたの?

300ページ弱を2か月予定という「全盛期のラノベ作家か!」
くらいのペースで書く予定だったけど最終的に3か月半くらいになった。
企画当初は類書が無かったので、品質上げるより拙速で出して、
巷に溢れる最悪な可視化を防ぐ足掛かりにしようという話をしていたが、
色々グダグダが発生して結局出版されるのが遅れ、
そのうちに類書が出たので本書の価値は半減したのは至極残念です。
学んだこととして、締切守れないケースがあるのは仕方ないけど、
伸ばすならスケジュール引き直して余裕持って伸ばすこと。
今回は締切直前になって
「1週間待って。あ、もう一週間待って。やっぱあと1か月!」
みたいな逐次延期を起こしたせいで、待ってる側は
「一週間じゃ誤字脱字修正くらいしか出来ないしなー」
みたいな感じで積極的な品質改善出来ず、
結局時間はそれなりに掛かったが品質は低いまま、
時間を有効活用できませんでしたという非常に問題ある進行になった。
締切間に合いそうになければ事前に共著者と相談しましょう、

どういう執筆分担だったの?

D3で具体的なコード書いたり可視化したりは全て森藤氏、
統計的な記述は基本的に私です。

謝辞

本書を執筆するにあたって次の方々に多大なるご協力頂きました。
本郷 豊様
春山 征吾様
山根 承子様
井戸 一二子様
市原 千里様

上記レビュアーの皆様のお蔭で
「次のようなグラフを使う奴は死ぬべきである」
「3D円グラフを殺そう!!」
とかいう記述を根こそぎ断絶し、
正気を保った文章を世に出すことが可能となりました。
本書がまともな内容になったのは皆様のお蔭です、
本当にありがとうございました。

終わりに

可視化勉強会するよ!!是非参加してね!!!
http://www.zusaar.com/event/3927003

追記

共著者の森藤氏の本書紹介です。
http://muddydixon.hatenablog.com/entry/2014/02/17/001909

追記2

本出すうえでの希望は何かあったの?

入門書である事、手に取ってもらいやすい本である事。
特に値段についてかなり気に掛けてて、
3000円以下にしたいという希望があった。
本体価格安くすると売上にも印税にも影響出るのだが、
(価格弾力性から見て安くしたからといって売上が伸びるとは思えない)
共著者も出版社も快くOKしてくださいました。
紙質がペラいとかカラーが少ないとかはご批判あるところだとは思いますが、
オールカラーにすると5000円近くになるとかいう話だったので、
構成変えてまで(個別にカラーページ挟み込むと高くて、
16ページとか32ページとか固まりでカラーページにすると安い)
値段抑えました。

どれくらいの時間で書いたの?

土日10時間ずつくらい書いて10日、合計約200時間くらい。
他細々と共著者や出版社とやりとりを15時間程度。

本書くの凄い?

凄い内容なら何に書いても凄いし
凄くない内容なら何に書いても凄くないです。

追記3

「印税50円?それアフィリエイトの方が高いじゃん…」
「なぜアフィリエイト付けないの、馬鹿なの???」
→付けました。

追記4

2/24 電子書籍版出たよー
https://gihyo.jp/dp/ebook/2014/978-4-7741-6372-7

追記5

書評頂きました!!
ありがとうございます!!
http://shimz.me/blog/d3-js/3405
良い点も悪い点も適切に取り上げて頂いて感謝しきりです。

*1:細かい話をすると、母数=パラメタの訳であるとしたとき、全数が母数になるケースもあるのですが(例えば検定で標本サイズが問題になる時など)、本書の文脈では分母というべきであります

*2:見直したら、比なのに小数点なの気持ち悪いな…