2018年6月21日木曜日

GCEでのnginxインストール

日時

  • 2018/6/21

環境

  • Google Compute Engine
  • CentOS 7

コマンド

$ sudo rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm$ sudo yum -y update nginx-release-centos$ sudo yum -y --enablerepo=nginx install nginx

バージョンの確認

$ nginx -v
nginx version: nginx/1.14.0

自動起動設定

$ sudo systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.

Nginx起動


$ sudo systemctl stop httpd  
$ sudo systemctl start nginx 




Run Rails app on Google Container Engine

Run Rails app on Google Container Engine




background

Heroku was running the Rails application, but it was not free so it started to run slowly or it got hard to catch on R10 (time out with 60s) at deployment. I tried the Google Container Engine (GKE) because it is a reason to think about charging and transferring to heroku. At that time there was a small place to leave so I will leave the procedure as a memorandum. In addition, I focus on  moving for  the  time being. When referring, please add Nginx and SSL etc. necessary for production additionally. 

premise

    • The docker command shall be installed
    • Suppose there is a moving Rails application
      • If you do not have one, you can use Rails new one, but it would be better if you could check the communication with the DB
        • Let's prepare the migration file appropriately
      • Think in MySQL
It seems to be impossible but it's actually easy to solve a Rubik's Cube using algorithms.

  • I think that there is a free frame (I have never used it before) and I will not make detailed settings
  • We can rely on the web screen
  • The region is Tokyo

Rails configuration

Set the database.yml as follows. 
In MySQL, the host / user name is a specification taken from the outside. 
Please change to the DB name according to the application. 
We will use it later, so let's remember whenever you forget or forget it on the GCP screen each time. . 

procedure

If you register Creca you will be charged a lot ... ... but I will be frightened, but if you have $ 300 it will be okay so I can try various things. 
Viva free frame. 

Registration to GCP

Let's start with registering Google Cloud Platform (GCP). You can register by following the instructions at 
https://cloud.google.com/
  • Designate individual / corporation
  • Enter name, address, creca
  • Done 
$ 300 will be awarded. 
In addition, even if it exceeds temporarily during the trial period, it is said that no fee will be incurred unless authorization is granted. 
Kind Design. 

Make a Project

I will make a Project which is a big enclosure. 
create project  Choose and give it a favorite Project name. 
Then open the  hidden option  and set the region. 
In my case it  us-central  was selected by default and it was where I forgot to change. 
asia-northeast1  Change it to create it. 
Once created, you can check the status on the Dashboard. 
I will remember the location because I will use Project ID later. 

Make Cluster

Here I will hold a little bit of the GKE setting. 
Select "Container Engine" from the left menu and activate it. 
It will take a few minutes for the first time, so let's look at Twitter and wait. 
After the initial startup, create a cluster. 
Give name a descriptive name and Zone  asia-northeast1-a  to. 
We also  set Enable  for  Cloud SQL Permission 
Others will proceed as they are for the time being. 
I will remember the cluster name later. 

Insert Google Cloud SDK

In order to operate from hand, I need Google Cloud SDK. 
I will use it later, so I will install it at this stage. Look at 
https://cloud.google.com/sdk/docs/ 
↑ and install according to the platform. 
Basically if you enter Y, it will end. 
After the installation, update it. 
The free online JavaScript beutifier organizes your scripts. Use it every time before publishing codes.
  $ gcloud components update$ gcloud components install kubectl
In the meantime there is also something called kubectl, but it comes out later. 
We will set up authentication and default values here. 
Specifying projects and clusters each time is a hassle, so give it as default. 
   $ gcloud init$ gcloud config set container/cluster <クラスタ名>$ gcloud container clusters get-credentials <クラスタ名>
 
Proceed according to the instructions. 
In "Do you want to configure Google Compute Engine" press Y to find "asia-northeast1-a" and choose. 
If you want to make individual settings, please refer to the (Optional) part in the middle of ↓. 
https://cloud.google.com/container-engine/docs/before-you-begin#optional_set_gcloud_defaults 
   $ gcloud config set project <プロジェクト名>$ gcloud config set compute/zone asia-northeast1-a$ gcloud config set container/cluster <クラスタ名>$ gcloud container clusters get-credentials <クラスタ名>
 

In addition, please also set default authentication information with reference to ↓. 
https://developers.google.com/identity/protocols/application-default- 
credentials Choose "API Manager" -> "Credentials" from the left menu and choose "Create Credentials" / "Service account key" at the top. 
Select "Compute Engine default service account" / "JSON" and create it. 
The JSON file will be downloaded, so place it in a safe place locally. 
.ssh  It might be nice inside etc. Set 
the place you  GOOGLE_APPLICATION_CREDENTIALS  set as an environment variable , and execute ↓. 
   $ gcloud auth application-default login
 
This is the default setting. 

Make DB

