Simple ClassifierをAdaBoostの弱学習器として使う

今回は,Simple ClassifierをAdaBoostの弱学習器として使ってみる.非線形な決定境界を実現するために,RBFSamplerを噛ませている.例にある,adaboost.pyを見ていただければと思うが,簡単にいうと,以下のようにしてモデルを作る.

from sklearn.ensemble import AdaBoostClassifier
from sklearn.kernel_approximation import RBFSampler
from sklearn.pipeline import Pipeline

classifier = AdaBoostClassifier(SimpleRandomBinaryClassifier(
        convert_y=True,
        random_state=0
), algorithm='SAMME', n_estimators=100, random_state=0)
pipe = Pipeline([
    ('transformer', RBFSampler()),
    ('classifier', classifier)
])

これをcirclesmoonsに適用すると,以下のような決定境界を得る.

enter image description here

enter image description here

結構うまく分類できているように見える.学習も早いので,弱学習器としては結構使えるのではないかと思う.しかし,まだマルチクラス対応をしていないので,実用上は微妙かも.一刻も早くマルチクラス対応したいと思います.

Written with StackEdit.

Kaggle用のリポジトリ作りました

Feature Engineering + Algorithm開発に集中できるように,Kaggle用のリポジトリを作ったので簡単に解説したいと思います.リポジトリは以下

使用方法ですが,まず,適当なCompetition(competitionとします)からtrain.csvtest.csvをダウンロードして,kaggle-base/input/competition/に配置します.そして,以下のコマンドでsubmission.csvを作成します.作成される場所は,デフォルトではkaggle-base/workspace/postprocessor/competition/配下です.
あとはこのsubmission.csvをKaggleにsubmitすれば完了です.

このリポジトリは以下の3つのモジュールからなります.

  • preprocessor
  • learner
  • postprocessor

preprocessorは,train.csvtest.csvを元に,以下の4つのファイルをkaggle-base/workspace/preprocessor/competition/ 配下に作ります.

  • x_train.pickle
  • y_train.pickle
  • x_test.pickle
  • id_test.pickle

各ファイルの意味はscikit-learnに準拠していますが,id_testだけはテストファイルのidのリストです.

learnerは,上のファイルを元に,kaggle-base/workspace/learner/competition/配下にmodel.pickleを作ります.

postprocessorは,できたモデルを使ってテストデータに対して予測をし,kaggle-base/workspace/postprocessor/competition/配下にsubmission.csvを作ります.

これらを実行するには,kaggle-base配下で以下のコマンドを実行します.

bash run.sh competition id_column target_column task_type random_state

各引数の意味をtitanicやhouse-pricesなどを例に解説すると,以下のような感じです.

  • competition: project_name的な役割です.例えばtitanicやhouse-pricesなどを指定します.
  • id_column: IDに該当するカラム名です.例えばPassengerIdやIdなどを指定します.
  • target_column: 目的変数を指すカラム名です.例えば,SurvivedやSalePriceなどを指定します.
  • task_type: タスクのタイプを指定します.例えばclassificationやregressionを指定します.現状classificationとregressionしかサポートしていません.
  • random_state: 乱数のseedです.実験結果を再現するのに使います.

以上が簡単な使い方です.さて,ほとんどの場合,自分で実装した前処理や学習アルゴリズム,そして後処理を使いたいという場合がほとんどでしょう.その場合は,環境変数でそれらを指定します.以下の3つの独自のスクリプトを作成したとします.

  • kaggle-base/preprocessor/competition.py
  • kaggle-base/learner/competition.py
  • kaggle-base/postprocessor/competition.py

これらを使ってsubmission.csvを作成するには,以下のコマンドを実行します.

env PREPROCESSOR=competiton.py LEARNER=competition.py POSTPROCESSOR=competition.py bash run.sh competition id_column target_column task_type random_state

以上が使い方になります.実際に独自スクリプトを使う際には,新しいブランチを作ることを推奨します.報酬がKnowledgeなCompetitionに対しては,competition-titanic-developer-nameみたいな感じで作って,cv score + public scoreを添えてプルリクを出していただければ,もっとも良いアルゴリズムは,competition-titanicにマージしようと思っています.初めて使う人が,ブランチをチェックアウトすることで,最高性能のアルゴリズムを見ることができるように.もちろん,このプロジェクトが流行ればですが笑.

ぜひ使っていただければ幸いです.

