ブラウザ上でデータ分析が出来る!Clojure/Gorilla入門

f:id:AntiBayesian:20140907214031j:plain
f:id:AntiBayesian:20140907201052j:plain

概要

この記事は、Gorillaという
ブラウザ上でClojureという言語を利用出来るライブラリを利用し、
ブラウザ上でデータ分析環境を構築するための入門記事です。
Clojureの事前知識は一切不要で、
ClojureやGorillaのインストールから、ブラウザ上で各種手法を
コピペだけで実践出来るになるまでを説明しています。
なお、各種分析手法の詳細には言及しておりません。

とにかくGorillaを動かす

「説明は良いから、とにかく動かしたい」
という方向けに要点だけ説明します。

leiningenをインストールし、作業フォルダにてlein new gorillaでプロジェクトを作り、
生成されたgoraillaフォルダ直下にあるproject.cljに下記をコピペし保存、
lein gorillaと打ち込み、少し待つと
Running at http://localhost:XXXXX/worksheet.html
と表示されるので、そのURLを叩くとこんな感じのページが表示されます。
以上。

(defproject gorilla-test "0.1.0-SNAPSHOT"
  :description "A test project for Gorilla REPL."
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [incanter "1.5.5"]
                 [incanter-gorilla "0.1.0"]
                 [cc.artifice/clj-ml "0.6.0-SNAPSHOT"]
                 [org.atilika.kuromoji/kuromoji "0.7.7"]]
  :main ^:skip-aot gorilla-test.core
  :target-path "target/%s"
  :repositories [["Atilika Open Source repository" "http://www.atilika.org/nexus/content/repositories/atilika"]]
  :plugins [[lein-gorilla "0.3.3"]]
  :profiles {:uberjar {:aot :all}})

Clojure/Gorillaとは

Clojureとは、JVM上で動くプログラミング言語の一種です。
Clojureには統計解析ライブラリIncanter機械学習ライブラリclj-mlなど、
継続して開発されているデータ分析用のライブラリが用意されています。
また、同じくJVM上で動くHadoopやHBaseなどのシステムとも親和性が高く、
それらを利用して大規模なデータ分析を行うのに適しています。
しかし、Clojureをいつでもどこでも誰にでも利用して貰うためには、
各端末にJDKのインストールやパスを通すなどの環境構築が必要であり、
各種ライブラリの更新の度全端末にそれを適用し続けるのは
ハードルが高いと言わざるを得ません。
また、データを個々の端末に移動するのも非常にコストがかかります。
勿論これはClojureに限った話ではなく
他の処理系においても同じ問題ではありますが。
そこで、ブラウザ上で誰でもアクセス出来て、
直ちにデータ分析を行えるようなシステムを簡単に構築出来れば
上記のハードルをクリアできます。
つまり、誰でも色んな端末(スマホタブレットでも!)アクセス出来て、
最新のバージョンを利用したければサーバ側で更新を掛ければ済み、
データはサーバ上に置いたままなので一々解析するのに
全データをローカルに落とす必要も無く、
解析用の処理を送り結果を受け取るだけでよくなります。
そのような要望によって生み出されたのがGorillaです。
下記のGollira本家サイト、また、
GorillaにIncanterを組み込んだincanter-gorillaのサイトを
ご覧頂ければどのようなものかがご理解頂けると思います。
Gollira本家
incanter-gorilla
同様のプロジェクトはPythonやRにも存在しています。
特にIPython notebookはかなりの出来栄えですので、
特にJVM環境以外でも問題無く、
かつPythonに慣れ親しんでいる方は
そちらを利用するのも良いと思われます。

Clojureのインストール

主にWindows7向けのインストール方法について説明します。

まず最新のJavaSDK(Javaの開発環境)を入れる必要があります。
下記からご自分の端末に合わせたモノをインストールしてください。
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

次に、下記のページを参考にPath, JAVA_HOMEを設定します(windows向け)。
http://www.javadrive.jp/install/jdk/index4.html

次に、Clojureの開発ツールであるleiningenをインストールします。
公式サイトからlein.batをダウンロードして下さい。
http://leiningen.org/
(あるいはこれを利用)

最後に、パスの通っている作業フォルダ(例:c:\lein)にlein.batを移動して、
コマンドプロンプトから
lein self-install
を実行。
あとはインストール処理が自動で行われますので、終了するまで待ちます。
終了したら
lein -version
と打ち込み、2014/09/07時点では
Leiningen 2.4.3
と表示されればインストール作業終了です。

Gorillaを起動してみる

作業フォルダにて、コマンドプロンプト
lein new <プロジェクト名>
と打ち込むと新規プロジェクトを作成出来ます。
新規プロジェクトには最低限必要なファイルや設定が自動で生成されています。
ここでは
lein new gorilla
と打ち込んでみましょう。
するとgorillaというフォルダ名の直下に
project.cljというファイルが生成されています。
これはこのプロジェクトの設定ファイルです。
設定を変更する場合はこのファイルを編集します。
ここでは下記のように編集して下さい。

(defproject gorilla-test "0.1.0-SNAPSHOT"
  :description "A test project for Gorilla REPL."
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [incanter "1.5.5"]
                 [incanter-gorilla "0.1.0"]
                 [cc.artifice/clj-ml "0.6.0-SNAPSHOT"]
                 [org.atilika.kuromoji/kuromoji "0.7.7"]]
  :main ^:skip-aot gorilla-test.core
  :target-path "target/%s"
  :repositories [["Atilika Open Source repository" "http://www.atilika.org/nexus/content/repositories/atilika"]]
  :plugins [[lein-gorilla "0.3.3"]]
  :profiles {:uberjar {:aot :all}})

ここで重要なのはdependenciesとpluginsです。
dependenciesに利用するライブラリを記載します。
ここに記載されたライブラリをleiningenが
依存関係などを自動解決してインストールしてくれます。
ここではincanterとincanter-gorilla、clj-ml、そしてkuromoji*1
という形態素解析器を指定しています。
形態素解析器についてはこちらをご覧ください。
pluginsにlein-gorillaを記載し、gorillaを使えるようにしています。*2

これらが全部終わったら
lein gorilla
コマンドプロンプトに打ち込むと
Running at http://localhost:xxxxx/worksheet.html
とURLが表示されるので、そのアドレスをブラウザで見ると
Clojure実行環境が表示されます。
f:id:AntiBayesian:20140907202323j:plain

なお、アドレスのxxxxxの部分はランダムで決まりますが、ipやportを指定したい場合は
lein gorilla :ip xxxxx :port yyyyy
とします。詳細なオプションは下記に記載されています。
http://gorilla-repl.org/configuration.html

動作するか確かめてみましょう。
f:id:AntiBayesian:20140907202437j:plain
表示された画面の灰色のブロックに
(+ 1 2 3)
と打ち込み、ShiftとEnterキーを同時押しすると処理が実行されます。
実行結果が6になったら成功!
これにてGorillaの設定作業は終わりです!お疲れ様でした!

Gorillaで統計量を求めてみる