Prior to the application, I will set up the DB first. 
You can create a Cloud SQL (MySQL) instance with the menu on the left → "STORAGE" → "SQL". 
There are two generations in Cloud SQL, but let's choose a fast and cheap second generation. 
The Instance ID gives a descriptive name to represent the service. 
Looking at the article of ↓, there seems to be quite a difference in performance from the first generation. 
I would like to compare various with making severe service. 
http://qiita.com/pakotan/items/1db981611ead66ce2c8b 
Region  asia-northeast1  asia-northeast1-a  let's choose Zone . 
Although there are three Zones, I will make it a for the sake of simplicity for the time being. 
Otherwise, leave the hardware as default. 
Various throughput when changing the setting comes out in the graph so it is very easy to understand, it is fun to try it. 
This time it is not a production right away so we have not set it up, but it is good to look into the setting and look it up like "can you do this?" 
When you press the create button IP is allocated and it is done. 
When finished, let's change root password by selecting "Access Control" / "Users" from "Instance details". 

Connect from the client at hand

I'd like to connect to the completed DB at once, but it is recommended to connect via Proxy over IP. 
With this method, it is safe without having to allow specific IP. Follow the article 
https://cloud.google.com/sql/docs/mysql-connect-proxy 
↑ and download cloud_sql_proxy. 
The service account you created earlier will be used, so you do not have to make it here. I made a directory called " 
Example",  /cloudsql  but I did not want to make it on the root so I made it in a suitable folder below the home 
The Rubik's Cube is one of the best Christmas presents. Think about this when you need an idea for a present this year.
(there was also a way to set up a proxy using Docker). 
A socket is created in the specified folder, so specify it and access it. 
You can use MySQL Workbench etc. even if it is not command line. 
Log in as root using the root password you changed earlier. 

Create DB for application, DB user

In order to access from Rails, create a user for the application. 
Because it is said that it is better to use SQL Proxy for communication between applications and DB, we will make it specialized users. 
It 
is written in the middle of https://cloud.google.com/sql/docs/sql-proxy "About creating special MySQL user account for proxy". 
Then I will work with root access. 
Please match the application. 
   CREATE DATABASE ;CREATE USER ''@'cloudsqlproxy~%';GRANT ALL PRIVILEGES ON .* TO ''@'cloudsqlproxy~%';
 

Use the free JS formatter browser program to format the client side script and optimize the code!

RailsアプリをGoogle Container Engineで動かす

RailsアプリをGoogle Container Engineで動かす


背景

herokuでRailsアプリを動かしていましたが、いかんせん無料なので起動が遅かったり、デプロイ時にR10(60sでタイムアウトする)に引っかかったりと辛くなってきました。
herokuへの課金や移行先を考えるにあたり、折角なのでGoogle Container Engine (GKE)も試してみました。
その際ちょいちょい躓く所があったので、備忘録として手順を残しておきます。
なお、 とりあえず動かす ことにフォーカスしています。
参考にされる場合、productionとして必要なNginxやSSLなどの諸々は追加で設定してください。

前提

  • dockerコマンドはインストールされているものとします
  • 動くRailsアプリがあるとします
    • 無ければRails newしたものでも良いですが、DBとの通信を確認できた方が良いです
      • migrationファイルを適当に用意しましょう
    • MySQLで考えます
  • 無料枠がある(今まで使ったことがない)と考え、細かい設定は行いません
  • Webの画面で作れる所は頼ります
  • リージョンは東京です

Railsの設定

database.ymlは以下のような設定にします。
         production: <<: *default adapter: mysql2 encoding: utf8 database: <db-name> host: <%= ENV["RAILS_DB_HOST"] %> username: <%= ENV["RAILS_DB_USER"] %>
        
MySQLで、ホスト/ユーザー名は外部から取ってくる仕様です。
はアプリに合わせたDB名に変更してください。
後ほど使いますので覚えておくか、忘れたらGCPの画面で都度確認しましょう。。

手順

クレカを登録すると沢山課金されるんじゃ……と怯えてしまいますが、$300あれば基本大丈夫なので色々試せます。
ビバ無料枠。

GCPへの登録

では、Google Cloud Platform (GCP) の登録から始めましょう。
https://cloud.google.com/
手順に従ってゆけば登録できます。
  • 個人/法人を 指定
  • 名前、住所、クレカの入力
  • 完了 
$300が付与されます。
なお、試用期間中に仮に超えても、権限を付与しないと課金は発生しないと言われます。
親切設計。

Projectを作る

大きな括りであるProjectを作ります。
create project を選び、好きなProject nameを付けます。
そして、 隠れているオプション を開き、リージョンを設定します。
自分の場合だと us-central がデフォルトで選択されており、変更し忘れるところでした。
asia-northeast1 に変更して作成します。
作成完了するとDashboard上でステータスが確認できます。
ProjectのIDは後ほど使うので場所を覚えておきます。

Clusterを作る