Written with StackEdit.

シンプルな非線形分類器を作りました

前回はSimple Classifierを作りました.今回はこれを非線形な分類器に拡張したいと思います.と言っても,よく使われている方法を使うだけなのですが.

学習データが与えられているとします.ただし,とします.入力の変換を以下で定義します.

ここで,から適当に個選ぶことにします.あとは,これにSimple Classifierを適用します.このやり方はよくやられていて,scikit-learnにも実装があります→RBFSampler

Grid Searchでを選んで,toy dataに対して適用してみました.結果は以下のようになりました.

うまく非線形な決定境界を得られていると思います.また今度になりますが,有名な分類器とのパフォーマンス比較もやりたいと思います.ソースコードはGithubに置いてます↓.

simple-classifier

Written with StackEdit.

シンプルな分類器を作りました (Simple-Classifier)

シンプルな分類器 (Simple Classifier)を作ったので,その仕組みをここに書きたいと思います.

まず,線形モデルについて少し深く考えてみたいと思います.入力を, 出力をとします.パラメータを用いて,パラメータに関する線形モデルを以下のように定義します.

簡単のため,として,の第j成分とします.を人として考えましょう.つまり,人の人がいます.そして,を人が賛成した(+1)か反対した(-1)かを表すものと考えます.こう考えると,を正解として,なら,は正解したと言えます.
この観点から線形モデルを見てみましょう.簡単のため,とします.こうすると,は人を信用する(+1)か信用しない(-1)かを表してると考えられます.信用しているなら,の意見をそのまま通しますが,信用していないなら,その反対を選びます.
今,学習データが与えられているとします.をどのように決めたらいいでしょうか?直感的には,「多く正解している人をより信じる」ように選んだらいいような気がします.の正解率は,

で表されます.これをそのままとして使います.つまり,

とします.これがプラスなら信用し,マイナスなら信用しないということです.さらに,値が大きいなら,より信用する(しない)ことになります.

今回作った分類器,Simple Classifierは,基本的にはこれだけの仕組みに基づきます.

さて,入力はであることが多いのが現実です.これを,に変換しなければなりません.もっとも簡単なのは,毎に,閾値を用意して,それで以下のように判断することです.

それでは,はどのように選んだらいいでしょうか?今回は,の平均を使って,

とします.これは,中立な人の立場から見て,その人が賛成か反対かを決めていることに相当すると考えられます.

以上がSimple Classifierの仕組みです.実装はGithubにあります,ぜひ使ってみてください.

simple-classifier

Written with StackEdit.

お手軽なvue.js + webpackプロジェクトの始め方

vue-cli

今回は,@vue/cli (旧vue-cli)を使って,お手軽にvue.js + webpackプロジェクトを作成したいと思います.

nodeのインストール

nodebrewを使います.

brew install nodebrew

nodebrewを使ってnodeを入れます. npmも入ります.VERSIONのところはインストールしたバージョンを指定してください.

nodebrew install-binary latest
nodebrew use VERSION

npmで@vue/cliをインストールします.最新版は,vue-cliではなく,@vue/cliなので注意.至る所で使うので,グローバルインストールでいいでしょう.

npm install -g @vue/cli

vueプロジェクトをお手軽に作るために,@vue/cli-initを入れます.

npm install -g @vue/cli-init

これで準備が整いました.webpack + vueプロジェクトを作ります.今回は,webpack-simpleをテンプレートとして選びました.

vue init webpack-simple vue-webpack-simple-example
cd vue-webpack-simple-example
npm install

以下で開発用サーバが動くと思います.

npm run dev

buildは以下でできます.

npm run build

とても簡単で素晴らしいですね.次回は開発用サーバではなく,nginx (docker)でこれを動かしてみたいと思います.

Written with StackEdit.

nginxのdockerイメージを使ったシンプルな静的コンテンツの表示

nginxのdockerイメージを使ったシンプルな静的コンテンツの表示

githubにソースコード置いてます: nginx-simple-example

今回は,nginxで静的コンテンツの表示というのをやってみたいと思う.自分の環境を汚したくないので,dockerを使う.nginxのdockerイメージはすでにあるので,これをベースに作っていく.ディレクトリ構成は以下.

nginx-simple-example/
	Dockerfile
	src/
		index.html
		css/
			style.css
		js/
			hello.js
	nginx/
		nginx-simple-example.conf