(use '(incanter core stats charts datasets)) ;統計解析ライブラリIncanterを使う指定
(def iris (get-dataset :iris)) ;サンプルデータセットの中からirisを選択し、その内容をirisに束縛
iris ;irisの中身を見てみる。
; :column-names から[:Sepal.Length :Sepal.Width :Petal.Length :Petal.Width :Species]
; という列があることが分かる。
; irisとはあやめのデータで、sepalはがく、petalは花びら、speciesはあやめの種類である
(mean ($ :Petal.Length iris)) ;花びらの長さの平均値を求める
(sd ($ :Petal.Length iris)) ;花びらの長さの標準偏差を求める

f:id:AntiBayesian:20140907202646j:plain

Gorilla上で可視化してみる

(use '(incanter core stats charts datasets))
(use 'incanter-gorilla.render) ;Incanterで可視化したモノをGorilla上で表示するライブラリを指定

(def iris (get-dataset :iris))
(chart-view (histogram :Petal.Width :data iris)) ;chart-view関数でヒストグラムをGorilla上に表示
(view (histogram :Petal.Width :data iris)) ;view関数でヒストグラムをGUIで表示

f:id:AntiBayesian:20140907202748j:plain
こちらに掲載した可視化のviewの部分を
chart-viewに置き換えれば、全てブラウザ上で実行可能です

Gorilla上で機械学習してみる

(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)))
; 決定木(c4.5)を作ってみる
(def decision-tree (-> (make-classifier :decision-tree :c45) (classifier-train iris)))
; 作成した決定木の中身を見てみます
decision-tree
;クロスバリデーションに掛けてみます
(def decision-tree-evaluation (classifier-evaluate decision-tree :cross-validation iris 10))
;クロスバリデーションの結果を確認します
(println (:summary decision-tree-evaluation))
(println (:confusion-matrix decision-tree-evaluation))

f:id:AntiBayesian:20140907203011j:plain
f:id:AntiBayesian:20140907203017j:plain
こちらに掲載した機械学習手法も
全てブラウザ上で実行可能です。RandomForestやK-meansなどもお試しください。
但し、ファイルを読み込む際、サーバ上でGorillaを立ち上げている場合はファイルパスにご注意ください。
ローカルファイル指定は自分の端末ではなくサーバ上で探索します。

Gorilla上で形態素解析してみる

(import [org.atilika.kuromoji Token Tokenizer])
(def tokenizer (.build (Tokenizer/builder)))
(defn ma [sentence] 
  (doseq [^Token token (.tokenize tokenizer sentence)] 
      (println (str (.getSurfaceForm token) "\t" (.getAllFeatures token))))) 
(ma "あきつ丸改二で大発動艇欲しい")
; (ma "あきつ丸改二で大発動艇欲しい")
; の形態素解析結果が望みの結果になってないので
; 形態素解析用の辞書を整備する必要がある

; 以下の内容を記載したファイルを用意し、適当なファイル名を付ける
; ここでは一旦userdict.txtと名付ける。
; -- ファイル内容ここから -- 
; 大発動艇,大発動艇,ダイハツドウテイ,固有名詞
; あきつ丸改二,あきつ丸 改二,アキツマル カイニ,カスタム名詞
; -- ファイル内容ここまで -- 
; 1列目:表層, 
; 2列目:1列目をどう区切るか。区切りたい位置に半角スペースを入れる
; 3列目:読み(カタカナ)
; 4列目:品詞情報
; ※windowsの場合はファイルのエンコードをSJISにする必要有り
; ファイルをc:\\lein\\gorilla\\userdict.txtに置いたとした場合、
; 以下のようにすると望みの結果が得られる。

(def dic "c:\\lein\\gorilla\\userdict.txt")
(def tokenizer (.build (.userDictionary (Tokenizer/builder) dic)))
(defn ma [sentence] 
  (doseq [^Token token (.tokenize tokenizer sentence)] 
      (println (str (.getSurfaceForm token) "\t" (.getAllFeatures token))))) 
(ma "あきつ丸改二で大発動艇欲しい")

f:id:AntiBayesian:20140907203143j:plain
f:id:AntiBayesian:20140907204502j:plain
形態素解析の結果を用いてワードカウントなどをする場合は
こちらをご覧ください。
ここで紹介している内容もブラウザ上で実行可能です。

終わりに

ブラウザ上で様々な分析が出来る便利な時代になってきました。
外出先の貧弱な端末や回線からでも、インタラクティブなデータ分析が可能になり、
例えばMTGの最中に「あのデータってどうなってるんだっけ?」
って話題に上がったその場ですぐ集計・可視化して確認出来るなど夢が広がりまくりです。

実務上データ分析しててかなり面倒だと思うのがデータサイズです。
数十GB単位になるとファイルの移動だけで面倒なことになりますし、
ローカルに持ってくるとそれだけでSSD空き容量死ぬケースがあります。

あと分析ツールの更新管理は多分皆さんが想像するのの27倍ダルいです。
一つのユースケースとして想像して欲しいのですが、
分析チームに30人くらい人がいて、
そのうちの半分がコンサルやマーケター的な方、
残り半分がエンジニアだったとしましょう。
大体前半の方々は「更新したのでアップデートしてくださーい」
とアナウンスしても、面倒なので無視します。
だって現状で使えてるもん。慣れてるのが一番だよね!
大体後半の方々は「更新したのでアップデートしてくださーい」
とアナウンスすると、既に自力拡張してるので、
それが動かなくなると嫌だから無視します。
こういう時システム提供側が取り得る選択肢は
更新しない同僚をハンマーで一人ずつ殴って回るか
あるいはブラウザで実行できるようにするかです。
非常に僅差ですが二個めの方がまだ若干マシかなと思わなくもないです。

ブラウザ上での分析環境構築は、
同時接続数とか認証周りとかにまだまだ機能不足や問題があります。
これはClojure/Gorillaだけではなく、
RのShinyやPythonのIPython notebookでも同じ問題は生じています。*3
とはいえ、ブラウザ上で分析可能なメリットは結構大きい上に、
Clojure/GorillaはJVM環境で簡単に構築できるツールなので
是非チャレンジしていきたい+皆さんもチャレンジして欲しいなと思います。
f:id:AntiBayesian:20140907214043p:plain
それでは皆様、よきGorillaライフを!!

素敵なLispエイリアンイラストをマルタコEX@marutakoEX様からお借りしました!
マルタコEX様、利用のご快諾、誠に有難うございます!!!

*1:ちなみにここで指定しているのは最新版ではありません。これは単に私が今まで利用してて動作が理解出来てるというので、今回も惰性で指定しているだけです。Lucene Kuromojiの最新版を使う方が良いです

*2:私は「何でこれがdependenciesで何でこれがpluginsなの?」っていうのがいまいちわかってないんですが、その切り分けをご存知の方いらっしゃったら教えてください…。まぁとりあえず公式サイトの指示に従って設定すれば動きます

*3:IPython notebookは一応パスワード設定出来ますが、ここでいう認証は「Aさんはこのデータとこのデータにアクセス出来て、Bさんはさらにあのデータにもアクセス出来て、あ、Cさんは異動したからこのデータへのアクセス禁止して」とかやりたいって意味です。まぁ他で認証機能別途付けろと言われたらそりゃそうなんですが

統計屋による新社会人のための統計系入門書お薦め一覧

本稿では統計学データマイニング機械学習関連書籍について

  • 内容が易しいこと。数学力(特に微積線形代数)を求められないこと
  • 入手しやすいこと。絶版や学会に入らないと入手不可などではない、値段が安いこと
  • 実務に繋げやすいこと。
  • 持ち運びしやすいこと。忙しい新社会人が通勤中や休み時間ポケットからさっと取り出し、継続して勉強出来ること

を主眼に選定したお薦め書籍を紹介します。
(満たせない要望も多いですが)

主な対象者は、文系で数学や統計学をやってこなかった、
プログラミングもわからない(Excelで四則演算やマウス操作くらいは使える)
けどいつかマーケティングやデータマイニングやってやるぜ!
って考えてる新卒の方です。

筆者自身は経済学科出身の文系で、あまり数学力に自信がないなりに
Web企業でデータマイニングをしているという人間です。

ここで紹介している内容で
統計学機械学習データマイニング
という言葉が出ていますが、ここでは

  • 統計学:分析計画を立てたりデータを要約する集計値を出したりサンプルに差や偏りがあるか検定・推定したり
  • 機械学習:データから何らかのパターンを見出して分類したりパラメタを求めたり
  • データマイニング:データに色んな手法適用してとにかく価値を得る行為全部を指す

程度に認識して下さい。

では始めましょう。

まずは勉強の前に読み物でデータ分析が
どのように実社会で使われているのかを事例を確認してみましょう。

会社を変える分析の力 (講談社現代新書)

会社を変える分析の力 (講談社現代新書)

誤解されがちなことですが、データ分析するだけでは意味はなく、
分析結果を元に何らかの改善策を生み出し、
その策を実践することによってようやく価値に繋がります。
よくある「データ分析したけど何の価値も生まなかった」という嘆きは、
本当に手元のデータの分析しかしていないケースが殆どです。
本書は「データ分析する前に、
まず必要なデータをどうやって入手するか、
データ入手するためには色んな部署の協力が必要だったりするがどうやってきたか、
分析結果を現場で活用して貰うためにはどうアプローチするか」
という泥臭いリアルな話を赤裸々に書いた名著です。
色んな分析手法やツールの使い方について学ぶことよりも、
分析から価値を得るにはどうすれば良いかを考える方が先です。
実務で分析を価値に繋げた経験を知ることが出来る本なので是非読んで頂きたいです。


なるほどー、データ分析ってこんな風に役立てればいいのかー
というのがわかったところで、統計学入門しましょう。

マンガでわかる統計学

マンガでわかる統計学

マンガでわかる統計学 回帰分析編

マンガでわかる統計学 回帰分析編

マンガでわかる統計学 因子分析編

マンガでわかる統計学 因子分析編

本書の特色はストーリー仕立てで統計学が学べることです。
統計学は多岐に渡る手法があり、各々使いどころ目的や性質が異なります。
統計学の書籍を読めば各々の手法は身につきますが、
具体的に目の前のタスクに対しどの手法をどのように適用すればよいかは
それなりの経験と手法への深い理解、そして統計学の体系的な認識が求められます。
それを独学で身につけるのは非常に困難です。
そこでお薦めなのが本書です。
この本は少女が必要に迫られて統計学を学ぶという展開で、
タスクの明示→目的の明確化→手法の紹介→分析結果の説明→結果の活用
という流れを漫画で追いかけることが出来ます。
これによりどういう時に何をすればよいかがまるで研究室の先輩から教わるように学べます。
よくある説明がだらだら続いてたまーに漫画美少女の挿絵が入るとかいうものではなく、
「なるほどー分析ってこういう流れでやればいいのかー」というのを
きちんと漫画の形式で紹介しているので、勉強するぞ!と気合いを入れることなく
とても気軽に読めます。
本書で分析の流れを掴むと良いでしょう。
このシリーズの漫画パートだけでも全部読めば分析の流れを知ることが出来ます。
出来れば全部読みましょう、最低一冊目だけでもお読み下さい。
統計手法の説明としても、まぁそんなに悪くはないです。
あとこれは文庫ではなく大版本なので持ち運びしづらいです。
薄くて軽いけど。


統計分析の実務への活用、データ分析の流れを知った所で、
今度は統計屋の心構えを学びましょう。

統計学 (サイエンス・パレット)

統計学 (サイエンス・パレット)

データ分析というと、まるで目の前にあるデータに
統計手法を適用するのが全てというような誤解されるケースもありますが、
そもそもデータは天から降ってきたり誰かが綺麗な形で
分析目的に沿うよう用意してくれるものではありません。
目的をきちんと策定し、その目的に沿ったデータを設計・実装し、
そこからようやくデータ分析に入れます。
統計屋の仕事とは、データを分析ツールに放り込むオペレータ業ではありません。
大目的(売上向上や品質改善)のために分析目的を設定し、
それを実現すべくデータを設計し、手法を選択し、分析結果を伝えることまで含みます。
とはいえデータ設計の話は非常に複雑で難解です。
本書はデータ設計の意義と初歩を簡単に紹介し、
逆にデータが不十分だとどのように困るかの説明があります。
それだけではなく、各種統計手法の概要説明も普通にわかりやすいです。
非常に完成度が高い素晴しい一冊で強くお薦めです。
とりあえずこれは読みましょう。
統計でウソをつく法―数式を使わない統計学入門 (ブルーバックス)

統計でウソをつく法―数式を使わない統計学入門 (ブルーバックス)

挑発的なタイトルですが、中身はむしろ
統計学を正しく活用するためにダメなパターンを学ぶ」
というものです。
皆さんも目にしたことがある珍妙なグラフや実感に合わない数値、
あれがどのようなトリック、あるいは分析者の錯誤により生み出されているかを
説明しています。
古い本ですが今なお統計屋の間で我が身の戒めとして愛される名著です。
集計一つするにしても繊細な注意をもってしなければ、
簡単に誤った結論を招く実例を多数紹介し、
何より最後にそのような誤った統計活用をしないようにするには
どうすれば良いかを指南しています。
受け継がれるだけのことはある内容です。
面白い読み物として肩肘張らずに読んで頂ければ幸いです。


データ分析について俯瞰する本を紹介してきました。
徐々に分析手法の詳細について説明している本の紹介に移ります。

品質管理のための統計手法 (日経文庫)

品質管理のための統計手法 (日経文庫)

この本は単純に統計手法の数理について分かり易く解説しているという面だけでも
優れていますが、品質管理入門としてもお薦めの一冊です。
品質管理は工場で不良品がどれだけ混入しているかチェックして
要求される品質水準を満たしているかなどの検証に使われる分野です。
最近データ分析と言えばWebサービスという風潮があるように見受けられますが、
遙か昔、百年以上前から工場での品質管理に統計学が用いられてきました。
品質管理には長い歴史に裏付けられた非常に高度な分析技術体系があります。
一般のWebサービスのデータ分析とは異なり
(と言ってもタスク次第であるのは勿論ですが)、
品質管理では非常に厳密な精度が求められます。
例えばWebサービスの優良顧客推定に95%の精度が得られるなら大万歳ですが、
工場から出荷される椅子や缶詰が一定品質をクリアしているかどうかの判定を
5%も失敗して不良品が混じってしまうと大問題になります。
本書はそんな品質管理に用いられる統計手法を分かり易く説明した本です。
仮にあなたがWeb企業で良くある最近の分析手法を使うにしても、
極限の精度を求める品質管理の話を知っておくのは非常に有意義でしょう。
永田先生の本は本当にどれも外れがないので、迷ったら永田本買えばいいです。

さらに統計学手法の本を。こちらは電子書籍もあって便利です。

入門 統計学 −検定から多変量解析・実験計画法まで−

入門 統計学 −検定から多変量解析・実験計画法まで−

大変わかりやすい説明で、カバー範囲も
ノンパラやクラスタ分析・主成分分析などの多変量解析まで幅広くおさえています。
最近の統計学の手法を説明する本としては一番良い出来ではないかと思います。
教科書的な統計学を体系的に一通り学んでみたいぞーって方は頑張ってコレを読みましょう。


分析結果を活かすためには、アウトプットを客に見せなければなりません。
その時誤った見せ方をしてしまえば誤った結論に陥ってしまいます。
正しいデータの可視化を学びましょう。

最初に言っておきますが、これ私が書いた本なので完全なる宣伝やで。
内容は

  • こんな可視化手法がありこういう風に使い分けるよという一覧
  • こういう可視化したら誤解を招くからしちゃダメだよという説明
  • 3D円グラフを使う奴は殺す

という感じです。
可視化は非常にインパクトが強いので扱いは繊細にならねばなりません。
同じデータでも全く違う印象を与えることが出来ます。
本書は誠実にデータを見るにはどうすれば良いか、
そもそもデータをどのように設計すれば良いか
について語っています。
ただ、統計面に関してはわかりやすく書いたつもりですが、
ぶっちゃけた話D3本として入門書かと言われると微妙に高度です…。
あと「D3で可視化?ってことは3Dグラフを
リアルタイムでぐりぐり動かすとかそういう内容なの?」
と期待された方にはご免なさい、
そういうのは一切載ってないどころか
そういうのやる奴は死ねと書いてます。
私の知る限り、本書ほど特定対象について
殺意を向けて書かれた本はありません。


ここまで頑張って読み切れば、あとは先輩や上司に付いて
色々教わるのもスムーズに行くでしょう。
お疲れ様でした。


さらに「私は機械学習までやってみたい!数学もちょっとは頑張る!!」
と意欲ある方向けに、機械学習系の理論を説明する本を紹介します。
今までは数学知識を要求されませんでしたが、
ここから先はそれなりの数学力、
微積と行列計算くらいは求められます。

フリーソフトでつくる音声認識システム - パターン認識・機械学習の初歩から対話システムまで

フリーソフトでつくる音声認識システム - パターン認識・機械学習の初歩から対話システムまで

タイトルは音声認識システムと書いていますが、
基本的な機械学習手法の説明がなされています。
まともな機械学習系の本の中では最も本書が易しいです。
機械学習入門はまずここから始めるのがよいでしょう。
説明自体も易しいのですが、実数値を使って計算の経過を
逐次実行して見せたり、ツールを使って実際の処理内容を見せたり、
理解させるために多大なる労力を払った素晴しい本です。
勿論音声認識の入門書としても、具体的なツールの使い方まで
説明しててわかりやすいです。
データマイニングと集合知 ―基礎からWeb,ソーシャルメディアまで― (未来へつなぐ デジタルシリーズ 11)

データマイニングと集合知 ―基礎からWeb,ソーシャルメディアまで― (未来へつなぐ デジタルシリーズ 11)

機械学習の各手法を俯瞰出来る入門書です。
数式も出てきますが、文章で各手法の原理や性質を説明しているため、
数学力に自信が無くても文章だけでも読んでおいた方が良いでしょう。
数式出ているとはいえ、機械学習系の手法を紹介している
書籍の中ではかなり平易に書かれています。
フリーソフトではじめる機械学習入門

フリーソフトではじめる機械学習入門

これまた機械学習の各手法を俯瞰するための入門書です。
データマイニング集合知に比べて

  • 最新のトピックスを扱っている
  • Wekaという機械学習ライブラリを用いて実際に動かせる
  • 数学的にちょっと高度

な点が違います。
どっちでも好きな方を読んで下さい。


ここまでで理論をおさえたので、
次は実際手を動かして処理する本を読みましょう。
データマイニング系で用いられるメインのツールは

などがあります。
ここではExcelでデータ分析をする本と
Rで統計解析をする本を紹介します。

知識ゼロからのExcelビジネスデータ分析入門 (ブルーバックス)

知識ゼロからのExcelビジネスデータ分析入門 (ブルーバックス)

本当に統計知識不要、それでいて実践的なマーケティング手法を紹介する本です。
Excelにはピボットテーブルという非常に強力な集計機能があります。
それを用いてデータを分析するにはどうすればいいか、
豊富な画像を用いて解説しています。
これ読むと一通りのマーケティング手法使えるようになるので中々の良書です。
これが気に入れば同著者の大判の本も読んでみると良いでしょう。
統計的な説明は一切触れてません。
EXCELマーケティングリサーチ&データ分析[ビジテク]2013/2010/2007対応

EXCELマーケティングリサーチ&データ分析[ビジテク]2013/2010/2007対応

同じくExcelでマーケティング手法利用する本です。
先程の本と違い(そこまで酷くない)最低限の統計の説明を入れています。
学んだ理論をExcelで実践する時に本書片手にやると覚えが早いでしょう。
統計学:Rを用いた入門書

統計学:Rを用いた入門書

Rで統計入門という本は結構出てるのですが、説明がやばい本結構多いです。
その点本書は統計学の説明に関してかなり良いです。
但し、Rを使いこなすぞ!という本ではありません。
Rのための本ではなく、
統計学の説明するときの処理系として
たまたまRを選んだっていう感じの本です。
Rをしっかり勉強したいという場合は別の本を読んで下さい。
データマイニング入門

データマイニング入門

Rで機械学習系のよく使われる手法を説明しています。
数式はそこそこ出てきます。
文章でもかなり説明してくれているのと、
Rで処理の動きを見ることが出来るので、
頑張れば数学力無くても各手法がどのような特性あるか把握出来ると思います。


「入門者が春に読む本」って話なら上記まで読めれば大変素晴しいと思います。
世の中には「いやいや実務ではもっと高度な手法を使うよプゲラ」
とか言ってくる人も居るでしょうが、焦らず基礎を積みましょう。
人生は長い。

余力がある、数学力に自信があるという方には
更に発展的な本として次を挙げておきます。

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

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

自然言語処理で用いられる機械学習手法に絞った解説書です。
と言っても自然言語処理の部分は僅かで、
真っ当な機械学習入門書として読めばよいでしょう。
機械学習で独学しづらい部分をピンポイントで解説している素晴しい本です。
これが出るまでは広範な数学力がある人か
先輩や先生が教えてくれるような環境を持ってないと
理解出来なかった部分もありました。
本書は個人的に人生を変えた本で、
コレがないと私は挫折して今機械学習やってなかったと思います。
これ読んで線形代数の本読み切ればPRMLという
機械学習系のバイブル的な本に進めると思います。


もっと高度なことをやりたいぞ!
と思ったら、最終的には数学力が必要になるときもあるでしょう。
具体的には微積分、線形代数、確率論あたりを押えておくと良いです。
特に線形代数をきちんとやっておかないと割と早い内に詰まります。
下記の本をお薦めします

統計学のための数学入門30講 (科学のことばとしての数学)

統計学のための数学入門30講 (科学のことばとしての数学)

統計的データ解析入門 線形代数

統計的データ解析入門 線形代数

キーポイント線形代数 (理工系数学のキーポイント 2)

キーポイント線形代数 (理工系数学のキーポイント 2)

はじめてのルベーグ積分

はじめてのルベーグ積分

上二冊は統計学で必要な部分だけに話題を絞った
独学の最短ルートを提供してくれる有り難い本です。
私も大変お世話になりました。
更にキーポイント線形代数まで読んで
言語処理のための機械学習入門読み切れば
相当数の論文を読むことが出来るでしょう。
最後のルベーグ積分は必須ではありません。
ただ、あなたが分析経験を積み、確率論が必要になった、
あるいは確率論に興味が出て学び始めた時、
手強い壁として立ちはだかるのがルベーグ積分でしょう。
本書はルベーグ積分本の中で一際易しい本です。
とは言え十分難しい内容です。
どうしても確率論に真正面からぶつからないといけなくなったときに
本書を参照すると良いでしょう。
余力があれば是非読んでおいて下さい。


最後に、統計学の手法ではなく、
統計学の歴史や哲学について書かれた本を紹介します。
なぜ統計学史や哲学について知るべきなのか?
それは、数々の統計手法はどのような要望で生まれたのか
という背景を知ることが、数式から手法の挙動を読み解くのと
同じくらい価値あることだからです。

統計学を拓いた異才たち(日経ビジネス人文庫)

統計学を拓いた異才たち(日経ビジネス人文庫)

科学と証拠-統計の哲学 入門-

科学と証拠-統計の哲学 入門-

上記2冊は統計学史と統計哲学の入門書です。
たまに数式も出てきますが、基本的に読み物です。
統計学者達の意見の対立の話も出てきます。
実際皆さんがデータ分析をするにあたって、
同僚と手法やデータの扱いについて意見が異なるかも知れません。
データ分析は何を一番大切にし何を懸念しているか、
一言で言えば立場によって用いる手法やデータが異なります。
過去の統計学の異才たちがどのような意見相違をしたか知ることで
己の統計屋としての哲学を確立していきましょう。


皆さんが良き統計屋になれますよう、心から願っております。

良き統計屋とは3D円グラフを使ってるプレゼンターを
その場で殴りに行く人のことです。
質疑応答の際、司会者からマイクを奪ってあらん限りの数学力で殴りましょう。

テキストマイニングのための機械学習超入門 二夜目 パーセプトロン

 一夜目はパターン認識と機械学習の概要を学びました。今夜は、識別部で用いられる機械学習の基本的な線形識別器である「パーセプトロン」を具体的に学びたいと思います。「線形識別器?パーセプトロン?何それ?」字面は厳しいですが、手を動かしてみると意外と簡単に理解できます。今夜からは数式をバリバリ使っていきますし、手を動かしていただきます。「必ず」手元にペンと紙を用意してください。そうは言ってもパーセプトロンが一体何なのか、機械学習の中でどのような位置づけなのかがわからないと混乱するかもしれません。パーセプトロンの説明へ入る前に、機械学習の3つのアプローチをご紹介します。


機械学習の3つのアプローチ - 識別関数、識別モデル、生成モデル
 機械学習は大きく分けて識別関数、識別モデル、生成モデルという3つのアプローチがあります。

  • 識別関数 := 入力データを見て、特定のクラスに属するよう識別(代表的な手法:パーセプトロンニューラルネットワークサポートベクターマシン
  • 識別モデル := 入力データからクラス事後確率をモデル化して識別(代表的な手法:CRF)
  • 生成モデル := 入力データがどのような分布で生成されたものかをモデル化して識別(代表的な手法:ナイーブベイズ)

 前夜学んだ最近傍決定則はデータから直接属するクラスを見つけたので、識別関数です。識別モデルと生成モデルが分かりにくいですね。ここでは識別関数と生成モデルの違いを、昨夜の例を用いて説明します。特徴空間がX=(サッカー、野球、政治、選挙)であり、Aさんが100単語発したある時の特徴ベクトルがX_A(50, 30, 15, 5)だとします。この場合、識別関数では、単に「サッカーという単語が出現した回数は50回である」とだけ考えます。対して、生成モデルでは「Aさんは特徴空間Xにおいて、サッカーという単語が出現したのは100回中50回なので、サッカーの出現確率は0.5だ」というように確率分布まで考えます。前者は、Aさんがさらに100単語発したときサッカーが何回出現するかを全く考慮していません。後者は、Aさんがさらに100単語発するなら、サッカーは50回程度出現するだろう」と考えます。「生成モデル」という名が表すように、「どのような確率分布でデータが生成されたのか?」というモデルを立てて識別するため、単に実際観測されたデータだけではなく、データが観測された背景まで考慮するので、データに欠損がある場合など、識別に有利に働く場合があります。ただし、非常に理論が複雑だったり、データに対し確率論の適用が必要になったりと、良いこと尽くめではありません。また、生成モデルが識別関数より一般的に精度が高いというわけでもありません。現実問題として、実務で用いられる機械学習の大半が識別関数です*1
 最近は異なるアプローチを混ぜて識別する先進的な手法を取ることもよくありますし、そこまで厳密に区別する必要はありません。ただ、アプローチが違うということは、識別の基となっている考え方そのものが違うということだけは念頭に置いてください*2


●線形識別器
 識別するとはどういうことでしょうか。以下、簡単のため、2クラスの識別問題について考えていきます。昨夜の最近傍決定則では、入力データは最も近いプロトタイプのクラスに属するとして識別を行いました。図で考えてみましょう。図1をご覧ください。


図1

青クラスを代表する青プロトタイプと赤クラスを代表する赤プロトタイプ、両プロトタイプから等距離に引かれた緑の直線を描きました。この緑の直線は各プロトタイプから等距離にあるため、この線より青プロトタイプに近ければ青クラス、赤プロトタイプに近ければ赤クラスだと考えること出来ます。
 このように、入力データを各クラスに識別するような直線を超平面(あるいは決定境界や識別面)といいます*3。つまり、識別する=超平面を求めることです。そして、超平面を求めるとは、正しいプロトタイプを適切に設定するということでもあります。なぜなら、ここでいう超平面とは各プロトタイプから等距離に位置するものだからです*4。また、このように超平面で完全にクラスを分離出来る場合を「線形分離可能である」といいます。図2のように直線で分離出来ないような場合を非線形分離といいます。


図2

 線形の超平面を求めるアルゴリズムの総称を線形識別器(あるいは分類器)といいます。どのようにして線形識別器は超平面を求めるのでしょうか?次からは線形識別器の一つであるパーセプトロンの中身を学びましょう。


パーセプトロンの概要
 パーセプトロンは識別関数に属する線形識別器の一種です。基本的な概念はとても簡単で、ニューラルネットワークサポートベクターマシン(以下SVM)など数ある識別関数の基礎中の基礎でもあり、非常に重要です。基礎と初歩は全く異なります。パーセプトロンが必ずしも他の手法より精度が低いというわけではありません。様々な拡張性に富み、最近必須と言っても良いオンライン学習として活用することが出来ます*5
 まずはパーセプトロンのイメージ大雑把に掴んでみましょう。図3をご覧ください(図2では青丸が青プロトタイプでしたが、今度は青丸=青学習データだと考えてください。赤丸も同様)。


図3

各クラスを分離するような超平面(緑の点線)を適当に作ります。適当なので、図にあるように誤識別してしまいます。誤識別してしまった場合は、正しく識別できるように超平面を正しい方向に少しずつ修正します(図3の黒矢印の方向に)。それを何度も繰り返して、最終的に全データを正しく識別出来る黄点線のような超平面を求めます。これがパーセプトロンの処理の流れです。誤識別したとき、正しい方向に修正することを「学習する」といいます。
 パーセプトロンの処理は、まとめると1.最初の超平面は適当に決める、2.識別関数が誤識別したときに学習する、3.2を何度も繰り返す、の3点です。特に2の学習部分が肝心です。


●識別関数
 先ほど「誤識別したときに学習を行う」と説明しました。なので、学習する前に識別をしなければなりません。識別とは、対象の学習データに対して、最も近いプロトタイプがどれかを判定することです。ではどうやって識別すれば良いのでしょうか。識別を実現する関数、その名も識別関数を作りましょう。
 学習データxからプロトタイプpまでの距離を||x-p||と表現します。二次元(横軸位置、縦軸位置)で考えてみましょう。数学的に、二点間の距離とは、二点の座標成分の差の絶対値を意味します。xが(3, 4)、pが(6,2)だった場合、||x-p||は(3-6, 4- 2) = ||(-3, 2)|| = ||(3, 2)||*6となります。これで学習データxとプロトタイプpの距離を表現することが出来ました。
 ですが、プロトタイプは一つではなく、クラスの数だけあります。学習データと複数のプロトタイプの距離を表現するにはどうすればよいでしょうか。二値分類(データを二つのクラスに分類)する場合は二つのプロトタイプ、百のクラスに分類する場合は百のプロトタイプが存在します。そこでプロトタイプをp_i i = 1, 2, ... , nと表現します。p_iはn個あるプロトタイプのうち、i番目のプロトタイプを指します。そしてi番目のiは1からn個まで存在します。プロトタイプが2つならp_1, p_2と表現できます。これを利用し、学習データxと各プロトタイプp_iを||x - p_i||と表現することが出来ます。
 これで学習データと各プロトタイプとの距離を表現することが出来ました…が、やりたかったことは、最も近いプロトタイプがどれかを判定することでしたね。そこで最も近いプロトタイプを arg_i min ||x - p_i||のように表現します。minはminimum(最小)の略で、minの右の項の中で最小のものを選択するという意味です。ここでは最小の距離を取得します。しかし本当に欲しかったのは、最小の距離ではなく、最小の距離のプロトタイプです。argはargument(引数)の略で、指定した引数の値を返すという意味です。ここでは引数にiを指定しているため、argの右項の条件を満たすiを取得します。つまり、「学習データとn個あるプロトタイプとの距離を一つ一つ調べて、その中でも最小の距離になるようなi番目のプロトタイプを取得する」という意味になります。たった一行の数式に沢山の意味が詰まってますね。
 対象の学習データに対して、最も近いプロトタイプがどれかを表現することが出来、ようやく識別関数を作る準備が整いました。識別関数を作るのにも色々な種類がありますが、ここでは一番シンプルな最小二乗法を用います*7。最小二乗法は、その名のとおり、距離を二乗して、その中でも学習データとの距離が最小になるプロトタイプを選択します。距離を||x - p||と表現したので、その二乗は||x - p||^2です。これを展開すると||x||^2 - 2p_ix + ||p_i||^2となります*8。この距離の式を最小にするようなプロトタイプを求めることが、識別関数のそもそもの目的でした。ということはこの式に全プロトタイプを当てはめて、距離が最小になるものを選択するわけですが、どのプロトタイプに対しても、||x||^2の部分は全く変更がありません。対象とする学習データxは固定で、プロトタイプだけ入れ替えているからです。つまり、 arg_i min ||x||^2 - 2p_ix + ||p_i||^2 arg_i min - 2p_ix + ||p_i||^2で選出されるプロトタイプは同じ結果になります。同じ結果になるなら、簡単のため、  arg_i min - 2p_ix + ||p_i||^2を利用しましょう。無駄な計算を省略することで、実際解析する際の高速化が望めます。さらにいうと、  - 2p_ix + ||p_i||^2という式の全ての項を定数倍しても結果は変わりません。後々計算しやすいよう、全体に\frac{1}{2}を掛けて -p_ix + \frac{1}{2} ||p_i||^2としておきます*9。そしてさらに計算の都合上、全体に-1を掛けて、符号を逆転させます。そうすることによって、最小化問題を最大化問題に変更することが出来ます*10(このへんの操作は、計算の都合上の話であり、パーセプトロンのロジックの本質的なことではありませんが、こうやると後々実際計算するとき非常に楽になるので、ちょっと頑張って読んでください)。これを識別関数  g(x) := p_ix - \frac{1}{2} ||p_i||^2であると定義します。そしてこの識別関数の値を最大にするプロトタイプが、学習データに最も近いプロトタイプです。
 随分時間がかかりましたが、ようやく識別関数を作ることが出来ました。いよいよ学習部分に入ります。
 

パーセプトロンの学習規則
 学習するとは、識別関数が誤識別した際、超平面を正しく修正することです。超平面の修正方法は二つあります。一つ目は図3のように超平面を回転させること、二つ目は図4のように超平面を移動させることです。


図4

適当に回転・移動させるだけではなく、正しい回転量・移動量を求める必要もあります。これを実現するにはどうすればいいでしょうか。
 超平面は各プロトタイプから等距離に位置すると説明しました。ということは、超平面の位置や向きはプロトタイプに依存しており、プロトタイプを上手く調整すると、正しい超平面を得られそうです。また、学習は誤識別したときに行います。誤識別するということは、識別関数が対象としている学習データとこれまでのプロトタイプからでは、最も近いプロトタイプがどれかを誤って判定してしまうということです。以上のことから、誤識別した学習データを利用してプロトタイプを移動させれば良さそうですね。直感的にも、図3や図4のように、誤識別した学習データを正しいクラスに識別できるよう超平面を引き直せばよいわけですから、学習には今の超平面(を形成するプロトタイプ)と誤識別した学習データを何らかの形で組みあわせる必要があるとわかります。
 誤識別した学習データに応じてどの程度現在の超平面を回転・移動させるかを求めるため、「重み」という概念を利用します。誤識別した学習データに重みを掛け、その値の分だけ超平面を回転・移動させます。重みベクトルwをプロトタイプpを用いて、識別関数  g(x) := p_ix - \frac{1}{2} ||p_i||^2から次のように表現します。

w_{ij} = p_{ij}
w_{i0} = - \frac{1}{2}||p||^2

p_{ij}のiとはプロトタイプが何番目かというインデックス、jはそのプロトタイプの要素j番目のインデックスです。二次元の場合、プロトタイプは縦軸と横軸の位置情報を持つため、p = (横軸の位置、縦軸の位置)と二つの変数を持っています。この時、例えばp_{32}は、3番目のプロトタイプの2番目の要素(縦軸の位置情報)であるという意味です。つまり、重みwはプロトタイプとバイアスw_{i0}という情報をひっくるめた概念です。
 さて、超平面における重みと何やら突然出てきた感のあるバイアス項の意味を二次元平面上で考えてみましょう。二次元では、超平面とは平面を横切る直線になります。例えばy = αx + β (α > 0)という式は、右上がりの直線が平面を二分割します。この式のαが重み、 βという切片に当たるのがバイアスです。ここでαを1、βを0として直線を描くと、原点を通り、45度で平面を二分割する直線が描けますね。αを2にしてみると、傾きが急になり、半時計回りに直線が回転しますね。αを変更すると直線が回転する、そして「α=重み」かつ「直線=超平面」なので、「重みを変更する=超平面を回転させる」という意味になります。また、βを0から1にすると、直線が上に移動しますね。ここで、「β=バイアス」なので、「バイアスを変更する=超平面を移動させる」という意味になります。これで重みとバイアス項が超平面に対してどのような働きをするのかがわかりました。
 超平面を正しく引くには、重みとバイアスを変更する必要があることがわかりました。ではどのように変更させればよいでしょうか。学習の具体的な更新式は次のようになります。

w' = w + ρ * x * L

ここでρは学習係数といい、重みに対して一回の学習がどの程度影響をするかを表します。あまりに小さすぎると収束まで時間がかかりますし、あまりに大きすぎるとぴったりの重みに収束しないケースが出てきます。ρの値の決め方は色々あり、また、ρを可変にして、学習回数が増加する度ρを小さくするアルゴリズムなどもあります。実用上、このρの値によって収束速度がかなりかわってくるため、徐々にρを小さくするアルゴリズムを採用するのが良いでしょう。Lは分類するクラスのラベルです。二値分類の場合、クラスのラベルを+1, -1として分類することが多く、こうすると計算上便利です。図3のように青赤クラス分類をする場合、青クラスを-1、赤クラスを+1とラベリングしておけば、青クラスの学習データを赤クラスだと誤識別したとき、超平面を半時計回りに回転させるように更新式に応じて重みを修正します。
 更新式、とてもシンプルですね。つまり、更新とは、元の重みに対し、学習係数と誤識別した対象の学習データ掛け合わせたものを引くというだけです。そうして新しく得た重みで再度識別関数の用い、識別を行います。これを全学習データ分繰り返し、誤識別が一つもなくなったら学習終了です。
 ここで、「全学習データに対して誤識別が一つもなければ学習終了?ということは誤識別してしまうような、線形分離不可能な場合はいつまでも収束しないの?」という疑問が生まれます。実際その通りで、収束しません。ではどうするか?あるデータに対して誤識別する上限回数は決まっているという、パーセプトロン収束定理というものがあります。この定理に基づき、上限回数を超えて収束しない場合はそこで学習を打ち切るなどします。ただ、実務上、「単に収束までの時間が掛かりすぎているのか、収束しないのか」の判断を分析前に知ることはまず不可能なため、事前に何回試行すればそこで打ち切りとするのが殆どです。
 これでパーセプトロンの説明は終わりです。では、実践に入りましょう。


●人力パーセプトロン
 実際手を動かして、パーセプトロンの挙動を確認しましょう。さーて、ここからが凄く面白いところなので、必ずペンと紙を用意して読んでください。
 例題:学習データがx = (5, 1, 4, 2)の4つで、C1 = (5, 4)、c2 = (2, 1)というクラスに属するときの超平面を求めよ。
要するに、一次元のデータ1, 2, 4, 5があり、1, 2と4, 5を分割するような超平面を求めればいいわけですね。直感的に、超平面は3を通りそうですね。
まず、各データのバイアス項を1と適当に決め*11ます。すると先程の学習データは次のように表現出来ます。
x1 = (1, 5)
x2 = (1, 2)
x3 = (1, 4)
x4 = (1, 1)
次に重みの初期値を適当に決めます。ここではw0 = 0, w1 = 0とします。また、識別関数に学習データを放り込んだ結果が≧0ならC1に、<0ならC2に識別するとします。本当なら、どの学習データを識別関数に放り込んで学習するかはランダムに決めるのですが、手作業でランダム選択は難しいので、便宜上1〜4まで順番に処理していきたいと思います。え、そんなことで良いのかって?それはやってみれば解ります:D。学習係数は1とこれも適当に決めておきます。え、これもそんな適当に決めていいのかって?それもやってみると解ります、楽しみにして下さい:D。二値分類なので、C1の方のラベルを+1、C2を-1にしておきましょう(逆でも良い)。
さぁ、下準備は終わりました。では実際学習していきましょう。まずx1を識別関数g(x)に掛けてみます。x1 = (1, 5)でw = (w0, w1) = (0, 0)なので、g(x) = 1 * 0 + 5 * 0 = 0となり、正しくC1に識別されました。ではC2に取りかかりましょう。x2 = (1, 2)、w = (0, 0)なので、g(x) = (1 * 0 + 2 * 0) = 0となり、x2はC2の筈なのにC1に識別されてしまいました。誤識別が発生したので学習します。学習データx2と現在の重みwを更新式"w' = w + ρ * x * L"に放り込むと、
w0' = 0 + 1 * 1 * -1 = -1
w1' = 0 + 1 * 2 * -1 = -2
となり、新しい重みがw' = (-1, -2)になりました。この新しい重みで次の学習データを識別します。x3 = (1, 4)、w =(-1, -2)なので、g(x) =1 * -1 + 4 * -2 = -9となり、x3はC1の筈なのにC2であると誤識別されました。再度学習しましょう。
w0' = -1 + 1 * 1 * 1 = 0
w1' = -2 + 1 * 4 * 1 = 2
で。新しい重みはw' = (0, 2)となりました。続けましょう。x4 = (1, 1)、w = (0, 2)→g(x) = 1 * 0 + 1 * 2 = 2なので誤識別。
w0' = 0 + 1 * 1 * -1 = -1
w1' = 2 + 1 * 1 * -1 = 1
また最初の学習データに戻って同じ事を誤識別が発生しないようになるまで繰り返します。x1 =(1, 5)、w = (-1, 1)→g(x) = 1 * -1 + 5 * 1 = 4。正しく識別されました。x2 = (1, 2)、w = (-1, 1)なので、g(x) = (1 * -1 + 2 * 1) = 1なので再度学習。
w0' = -1 + 1 * 1 * -1 = -2
w1' = 1 + 1 * 1 * -1 = 0
x3 = (1, 4)、w =(-2, 0)なので、g(x) =1 * -2 + 4 * 0 = -2なので再度学習。
w0' = -2 + 1 * 1 * 1 = -1
w1' = 0 + 1 * 4 * 1 = 4
x4 = (1, 1)、w = (-1, 4)→g(x) = 1 * -1 + 1 * 4 = 3なので再度学習。
w0' = -1 + 1 * 1 * -1 = -2
w1' = 4 + 1 * 1 * -1 = 3



どうしよう、大変辛くなってきた… :(




気を取り直して頑張りましょう :)
またまた最初の学習データに戻って同じ事を誤識別が発生しないようになるまで繰り返します。x1 =(1, 5)、w = (-2, 3)→g(x) = 1 * -2 + 5 * 3 = 13。正しく識別されました。x2 = (1, 2)、w = (-2, 3)なので、g(x) = (1 * -2 + 2 * 3) = 4なので再度学習。
w0' = -2 + 1 * 1 * -1 = -3
w1' = 3 + 1 * 2 * -1 = 1
x3 = (1, 4)、w =(-3, 1)なので、g(x) =1 * -3 + 4 * 1 = 1なので正しく識別されました。
x4 = (1, 1)、w = (-3, 1)→g(x) = 1 * -3 + 1 * 1 = -2なので正しく識別されました。


またまたまた最初の学習データに戻って同じ事を誤識別が発生しないようになるまで繰り返します。x1 =(1, 5)、w = (-3, 1)→g(x) = 1 * -3 + 5 * 1 = 2。正しく識別されました。x2 = (1, 2)、w = (-3, 1)なので、g(x) = (1 * -3 + 2 * 1) = -1なので正しく識別されました。
おや、x3, x4は先程この重みで正しく識別されると言う事を確認しましたね。ということで、全データに対して重みw =(-3, 1)は正しい識別を提供するようです。実際紙に描いて確認してみましょう。二次元座標を描いてみて下さい。一次元の学習データが1, 2, 4, 5なので、横軸の数直線に1, 2, 4, 5と描きます。それに超平面(二次元なのでここでは直線)y = x - 3を引きましょう。すると綺麗にデータを二分割する直線になりましたね。やった!成功です!
あー、長かった…。
これで要領は掴めたと思います。次に、学習データの並びを変更してみたり(今は各クラスのデータが交互に出現しましたが、クラス毎に偏って出現するなど)、学習係数を学習データに対して大きく、あるいは小さく設定してみたりしましょう。是非手計算してみて下さい。

 わかったことをまとめましょう。

  1. 学習係数ρが大きすぎると収束しない。かといってρが小さ過ぎると収束まで時間がかかる
  2. 逐次学習であるため、全く同じデータでも、入力順が異なると、異なる超平面を形成する(だから学習データをランダムに選択する必要が有るわけですね)。超平面は一つではない。先程の例だとy = x - 3になったが、例えばy = 1.5x - 2.5でもきちんと分割できる。線を描き込んで確かめて下さい
  3. 1次元でデータ数4個という非常の小規模な学習でも、収束までそれなりの試行回数が必要。実際の分析では高次元大量データを扱うことになるので、反復数はとんでもないことになる。そのため、一回一回の計算をほんの少しでも高速化出来れば、全体的にかなり改善される

 お疲れ様でした。パーセプトロン、理屈は割と簡単でしたね。しかし、実際手を動かして処理を追うことにより、識別器の動きが肌で理解できたのではないかと思います。パーセプトロンは実装も簡単ですので、是非チャレンジしてみてください。


▲追記
パーセプトロンの説明記事を書きます」と言ったらさくさくテキストマイニング勉強会のアイドルtorotoki君がPython実装してくれました。是非御覧下さい。
Pythonパーセプトロンを実装した」 http://eaqule.com/blog/python/perseptron-with-python/

*1:素晴らしい記事なので、是非ご一読頂きたい "機械学習超入門 〜そろそろナイーブベイズについてひとこと言っておくか〜" http://d.hatena.ne.jp/echizen_tm/20110114/1295030258

*2:もっと詳しく知りたい方は、パターン認識と機械学習(上)1.5.4に書いてありますのでご参照下さい

*3:超平面と言いつつ、この図では二次元に引かれた直線なので「なんで超『平面』なの?」と疑問に思われるかもしれませんが、一般に特徴空間は高次元であるため、直線の場合も平面の場合も総称して超平面といいます

*4:本当はちょっと違いますが簡単のために…。学習データと超平面との距離をマージンといいます。パーセプトロンにはマージンを最大化するように学習するマージン最大化学習や、パッシブアグレッシブパーセプトロンではある程度の誤識別を許容するソフトマージンという手法などもあり、また、この例で言うと、青クラスのマージンと赤クラスのマージンを非対称に設定する場合もあります。例えば、健康診断で癌の識別をする際、百歩譲って癌でもないのに癌だと診断されても再診断を受けるだけで話は済みますが、癌なのに癌でないと診断されてしまうと取り返しのつかないことになってしまいます。なのでがんではないと判定するマージンを大きく取る、つまり癌ではないと誤識別しにくいようにマージンを設定するということもあります

*5:ぶっちゃけた話をすると、大抵の分類問題はパーセプトロンで何とかなりますし、パーセプトロンわからないと他の識別関数もほぼ全部理解できないと思います。それくらい滅茶苦茶重要です

*6:絶対値とは、数の大きさだけを考えて、符号は考えないことです。例えば|-3| = |3|となります。xの絶対値を表現する記号は|x|、xの距離を表現する記号は||x||となります。混同しないよう注意してください

*7:参照 http://ibisforest.org/index.php?%E6%9C%80%E5%B0%8F2%E4%B9%97%E6%B3%95 ちなみに、最小二乗法はシンプルかつ理論上正規分布最尤推定になっているなどのメリット(?)もありますが、実際使うと、外れ値に弱かったり、データ数の多いクラスに超平面が吸い寄せられるなど癖があってあまりお薦めできません。もうちょっと詳しく知りたい方は、わかりやすいパターン認識9章、あるいはパターン認識と機械学習4.1.3などをご参照下さい

*8:すみません、誤魔化しています。pもxもベクトルなので、本当なら[tex:2p_i]の右肩に転置を意味するtが乗ります。ただ、それを言い出すと簡単な線形代数の知識が必要になるので、また後日ということで…

*9:xで微分するとき、分数が消えて式がスマートになりますね:D

*10:[-xを最小化する = +xを最大化する]です。xに具体的な数値を当てはめて考えてみましょう

*11:0.1でも3でも構いません。よく1が使われます。極端な値でなければ、バイアス項も適宜学習されていくで問題有りません

テキストマイニングのための機械学習超入門 一夜目

 テキストマイニングに必要なパターン認識と機械学習について学びます。非常に初歩的な話から始めます。対象者は「テキストマイニングに興味があり、用いられる手法の中身を知りたい(けれど高度な数学は厳しい…)」というビジネスマンや学生さんです。数式は出来る限り「使います」。使わないと意味するところは理解できません。ただし、愚直に数式の一行一行を手計算で順を追って解いていきますし、必要な数学知識はその都度説明し、前提知識は求めませんので「数式出てくるの?じゃあついていけないのでは…」という心配は不要です。この記事の特徴は「機械学習の手法をやたら冗長な数式と過剰なまでの例を用いて、くどくどと同じ話を何度も説明する」ことです。


 筆者ことあんちべは純文系出身で、数学や統計学、プログラミングは全然学生時代やってこなかった上、業務でも機械学習を使うことなんて皆無、それどころか機械学習なんて言葉は就職してからようやく知った…という超ド素人です。それ故、自然言語処理のプロの方がお勧めしてくださる専門書籍や論文は難しくて全く読めず、かと言ってテキストマイニングのビジネス読み物では業務で活かすレベルには達せず、仕方なく高校生レベルの数学書から2年かけてちょっとずつ勉強してきました。そんな私が、今まで勉強してきたことをまとめるために記事を書くので、ひたすら冗長ですが、その分専門書籍によくある「式aを展開すると式bになる、自明である」のような「え、これ何をどうすればaからbに変形出来るの???」というジャンプを皆無にしたいと思っています。何か不明な点があればご質問ください。


 以下三冊(難易度順)を教科書として利用します。

  1. フリーソフトでつくる音声認識システム
  2. わかりやすいパターン認識
  3. 言語処理のための機械学習入門

この三冊は非常に分かりやすく、また、必要な数学は付録で説明されているため、事前知識はほとんど必要ありません(行列式偏微分くらいはわかってないと辛いですが…)。副読本として「パターン認識と機械学習」を挙げておきます。辞書がわりに使います。この記事の目標は、

  1. 言語処理のための機械学習入門の内容を理解できること
  2. パーセプトロン、ナイーブベイズ、k-meansクラスタリング程度の機械学習の基礎的な手法を実装できるようになること

です。何日かかるかわかりませんが、頑張りましょう。


 さて、そろそろパターン認識と機械学習の勉強を始めましょう。と、その前に。そもそも「パターン認識と機械学習*1とは何でしょうか?何やらテキストマイニング自然言語処理で必須らしいのですが、それの意味するところとは?教科書の定義を読んでみると、まず、パターン認識とは「観測されたパターンを特定の概念(クラスやカテゴリという)に対応させること」だそうです。…ちょっと分かりづらいですね。例を考えてみましょう。あなたが家に入ると、キッチンからスパイシーな香りが漂ってきたとしましょう。また、テーブルの上には近所のスーパーで人参やジャガイモを買ったレシートが置いてあったとします。あなたはこの二つの事実から、「今夜はカレーだな」と思いました。まとめると、「嗅覚的パターンの特徴:=キッチンからスパイシーな匂いがする」、「視覚的パターンの特徴:=人参やジャガイモを買ったレシート」という二つの観測パターンから「今晩はカレーだな」というように料理のクラスを導いたのです。もし、ツンとくる酸の匂いと沢山の刺身のレシートを観測したら「今夜はお寿司だな」と料理のクラスを認識できそうですね。このように、人間には観察されたパターンから、ある特定のクラスを認識することが可能です。これをパターン認識といいます。そして、テキストマイニングでいうところのパターン認識は、人間が行うパターン認識を機械にやってもらうことです。機械にパターン認識をしてもらえば、人間がやるよりも大量かつ高速、しかも安価にデータを処理することが出来て、人間は大変楽になります。では、パターン認識をどのようにテキストマイニングに活用するのでしょうか?例えばメールのスパム判定があります。人間が見ると、スパムメールかどうかはかなり高精度に認識できますね。しかし、人手でスパムメールと大切なメールを分類するのは面倒です。機械にスパムメールを認識する能力を持たせ、振り分け作業を任せて楽をしましょう。

 ここで一つの疑問が生まれます。「機械に人間がやるような認識能力を持たせて仕事をしてもらうのってAI(人工知能)では?」確かにそうですね。どこからどこまでが人工知能分野、パターン認識分野かは専門家でも意見はまちまちだったりします。大雑把な指針として、AIとパターン認識の違いは、

  • 人工知能:人間がする判断を「人間がするように」機械にもやらせる
  • パターン認識:人間がする判断を「機械がやりやすいように」機械にやらせる

ことです。これは「鳥のように空を飛びたい!」という欲求に対し、

  • 人工知能:鳥を模倣して羽ばたいて飛ぶ
  • パターン認識:ジェットやプロペラを作って飛ぶ

という違いです。人間や知能/知性そのものを作ることを目指すか、それらが持つ能力を作ることを目指すかの違いと言ってもいいでしょう。



●パターン認識の手順
 パターン認識がどのようなものなのか、その概要が掴めたところで、実際どのように実行するのかを追っていきましょう。次のような手順でパターン認識を進めていきます。

パターン→前処理部→特徴抽出部→識別部(識別辞書)→識別結果出力部

特徴抽出など、あまり日常では聞きなれない単語が出てきましたね。OCR(文字認識)を例にとってパターン認識の手順を考えていきましょう。OCRの場合、パターンに該当するのは手書き/印刷文字といったデータです。「前処理部」はパターンをスキャナやカメラで画像取り込みする処理です。「特徴抽出部」は文字を識別するのに役立つ特徴を抽出(=言い換えると、役に立たないデータを捨てる。例えば、文字色は、読み込んだ文字を特定するのに役立たないので捨てる)する処理です。「識別部」は読み込んだ画像の特徴と辞書の情報を比較し、最も当てはまりのよい文字を識別する処理です。「識別結果出力部」では、識別部で得られた識別結果を、ユーザーの役に立つように出力する、つまり読み込んだ文字画像に該当する文字列を出力する処理です。パターンと前処理部、識別結果出力部はまだわかりますが、特徴抽出部と識別部の処理がよくわかりませんね。ここを詳細に見ていきましょう。


●特徴抽出部とは
 パターンがどんなクラスに属するかを認識するためには、各パターンの特徴を掴む必要があります。適切な特徴を掴むことが出来れば、上手くクラスを識別することが可能になります。逆に言うと、どんなに(後で登場する)識別部で頑張っても、特徴をつかめなければ識別が上手くいきません。特徴抽出は非常に重要です。
 例として、料理を識別するにはどんな特徴を把握することが必要でしょうか?食材の種類?材料費?調理器具?色々考えることができそうですね。材料費が10万円もかかっているのに、出来た料理が目玉焼きということは恐らく無いでしょう。同じく、調理器具として土鍋を使っているのに、出来た料理が目玉焼きということもまず無いでしょう。このように、材料費や調理器具という特徴を使えば、ある程度料理を識別しやすくなるかもしれません。しかし、材料費や調理器具で料理を識別することは一般的にかなり難しいでしょう。それよりも食材を知ったほうが識別しやすそうですね。なので、料理を識別する場合は、食材の方が調理費用や器具よりも適切な特徴と言えます。あまり識別に有用でない特徴をデータとしてもたせると、計算量が増えてしまい、計算時間が伸びたり、認識精度が悪くなったりします。適切な特徴を選択するよう心掛けねばなりません(具体的にどう選択するかはまた後日)。


 さて、そろそろ数式っぽいものが登場します:D。特徴抽出部とはどのようなものなのか、教科書を参照してみましょう。

パターンからd個の特徴を抽出した場合、それをd次元のベクトルとして次のように表現できる。
\it{\mathbf{x}} = (x_1, x_2, x_3, ..., x_d)^t*2
このd次元空間を特徴空間という。また、そのベクトル\it{\mathbf{x}}を特徴ベクトルという。
特徴ベクトルは特徴空間上の一点になる。
(パターンからどんな特徴を抽出すべきか?何個の特徴を抽出すべきか?は問題やデータに依存する)

抽象的すぎて、何を言ってるのかさっぱりですね。d個とか言われてもよくわからないので、具体的に数値を入れていきましょう。

パターンから3個の特徴を抽出したとする。その場合、特徴空間は3次元であり、
あるパターンの特徴ベクトルが\it{\mathbf{x}} = (2, 3, 7)の場合、
そのパターンは特徴空間上で(2, 3, 7)地点に位置する。


…まだよくわかりませんね。我々の関心のあるテキストマイニングに話題を絞って、具体的に意味を理解するようにしましょう。「どんな特徴を抽出すべきか?」に関しては、各パターンを識別しやすいよう設定しなければなりません。先程のOCRの例では、文字色を特徴として設定するのは不適切ですね。テキストマイニングでは「文書に出てくる単語の頻度」をその文書の特徴とすることが多々あります。文書をテーマごとに分類するというタスクがあるとすると、「サッカー」や「野球」などの単語頻度が大きい文書は「スポーツ」に分類し、「選挙」や「政党」などの単語頻度が大きい文書は「政治」に分類する、というように特徴を活用することが出来そうですね。これを特徴ベクトルで表現すると、 (サッカー, 野球, 選挙, 政党)という4次元*3の特徴空間を考え、ベクトルの各要素を単語頻度だとします。つまり、文書にサッカーが5回、野球が7回、選挙が13回、政党が2回出現した場合、特徴ベクトルを\it{\mathbf{x}} = (5, 7, 13, 2)と考える、ということです。ここで、文書aがx_a = (10, 37, 1, 0)、文書bがx_b = (1, 2, 108, 47)であった場合、文書aはスポーツに、文書bは政治に分類出来るのではないかと考えることが出来ます。(※これは説明の簡便のため、非常に単純化した話であって、実際の分析では文書の長さや単語頻度に対して正規化を行うなど、様々な工夫が必要です)


●識別部の処理
 入力された特徴ベクトルが、どのクラスに属するかを識別する処理です。どのような特徴をもったパターンを各クラスに属するかを識別するために「プロトタイプ」を設定します。プロトタイプとは、クラスを代表する特徴ベクトルのことです。出身地を識別するというケースであれば、香川県民のプロトタイプは毎日うどん、大阪府民のプロトタイプは毎日たこ焼きやお好み焼きを食べるといった各クラスの典型パターンのことです。


 最も基本的な識別手法として挙げられる最近傍決定則(Nearest Neighbor Method)は、入力された特徴ベクトルがどのプロトタイプに最も近いかで判別する手法です。あなたが毎週うどんを食べ、かつ、全くたこ焼きやお好み焼きを食べない人なら、大阪府民よりも香川県民のプロトタイプに近いので、どちらかに分類するとするなら香川県民に分類するわけです。


 最近傍決定則を用いて、文書を「スポーツ」「政治」の2つのテーマに分類するタスクを考えてみましょう。クラスは「スポーツ」と「政治」の2つ、特徴空間をx = (サッカー, 野球, 選挙, 政党)とします。スポーツクラスのプロトタイプをx_{sports} = (10, 10, 0, 0)、政治クラスのプロトタイプをx_{politics} = (0, 0, 10, 10)と設定したとします。入力パターンの特徴ベクトルがx_{input} = (9, 14, 0, 2)であるとき、各プロトタイプと入力パターンの特徴ベクトルの距離を測る何らかの関数fを用意し、どのプロトタイプが最も近いかを考えます。

 ここで具体的なイメージを掴むため、関数fの中身を実際に定義してみましょう。関数fを「特徴ベクトルの各要素の差の二乗(計算の便宜上、負の符号を消すため)を合計した値を距離とする関数」であると定義します。入力パターンの特徴ベクトルがx_{input} = (9, 14, 0, 2)、スポーツクラスのプロトタイプの特徴ベクトルがx_{sports} = (10, 10, 0, 0)なので、

  1. 要素目:9 - 10 = 1
  2. 要素目:14 - 10 = 4
  3. 要素目:0 - 0 = 0
  4. 要素目:2 - 0 = 2

これで入力パターンとスポーツクラスのプロトタイプとの各要素の差を計算できました。次に、各要素の差の二乗を合計します。
1^2 + 4^2 + 0^2 + 2^2 = 21
これを入力パターンとスポーツクラスのプロトタイプとの距離だとします。

同じようにして、入力パターンの特徴ベクトルx_{input} = (9, 14, 0, 2)と政治クラスのプロトタイプの特徴ベクトルx_{politics} = (0, 0, 10, 10)の距離を測ります。

  1. 要素目:9 - 0 = 9
  2. 要素目:14 - 0 = 14
  3. 要素目:0 - 10 = -10
  4. 要素目:2 - 10 = -8

合計値、つまり両者の距離は9^2 + 14^2 + (-10)^2 + (-8)^2 = 441となりました。直感でも明らかなように、入力パターンは政治よりもスポーツの方が近いため、この入力文書はスポーツに分類されます。無事識別部の処理が完了しました。後はこの分類結果を、ユーザーに役立つように提示する識別結果出力部に渡し、終了です。というわけで、パターン認識の概要と、その手順を学びました。が、ここでまた一つ疑問が生まれます。プロトタイプってどうやって設定するのでしょうか?


機械学習
 上記の説明ではプロトタイプが与えられていましたが、実務において、どのような特徴ベクトルがプロトタイプとして相応しいかを判断することは非常に難しい問題です。どんなに上手く特徴を抽出し、識別処理を施しても、そもそものプロトタイプが誤っていれば、識別は間違ってしまいます。先程の出身地を識別する例で言うと「大阪人のプロトタイプは巨人ファンである」のように明らかに言語道断な間違った設定をしてしまえば、決して大阪人の正しい識別は出来ません、もう絶対に出来ませんね。ではどうすればいいのでしょうか?OCRであれば、手書き文字や印刷文字を用意し、どのような特徴ベクトルを持てばどのクラスに属するかという正しいデータを大量に記録しておきます。スポーツと政治の分類問題であれば、スポーツや政治について言及している文書を大量に集め、実際にどのクラスにどの単語がどのような頻度で出現しているかの分布情報を取得します。出身地識別なら、大阪人を大量に招集し、どの野球チームのファンかを聞いて回り、実際大阪人はどのチームのファンが多いのかのデータを取ります。これらのデータのことを学習データ、正解データ、教師データ、正例などといいます。大量に学習データがあれば、ある程度の文字画像の揺れを許容して正しい文字認識を行うことが出来ます。このように、各クラスを正しく判別できるようなプロトタイプを求めるため、大量の学習データを統計的に用いて、より良いプロトタイプとは何かを機械に自動で学習させていく一連の手法を(教師あり)統計的機械学習、あるいは単に機械学習といいます。人間は沢山の経験を積み、自分の判断の精度を向上させることが出来ます。その学習能力を機械に持たせるのが機械学習です。テキストマイニングは、パターン認識と機械学習を用いて、より精度の高い分析を可能にします(具体的にどのように学習していくのかはまた後日)。


●終わりに
 お疲れ様でした。本日は数式もほぼ登場せず、読み物としてパターン認識と機械学習の概念を紹介しました。明日以降、具体的な手法について学んでいきましょう。

*1:専門家の中でもパターン認識と機械学習(さらに言うと人工知能データマイニングも)を別区分とする人も居ますし、区別しない人も居ます。本稿では基本的に機械学習とパターン認識を区別しませんが、説明の便宜のため、主に識別部をパターン認識、プロトタイプの学習部を機械学習とします。なお、昔はまとめてパターン認識と呼称する方が多かった印象で、最近は機械学習と呼称するのが一般的であるように見えます(個人的見解)

*2:右肩についてるtは転置を意味する。転置とは列(縦)ベクトルを行(横)ベクトルに(あるいは逆に)する操作である。ベクトルは本来縦に要素を並べて書くが、表記の都合上、横に並べた方が書きやすいので転置を使っている。そんな操作しても問題ないのか?という点につていてはまた後日。無論ここでは問題ないので行っています

*3:次元という単語を恐れる必要はありません。単に変数が4つあるということを示しているだけに過ぎません。変数が一つなら直線上で、変数が二つなら平面上で表現することが出来ますね。変数の数だけ軸が存在し、1変数なら1次元=直線、2変数なら2次元=平面…となるだけのことです。もうちょっと細かい話をすると、線形独立な変数の数であるとか色々ありますが、線形代数の知識が必要なので、また後日にしましょう