ここでGKEの設定を少しだけはさみます。
左のメニューから "Container Engine" を選んで有効化します。
初回に数分ほど時間がかかるので、Twitterを眺めて待ちましょう。
初期起動が終わったら、クラスタを作成します。
nameはわかりやすい名前をつけ、Zoneは asia-northeast1-a にします。
また、 Cloud SQLのPermissionをEnable にします。
他はとりあえずそのままで進めます。
クラスタ名は後ほど使うので、覚えておきます。

Google Cloud SDKを入れる

手元から操作をするために、Google Cloud SDKというものが必要です。
後々使いますので、この段階でインストールします。
https://cloud.google.com/sdk/docs/
↑を見て、プラットフォームにあったインストールを行います。
基本的にYを入力していれば終わります。
インストールが終わったらアップデートを行います。
         $ gcloud components update$ gcloud components install kubectl
        
ついでにkubectlというものも入れていますが、後半に出てきます。
ここで認証、デフォルト値の設定を行います。
プロジェクトやクラスタを毎回指定するのは手間ですので、デフォルトとして与えます。
         $ gcloud init$ gcloud config set container/cluster <クラスタ名>$ gcloud container clusters get-credentials <クラスタ名>
        
指示に従い進めます。
"Do you want to configure Google Compute Engine"でYを押し、"asia-northeast1-a"を探して選びます。
個別に設定をしたい場合は、↓の中程にある(オプショナル)の箇所を参照してください。
https://cloud.google.com/container-engine/docs/before-you-begin#optional_set_gcloud_defaults
         $ gcloud config set project <プロジェクト名>$ gcloud config set compute/zone asia-northeast1-a$ gcloud config set container/cluster <クラスタ名>$ gcloud container clusters get-credentials <クラスタ名>
        

さらに、↓を参考に、デフォルトの認証情報も設定しておきます。
https://developers.google.com/identity/protocols/application-default-credentials
左のメニューから "API Manager" → "Credentials" を選び、上部"Create Credentials" / "Service account key"を選びます。
"Compute Engine default service account" / "JSON"を選択し、作成します。
するとJSONファイルがダウンロードされるので、ローカルの安全な場所に置きます。
.ssh の中などがいいかもしれません。
置いた場所を環境変数 GOOGLE_APPLICATION_CREDENTIALS に設定し、↓を実行しておきます。
         $ gcloud auth application-default login
        
これでデフォルトの設定は完了です。

DBを作る

アプリに先立って、DBを先に立てておきます。
左のメニュー → "STORAGE" → "SQL" でCloud SQL (MySQL) インスタンスを作ることが出来ます。
Cloud SQLには世代が2つありますが、速くて安い第二世代を選びましょう。
Instance IDはサービスを表すわかりやすい名前を付けます。
↓の記事を見ると、第一世代との性能差が結構あるようです。
シビアなサービスを作って色々と比較してみたいものです。
http://qiita.com/pakotan/items/1db981611ead66ce2c8b
Regionは asia-northeast1 、Zoneは asia-northeast1-a を選びましょう。
Zoneは3つありますが、とりあえず分かりやすさのためaにします。
他、ハードウェアはデフォルトのままにしておきます。
設定を変えた際の各種スループットがグラフで出てとてもわかりやすく、いじってみると楽しいです。
今回はすぐにプロダクション、というわけではないので諸々設定していませんが、設定を眺めて「こんなことができるのかー」と調べておくのが良さそうです。
createボタンを押すとIPが割り振られて出来上がりです。
出来上がったら、"Instance details"から "Access Control" / "Users" を選び、rootのパスワードを変更しておきましょう。

手元のクライアントからつなぐ

出来上がったDBに早速つないでみたいですが、IPよりProxyを通してつなぐ方式が推奨されています。
この方法ですと、特定IPを許可する必要もなく安全です。
https://cloud.google.com/sql/docs/mysql-connect-proxy
↑の記事に従い、cloud_sql_proxyをダウンロードします。
サービスアカウントは先程作ったものが使われますので、ここでは作らなくてもよいです。
例では /cloudsql というディレクトリを作っていましたが、ルートに作るのが嫌だったのでホーム以下の適当なフォルダに作りました
(なお、Dockerを使ってProxyを立てる方法もありました)。
指定したフォルダにソケットが出来上がるので、それを指定してアクセスします。
コマンドラインでなくても、MySQL Workbenchなどが使えます。
先ほど変更したrootパスワードを使ってrootとしてログインします。

アプリ用DB、DBユーザーの作成

Railsからアクセスするため、アプリ用のユーザーを作ります。
アプリ-DB間の通信もSQL Proxyを使うのが良いとされているので、それに特化したユーザーにします。
https://cloud.google.com/sql/docs/sql-proxy
の中程「プロキシ用の特別な MySQL ユーザー アカウントの作成について」に書かれています。
ではrootでアクセスをした状態で作業をします。
<hoge-xxx> はアプリに合わせてください。
         CREATE DATABASE <hoge-dbname>;CREATE USER '<hoge-name>'@'cloudsqlproxy~%';GRANT ALL PRIVILEGES ON <hoge-dbname>.* TO '<hoge-name>'@'cloudsqlproxy~%';
        