src/の中身が静的コンテンツで,例えばwebpackの出力なんかを想定している(多分こんな感じだった気がする…).nginx/配下にnginxの設定ファイルをおく.

nginxの設定ファイルは以下のようにする.

nginx-simple-example.conf:

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/local/nginx-simple-example;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

ほとんどデフォルトのままだが,rootを変えている.nginxというかwebserverが具体的にどのような役割を担っているのか,あんまり知らなかったので,調べてみた.僕の理解では,/にアクセスすると,/usr/local/nginx-simple-exampleをみて,その中のindex.htmlが表示されるという具合なんだと思う.となると,/cssにアクセスすれば,/usr/local/nginx-simple-example/cssにアクセスしていることになる.この仕組みを想定すれば,index.htmlで,cssやjsの読み込みは以下のようになるだろう.

index.html:

<html>
  <head>
    <link href="/css/style.css" rel="stylesheet" type="text/css">
    <script type="text/javascript" src="/js/hello.js"></script>
  </head>
  <body>
    <h1>Hello World!</h1>
  </body>
</html>

/hrefsrcの先頭についていることに注意.

次にDockerfileは以下のようにした.

Dockerfile:

FROM nginx
COPY ./src /usr/local/nginx-simple-example
COPY ./nginx/nginx-simple-example.conf /etc/nginx/conf.d/default.conf

どうやら,default.confというのが最初からあるようで,今回はこれを上書きしているが,どうにか共存させることもできそう.これは後日調べようと思う.

最後に,style.csshello.jsの中身も載せておく.

style.css:

h1 {
    color: red;
}

hello.js:

console.log("Hello World!")

これでビルドする.

docker build --tag nginx-simple-example .

で,runする.

docker run --rm -p 8080:80 --name webserver nginx-simple-example

localhost:8080にアクセスすると,赤字のHelloWorld!が表示される.それとconsoleにHelloWorld!が出力されていると思う.

かなりシンプルにできた.ソースはgithubに置いてます.
nginx-simple-example

Written with StackEdit.

測度論や確率論を学ぶモチベーション

何かを選ぶということ

我々は集合SSを常に持っているとし,完全にランダムにこの元を選ぶことができるとする.
そして,

  1. 選択肢の集合XXに出会う.
  2. XXの中から一つ選ぶ

というプロセスを考える.
我々は選択肢に出会った瞬間,関数ξ:SX\xi: S \rightarrow Xを定義し,乱数sSs \in Sを発生させ,x=ξ(s)x = \xi(s)を選ぶ.

では,関数ξ\xiの性質を考えよう.
XXの中に「絶対に選びたくない」ものが ある場合もあるだろう.この場合,ξ\xiは全射にならない.完全にランダムに選ぶなら,ξ\xiは単射である.それをしないならば,ξ\xiは単射にならない.

次に,ξ1(x)={sSξ(s)=x}\xi^{-1}(x) = \{s \in S | \xi(s) = x\}というものを考えよう.この集合のサイズが大きければ,選ばれる可能性が高そうである.では,集合のサイズを測る関数μ\muを用意しよう.μ:2S[0,)\mu: 2^S \rightarrow [0, \infty)とする.ここで,2S2^Sは冪集合,つまり,SSの部分集合の集合である.値域を[0,)[0, \infty)としたのは,大きさがマイナスというのは直感的によくわからないし,大きさが無限大というのもどういうことなのかわからないからである.以上を踏まえて,μ(ξ1(x))\mu(\xi^{-1}(x))を,xxが選ばれる可能性と呼ぼう.

上では,XXの中から一つ選ぶことを考えたが,実際には複数個選ぶ場合もあるだろう.つまり,2X2^Xの中からAAを選ぶことになる.同様の流れになるが,ξ1(A)={sSξ(s)A}\xi^{-1}(A) = \{s \in S | \xi(s) \in A\}を考えて,μ\muを定義する.そして,μ(ξ1(A))\mu(\xi^{-1}(A))を,AAが選ばれる可能性と呼ぼう.複数個選ぶというのは,一つを選ぶことを含むので,これからは複数個選ぶ場合を考える.

ここで,何か不思議なことに気づく.選択肢を選ぶ可能性の 高さの話が,集合のサイズを測る話になっている.ここまできてしまえば,集合のサイズを測る学問の知識が使えそうである.続きはまた次回.