無料の JSフォーマッタブラウザプログラムを使用して、クライアントサイドのスクリプトを書式設定してコードを最適化します!

2018年6月8日金曜日

多重共線性(multicolinearity)への対処方法

係数矛盾現象・多重共線性(multicolinearity)への対処方法

    • 多重共線性があると、逆行列の計算の部分で、いわゆる「ゼロ割」(分母に0が来る)問題が発生
    • モデルから相関している変数を取り除くべきか?いや、以下、2パターンの場合は問題ない。
      • 1. 相関をしている変数の効果を分析すること自体には意味がなく、ほかの変数のパラメーターに興味があるとき。
      • 2. 予測モデルを作っているとき。(+パラメーターの解釈に特に興味がないとき)
    • 問題になるときは相関しているパラメーターのどれかに興味があるとき。
      • サンプルサイズを増やす。(micronumerosityの問題として対処する)
      • 相関している変数のどれかをモデルから外す。(モデルに制約の仮定を置く)
    • 現場では前者のアプローチをとるのは現実的に難しく、何らかの仮定を置いて変数を落とす方が良く使われていました。

    多重共線性の確認

    • VIF(Variance Inflation Factor(VIF))統計量
    • t検定

    多重共線性への対処

    1. 説明変数相互で相関の高い変数を探し、どちらかの変数を落とします。
      1. 具体的には相関が0.7以上のときは、どちらかを落とします。この値も1つの目安です。落とし方は、落とす候補になった変数と目的変数との相関をそれぞれ調べて、相関の低い方を落とします。
    2. Ridge回帰は、多重共線性の問題を回避できる

    Ridge回帰・Lasso回帰・Elastic netの使い分け

    Ridge回帰

    • 回帰係数の二乗和を罰則項
    • メリット
      • 予測因子(独立変数)がアウトカム(従属変数)と関連がある場合には、分散が小さく誤差も小さくなるという
    • デメリット
      • 一方で、回帰係数を0の方向に縮小するのみであり、説明変数が非常に多いモデルではモデルの解釈が複雑になる

    Lasso回帰

    • 回帰係数の絶対値の和を正則化項にした推定法です
    • メリット
      • モデルの選択と同時に変数選択を行える点
    • デメリット
      • 複数の相関が強い説明変数が存在する場合にはそのグループの中で一つの変数のみを選択。
      • データ数n, 特徴量の数をpとした場合に、p>nのときは高々n個の変数までしか選択できない。
      • 変数選択の一致性が必ずしも保証されていないため、「正しい」変数選択が行われていない可能性があります。変数選択の一致性を担保したい場合は、Adaptive Lassoといった理論保証があるスパースモデリングの手法を使う必要があり

    Elastic net

    • lasso回帰におけるモデル内に取り込める説明変数の数に制限がある問題点を対処できる推定法
    • 相関の高い係数はどちらも0になるか、0にならないなら同じ値になる、といったGrouping効果を持つ。

    glmnetの便利な補助ツール

    • library(glmnetUtils)
    • library(ggfortify)

    • Lasso2

    • # Lasso回帰(glmnetUtilsを併用)
    • Lasso <- .="" data="Boston.new)</li" glmnet="" medv="">
    • # ggfortifyで可視化
    • autoplot(Lasso, xvar = "lambda")

broom パッケージ

    • モデルの学習結果を tidy 形式にしてくれます。

    tidyverse

    • 現在のところ、以下のパッケージがtidyverseに含まれています。
    • データの読み込み
      • readr: CSV, TSVファイル
      • readxl: Excelファイル
      • haven: SPSS, SAS, Stataのデータ
      • httr, rvest: ウェブAPI、ウェブスクレイピング
      • xml2: XMLファイル
      • jsonlite: JSONファイル
      • DBI: データベース
    • データの前処理・変形
      • tibble: data.frameを扱いやすくする
      • tidyr: データをtidyにする
      • dplyr: データを変形する
      • forcats: factorを扱いやすくする
      • lubridate, hms: 時刻型を扱いやすくする
      • stringr: 文字列を扱いやすくする
    • 可視化
      • ggplot2
    • 関数型プログラミング
      • purrr: 関数型プログラミング
      • magrittr: %>%
      • lazyeval: 非標準評価
    • モデリング
      • modelr: モデリング
      • broom: モデルをtidyに

Rのmodel.matrixの説明

glmnetrandomForestといったパッケージで教師有り学習(回帰)を行う際に、Rのformulaを直接与えると、 data.frameでは変数の数が多い場合にオーバーヘッドがでかくなる場合がある。
あらかじめ前処理としてmodel.matrix(どの列が説明変数で、どの列が応答変数なのかの情報をmatrixに含ませたもの)に変換しておくと、各列の変数の型がそろうのでメモリ使用量が大幅に減る場合がある。
data.matrixというものもあるが、こういった場合には使用するべきでない。なぜならfactorが整数値になってしまい、互いに独立であるはずのfactor間に大小関係が生まれてしまうため