Written with StackEdit.

ルベーグ可測集合の自分なりの解釈

ルベーグ可測集合の自分なりの解釈

ルベーグ可測集合というのを導入する.導入のモチベーションを考えよう.あくまでも自分なりのイメージです.

ルベーグ外測度は,EGE \subset Gに対して,GEe|G - E|_eを考えれば,距離みたいなものとも考えられる(実際には距離ではない).こうなると,極限みたいなものが定義できそう.

EEがルベーグ可測集合とは,任意のϵ>0\epsilon > 0に対して,GEG \supset Eで,GEe<ϵ|G - E|_e < \epsilonとなるような開集合GGが存在することをいう.

では,このような集合を考えることで,どんな嬉しいことがあるのだろう?

まず,開集合のルベーグ外測度は体積になっている.ある集合が開集合で包めるなら,その集合の体積を近似できそう.包む開集合がタイトであればあるほど正確にその集合の体積を測ることができる.包む開集合をいくらでもタイトにできるような集合の体積は, ほとんど誤差なく測ることができそう.このような集合がルベーグ可測集合だと思っている.

こう考えると,なんというか,ルベーグ可測集合は開集合を集合の極限としてもつと言っても良いのだろうか?

Written with StackEdit.

なぜルベーグ外測度を導入するのか?

なぜルベーグ外測度を導入するのか?

測度論を勉強していて,「ルベーグ外測度」 というものが出てきた.今回はこれの定義を見ていくと共に,導入の目的を自分なりに考えてみる.

まず,導入のモチベーションから.これを説明するために,左半開区間の「体積」を導入する.Rn\mathbb{R}^nの左半開区間i=1n(ai,bi]\prod_{i=1}^n (a_i, b_i]の体積v(i=1n(ai,bi])v(\prod_{i=1}^n (a_i, b_i])

v(i=1n(ai,bi])=i=1n(biai) v(\prod_{i=1}^n (a_i, b_i]) = \prod_{i=1}^n (b_i - a_i)

で定義する.これはai,bia_i, b_iが与えられれば,具体的に計算できる.ここで,左半開区間全体に空集合\emptysetを加えたものを,GRn\mathscr{G}_{\mathbb{R}^n}とおく.これでGRn\mathscr{G}_{\mathbb{R}^n}の元に対して,体積を測ることができる.ここで出てくる問題の一つは,「GRn\mathscr{G}_{\mathbb{R}^n}に入っていない集合の体積はどうやって測るのか?」というものである.これがまさに,ルベーグ外測度導入の理由だと思う.

自分なりのモチベーションを考えることができたので,具体的に導入したいと思う.
任意のRn\mathbb{R}^nの部分集合ERnE \subset \mathbb{R}^nを考える.注意したいのは,これはERn\mathscr{E}_{\mathbb{R}^n}に入っているとは限らないこと.EEの体積を測るための,基本的なアイデアは,左半開区間の体積は計算できるのだから,これで覆ってあげて,その下限をとるというものである.

SE={Ij}jNS_E = \{I_j\}_{j \in \mathbb{N}}GRn\mathscr{G}_{\mathbb{R}^n}の可算個の集合列で,jNIjE\cup_{j \in \mathbb{N}} I_j \supset Eとなるものとする.このようなSES_E全体をSE\mathscr{S}_Eとする.今,SE={Ij}jNS_E = \{I_j\}_{j \in \mathbb{N}}に対して,

σ(SE)=jNv(Ij) \sigma(S_E) = \sum_{j \in \mathbb{N}} v(I_j)

とおく.

ルベーグ外測度はこの下限として定義される.

Ee=inf{σ(SE)SES(E)} |E|_e = \inf \{\sigma(S_E) | S_E \in \mathscr{S}(E)\}

これがルベーグ外測度の定義である.ここで,SES_Eが一つも存在しないときはどうするのだろうか?という疑問が生まれる.結論からいうと,「RnR^nの開集合は互いに交わらない左半開区間の可算個の和集合で表される」という定理がある.証明は僕にとってはまだ難しく,省略してこの事実を飲み込むこととする.

Written with StackEdit.

機械学習の問題設定

機械学習の問題設定 機械学習の問題設定を見直したのでメモ. ( Ω , F , P ) (\Omega, \mathcal{F}, P) ( Ω , F , P ) : ベースとなる確率空間 ( X , F X ) (\mathcal...