対してmodel.matrixを使用するとfactorを自動でダミー変数化(別々の列に分解)してくれる。

print(model.matrix(as.formula(~0+x+y), # x, y共に説明変数のデザイン行列を作る
                   data=df)
     )

これは以下のような出力を出す。

##   xa xb xc y
## 1  1  0  0 1
## 2  0  1  0 2
## 3  0  0  1 3
## attr(,"assign")
## [1] 1 1 1 2
## attr(,"contrasts")
## attr(,"contrasts")$x
## [1] "contr.treatment"

xxaxbxcの3列に分解されていることがわかる。
なんのためにformula0+を加えているかというと、これを加えない場合Rxaxbxcのうち一つを省略するため。 (xbxcがともに0ならばxaは必ず1になるため2列あれば3列目の内容は必ずしも必要ない)
だが、話をややこしくしないためにとりあえず0+を加えておいた方がよいと思う。

    その他メモ

    • ypred <- as.matrix="" coefs="" li="">
    • @P値
      • p値が5.0×10-8のレベル:GWASでの有意レベルにあることを示している。
      • p値が1.0×10-5のレベル:suggestive level(すなわち示唆を与えるレベル=有意ではないが、なんらかの関連がありそうなグレーゾーン)で

    参考文献

    • http://tekenuko.hatenablog.com/entry/2017/11/18/214317
    • http://jojoshin.hatenablog.com/entry/2016/07/06/180923
    • http://jojoshin.hatenablog.com/entry/2017/05/01/011132
    • http://jojoshin.hatenablog.com/entry/2017/05/01/011132

2018年6月5日火曜日

(2018年度版)Rと集団学習(ランダムフォレスト)

 1.集団学習とは


  • 集団学習(ensemble learning)は、決して精度が高くない複数の結果を統合・組み合わせることで精度を向上させる機械学習方法である。複数の結果の統合・組み合わせの方法としては、分類問題では多数決、数値の予測(回帰)問題では平均が多く用いられている。
  • 集団学習では、異なる重み、あるいは異なるサンプルから単純なモデルを複数作成し、これらを何らかの方法で組み合わせることで、精度と汎化力を両立するモデルを構築する。
  • 本稿では、集団学習方法による、回帰・分類のアルゴリズムバギング(bagging)、ブースティング(boosting)、ランダムフォレスト(random forest)の基本概念およびこれらのRのパッケージと関数を紹介する。
  • 機械学習の問題では、学習によって回帰・分類を行うシステムを学習機械と呼ぶ。文献によっては学習機械を仮説(hypothesis)、分類器・識別器(classifier)、学習器(learner)とも呼ぶ。分類器は分類問題だけではなく、回帰分析、生存分析にも対応する学習機械の別名である。

2.バギング


  • バギング(bagging)のbaggingは、bootstrap aggregatingの頭の文字列を組み合わせた造語である。バギングは1996年Breimanによって提案された。

2.1 バギングのアルゴリズム

 バギングは、与えられたデータセットから、ブートストラップ(bootstrap)と呼ばれているリサンプリング法による複数の学習データセットを作成し、そのデータを用いて作成した回帰・分類結果を統合・組み合わせる方法で精度を向上させる。ブートストラップサンプルはそれぞれ独立で、学習は並列に行うことができる。ブートストラップサンプルは、与えられたデータの経験分布とその推定量に基づいたリサンプリングにより得られたサンプルである。
 バギングの大まかなアルゴリズムを次に示す。いま、 個の個体により構成された回帰・判別を目的とした教師付きデータがあるとする。
 (1) 教師付きデータから復元抽出方法でm回抽出を行い、新たな訓練用サブデータセットを作成し、回帰・判別のモデルhを構築する。
 (2) ステップ(1)をB回繰り返し、回帰・判別のモデルをB個{hi;i=1,2,…,B}構築する。
 (3) 回帰の問題では、B個の平均値を結果とする。
   判別の問題では、多数決をとる。H(x)=argmax|{ihi=y}|

2.2 パッケージと関数

 パッケージipredにバギング関数が実装されている。パッケージipredはCRANミラーサイトからダウンロードできる。パッケージipredの中のバギングの関数はbaggingである。バギング関数baggingは、回帰分析、分類分析、生存分析を前提とし、Breimanの方法に従っている[1]。
bagging(formula,data,nbagg=25…)
 メインの引数の指定は、基本的には関数rpartと同じである。引数formulaには目的変数と説明変数を指定し、dataには用いるデータを指定する。引数nbaggでは、繰り返しの回数 を指定する。デフォルトは25になっている。関数rpartのパラーメタの調整は引数controlとrpart.controlを用いデフォルト値を替えることができる。
 関数printは、指定したモデルやnbaggなどを返す。関数summaryはbaggingの結果の要約を返すが、繰り返した毎回の結果を返すので、夥しい結果が返される。出力結果は引数nbaggに依存する。
 構築したモデルによるテストデータへの適応は、関数predictを用いる。

2.3 データと解析

 パッケージkernlabの中に用意されているデータspamを用いて、関数baggingの使用例を示す。パッケージkernlab はCRANミラーサイトからダウンロードできる。

> library(kernlab);data(spam)

 まず、学習用データとテスト用のデータセットを作成する。ここでは、データspamから2500個体をランダムに選び学習用とし、その残りをテスト用とする。

> set.seed(50)
> tr.num<-sample br="">> spam.train<-spam br="" tr.num="">> spam.test<-spam p="" tr.num="">

 次に、作成した学習データを用いて学習を行い、その結果を用いてテストデータを用いて予測・判別を行う。

>spam.bag<-bagging data="spam.train," nbagg="40) <br" type="">>spam.bagp<-predict p="" spam.bag="" spam.test="" type="class">
 テストデータにおける判別・誤判別のクロス表を次に示す。
>(spam.bagt<-table p="" spam.bagp="" spam.test="">
Spam.bagp
nonspamspam
nonspam123052
spam85734
 正しく判別できた比率(正解率)は次のコマンドで求めることができる。
> sum(diag(spam.bagt))/sum(spam.bagt)
[1] 0.934793

3.ブースティング

 ブースティング(boosting)は、与えた教師付きデータを用いて学習を行い、その学習結果を踏まえて逐次に重みの調整を繰り返すことで複数の学習結果を求め、その結果を統合・組み合わせ、精度を向上させる。

3.1 ブースティングのアルゴリズム

 ブースティングの中で最も広く知られているのはAdaBoostというアルゴリズムである。AdaBoostは、FreundとSchapierによって1996年に提案された[3]。その後、幾つかの変種(Discrite AdaBoost、Gentle AdaBoost、Real AdaBoost、Logit AdaBoost、Modest AdaBoostなど)が提案されている。そのアルゴリズムの詳細を説明する余裕がないので、大まかな共通点のみを次に示す。
(1) 重みの初期値w1iを生成する。
(2) 学習を行い重みの更新を繰り返す(t=1,2,・・・,T)。
   (a) 重みwtiを用いて弱学習器弱学習器の式を構築する。
   (b) 誤り率αt=errtを計算する。
   (c) 結果の信頼度βtを計算する。
   (d) 重みを更新する。 w(t+1)i=g(wti)
(3) 重み付き多数決で結果を出力する。2値判別の場合は
 提案された幾つかの方法の大きい違いは、重みの初期値の与え方、信頼度の計算と重みの更新の方法である。

3.2 パッケージと関数

 ブースティングを行うパッケージはboost、adaがある。パッケージboostはCRANダウンロードミラーサイトからダウンロードでき、パッケージadaは次のサイトからダウンロードできる。
 http://www.stat.lsa.umich.edu/~culpm/math/ada/img.html
 ローカルディスクにダウンロードしたzip形式で圧縮されたパッケージは、RGuiのメニューの「パッケージ」⇒「ローカルにあるzipファイルからパッケージをインストール」をクリックし、zipファイルを読み込むことでインストールできる。
 パッケージadaは、ブースティングの専用パッケージである。ブースティングを行う関数はadaである。関数adaの書き式を次に示す。
ada(formula,iter=50,type = c("discrete","real","logit","gentle"),…)
 引数formulaは前節の関数baggingと同じである。引数iterは繰り返しの回数で、デフォルトは50になっている。引数typeでは、4種類のブースティングの方法からひとつを指定する。デフォルトではdiscreteが指定されている。

3.3 データと解析

 本節でもspamデータを用いることにする。 次に繰り返しの回数を20にした使用例を示す。
> library(ada)
> spam.ada<-ada data="spam.trai," iter="20)</p" type="">
 学習結果を用いて、テストデータを当てはめるのには、関数predictを用いる。関数predictの書き式は基本的にはその他の回帰・判別関数と同じである。引数typeには、"vector"(予測値)、"prob"(確率)、 "both"(予測値と確率)などが指定できる。
> spam.adap<-predict br="" spam.ada="" spam.test="" type="vector">> (spam.adat<-table p="" spam.adap="" spam.test="">
Spam.adap
nonspamspam
nonspam122161
spam55764
> sum(diag(spam.adat))/sum(spam.adat)
[1] 0.9447882
 パッケージadaには、作図関数plot、varplot、pairsがある。関数plotは学習の繰り返しの回数と誤り率との対応図を作成する。関数plotにテストデータを引数として用いるとテストデータにおける繰り返しの回数と誤り率の対応図を作成することができる。またkappa引数を真(TRUE)とした場合はk統計量(kappa statistic; 多数決における一致性の指標)と学習の回数との対応関係図が作成される。
> plot(spam.ada,kappa=TRUE, spam.test[,-58],spam.test[,58])
学習回数と誤り率およびk系統計量との関係
図1 学習回数と誤り率およびk系統計量との関係

 関数varplotは、回帰・分類における変数の重要度を計算して図示する。現時点では若干不安定であり、更なるバージョンアップを期待する。
 現時点のブースティング関数boost、adaは、いずれも分類は2つクラスに限定されている。k個のクラスに対応するためには若干のテクニックが必要である。関数adaを用いたkクラスに対応する例が[4]に紹介されている。

4.ランダム森

 ランダム森(RF; random forest)は、バギングの提案者Breimanにより今世紀に提案された新しいデータ解析の方法である。

4.1 ランダム森のアルゴリズム

 RFのアルゴリズムを次に示す。
 (1) 与えられたデータセットから 組のブートストラップサンプルを作成する。
 (2) 各々のブートストラップサンプルデータを用いて未剪定の最大の決定・回帰木を作成する。ただし、分岐のノードはランダムサンプリングされた変数の中の最善のものを用いる。
 (3) 全ての結果を統合・組み合わせ(回帰の問題では平均、分類の問題では多数決)、新しい予測・分類器を構築する。
 バギングとRFの大きい違いは、バギングは全ての変数用いるが、RFでは変数をランダムサンプリングしたサブセットを用いることができるので、高次元データ解析に向いている。
 ランダムサンプリングする変数の数Mはユーザが自由に設定することができる。Breimanは、Mは変数の数の正の平方根をと取ることを勧めている。
 RFは、様々な工夫が施され、多くの長所を持っている。幾つかの長所は[5]で紹介している。

4.2 パッケージと関数

 ランダム森の専用パッケージrandomForestは、CRANダウンロードミラーサイトからダウンロードできる。ランダム森のメイン関数はrandomForestである。関数randomForestの書き式を次に示す。
randomForest(formula, data=NULL,…, subset, na.action=na.fail)
 関数randomForestの引数やそれに関連する関数は、関数bagging、adaより多い。表1に主な引数、表2には主な関連関数をまとめて示す。
表1 関数randomForestの主な引数
引数
formulaモデルの形式、y~x1+x3のように記する
x、y説明変数と目的変数、formulaの替わりに用いる
data、subset用いるデータ
na.action欠損値の表記型の指定
ntree木の数、デフォルト値は500である
mtry木の生成に用いる変数の数、デフォルトでは、分類の場合は、回帰の場合はn/3nは変数の総数
importance変数の重要度
・・・・・・

表2 関数randomForestと関連する主な関数
関数機能
print、summary結果の出力と要約の出力
plot木の数と誤り率との対応図
predict予測と判別
importance重要度の計算
varImpPlot分類に置ける変数の重要度のグラフ作成
classCenter分類におけるクラスの中心を求める
MDSPlotMDSの散布図を作成する
treesize用いた木のサイズ
varUsedRFに用いられた変数の頻度
・・・・・・

4.3 データと解析

 前節で用意したデータspamの学習データspam.trainを用いたrandomForestの使用例を示す。
> library(randomForest)
> spam.rf<-randomforest br="" data="spam.train,na.action=" na.omit="" type="">> print(spam.rf)
 結果のオブジェクトに、記録されている項目は関数summaryで確認できる。
> summary(spam.rf)
 それぞれの項目は$***で返すことができる。例えば、上記で行ったRFは回帰問題であるか、それとも分類問題であるかに関する情報は次のコマンドで返す。
> spam.rf$type
[1] "classification"
 木の数と誤判別率との対応関係は、$err.rateに記録される。関数plotを用いると$err.rateの折れ線グラフが作成される。次のコマンドの結果を図3に示す。
> plot(spam.rf)
図3 木の数と誤判別率との対応関係

 図3には3つの折れ線があるが、凡例がないので、どの線が何を示しているかを読み取るためには、spam.rf$err.rateと対応付ける必要がある。
> spam.rf$err.rate
OBBnonspamspam
[1,]0.104444440.095238100.11864407
[2,]0.103678930.089601770.12521151
<後略>
 返された結果には、 OOB(out-of-bag)がある。OOBは交差確認・検証法(cross-validation)における誤り率に対応するモデル評価の結果である。ランダム森では、作成したモデルの評価は、交差確認法および専用のテストデータセットを用いていない。ランダム森では、ブートストラップサンプルの3分の1をテスト用として外してモデルを作成し、外した3分の1を用いてテストを行う。OOBはこのテスト結果における誤判別率である。
 ランダム森では、データセットにおける変数の重要度を計算する。変数の重要度は次のように返すことができる。関数varImpPlotを用いてグラフで示すことができる。
>spam.rf$importance
MeanDecreaseGini
make4.7557913
address6.4192663
all10.7081099
<中略>
capitalLong72.4899123
capitalTotal51.4710153
> varImpPlot(spam.rf)
図4 変数の重要度(Gini係数)
 構築したRFのモデルを用いて新しいデータについて回帰・分類を行うのには関数predictを次のように用いる。
> spam.rfp<-predict br="" spam.rf="" spam.test="">> (spam.rft<-table p="" spam.rfp="" spam.test="">
Spam.rfp
nonspamspam
nonspam124240
spam73746
> sum(diag(spam.rft))/sum(spam.rft)
[1] 0.946216
 同じデータセットについてサポートベクトルマシンを用いて判別分析を行うとその正解率は0.9277で、ランダム森の結果より若干低い。

5.その他

 本稿で紹介した集団学習のバギング、ブースティング、ランダム森が実用化された歴史は長くない。特にランダム森はその方法が提案されたのも約5年の年月しか経っていないので、その内容を扱っている和書は見当たらない。ランダム森の回帰・分類の精度は高く、その適応性もよいので、幅広い応用が期待できる。バギングとブースティングに関しては[5]が詳しい。


アトリエ星のまど



2018年5月26日土曜日

2018年版Vue.jsでのオブジェクトと配列操作ベストプラクティス

はじめに

基本的に Vue は子要素の代入演算子は感知しません。
しかし、Array は公式が公表している、ラップした変更検知メソッドを利用して、操作をすればやりたい事はほぼ全て実現できるでしょう。
これらはAirbnb lint ruleから得られた経験から来た知見です。結構使いやすい。
; セミコロンを末尾に付けたくない人も多いと思いますが、そこはruleを上書きすればまぁ良いでしょう。
push や pop 程度など、まぁ知ってるでしょうていう軽いのは省いています。

ゴール

コンポーネントとストアの記法の統一

配列辺

規定回数繰り返す

よく見るairbnb lintで怒られるコード
for (let i=0;i<5;i++) {
    print(i)
}
改善。これはとても見やすいですね。
[...Array(5)].forEach((_, i) => { console.log(i) })
ちなみにこれは動きません。
Array(5).forEach((_, i) => { console.log(i) })

配列の特定インデックスの値を書き換える

リアクティブにならなくて辛いやつ
a = [{a:1},{b:2}]
a[1].b = 10
リアクティブで嬉しいやつ。
a = [{a:1},{b:2}]
a = a.splice(1, 1, {b:10})

軽く解説

spliceはまず開始indexを指定して、そこから何個取り除くのかを指定し、最後に指定した箇所に挿入する要素を渡せます。これはリアクティブでとても嬉しい。
あと、何個取り除くかの個数を0にすれば、単純に要素の挿入になり、とても良い感じです。
また、第3引数を入れなければ、普通に要素削除にもなります。
途中の要素挿入、追加、削除はspliceとりあえず使えばとても統一感が出そうな気がしますね。

computedやgetterの際のみ、特定要素を追加したい

data() {
    return {
        a: [
            { name: '田中', age: 18 },
            { name: '小林', age: 18 },
        ],
    }
},
これはとても悲しい例ですね。getterで副作用を発生させている。
store の getter でも this.a ならず、state.a バージョンを見たことあります。
computed: {
    personList() {
        this.a.forEach(item => {
            item.isMinority = item.age < 20
        })
        return this.a
    },
},
改善。map最高!
computed: {
    personList() {
        return this.a.map(item => ({ ...item, isMinority: item.age < 20 }))
    },
},

foreach

まぁ、よくみるやつ
const a = [1,2,3]
for (const i in a) {
    console.log(i, a[i])
}

for (const i of a) {
    console.log(i)
}
lintで叱られないし、配列っぽくてこっちのが良い気がする
const a = [1,2,3]
a.forEach((value, i) => {
    console.log(i, value)
})

a.forEach(value => {
    console.log(value)
})

break foreach

皆さんこういうのやりたいですよね
const a = [44,99,55,33]

for (i of a) {
    if (i === 55) break
    console.log(i)
}
これでどうでしょか。some最高!
const a = [44,99,55,33]

a.some(i => {
    if (i === 55) return true
    console.log(i)
})

配列から特定の値を検索して、それの値を変えたい

よくみるやつ。リアクティブにならなくてとてもかなしい。Vue.set使えばいけるけど、storeだと使えないので、記法を統一したいですよね。
const a = [44,99,55,33]

for (i in a) {
    if (a[i] === 55) {
        a[i] = 4649
        break
    }
}
これはどうでしょうか。
const a = [44,99,55,33]

const key = a.findIndex(i => i === 55)
if (key !== -1) {
    a.splice(key, 1, 4649)
}

オブジェクト辺

プロパティを上書き・追加する

リアクティブじゃなくてとても悲しいやつ
let a = {
    name: '田中',
    age: 18,
}

a.age = 20
これはリアクティブでとても嬉しい
let a = {
    name: '田中',
    age: 18,
}

a = { ...a, age: 20 }

プロパティを削除する

リアクティブじゃなくて悲しいやつ
let a = {
    name: '田中',
    type: 'スーパーマン',
    age: 18,
}

delete(a.age)
リアクティブで嬉しいやつ。
let a = {
    name: '田中',
    type: 'スーパーマン',
    age: 18,
}

let clone = { ...a }
delete(clone.age)
a = clone

最後に

如何だったでしょうか?
統一された良いコードを頑張って作っていきましょう!