はじめに
本日時点(2016/09/26)での最新の環境で、MADlibの環境を構築してみたいと思います。
MADlibは「Big Data Machine Learning in SQL」との事で、PostgreSQL( or Greenplum or HAWQなどのPostgreSQLの仲間達)上で、統計や機械学習などのアルゴリズムをユーザ定義関数として実装したもので、SQLを使って機械学習なんかができる優れものです。
ちなみに、自分は普段PostgreSQLを普段使わない、機械学習とかほぼ知らない、程度の知識なので、間違った情報が含まれているかもしれませんので、ご注意ください。
今回は、基本的に下記の公式ドキュメントをやってみた形です。詳細はこちらをご参照ください。
今回の環境
- IDCF Cloud
-
CentOS 7.2 +
yum update
- SCL版 PostgreSQL 9.5
- MADlib Binaries v1.9.1
基本的にはすべてrpmでインストール可能なので、全然難しくありませんが、SCLは馴染みが薄いかもしれません。
ちょっと古い(基本的には変わっていません)ですが、下記のIDCF Tech-Blogあたりを参照頂ければと思います。
CentOS + PostgreSQL(SCL)のインストール
以降は概ね、
の内容になります。CentOS 7.2 + SCLなので、少し違いますがMADlibの部分は殆ど同じです。
仮想マシンの起動
IDCF Cloudで、標準テンプレートのCentOS7.2から仮想マシンを起動します。下記参照していただければ、問題なくできるかと思います。
インストール後に、yum -y update
して再起動しておいてください。
SCL版 PostgreSQLのインストール
まずは、SCLを有効にします。(sclのレポジトリのrpmを入れるだけ)
# yum -y install centos-release-scl centos-release-scl-rh
SCL版のPostgreSQL 9.5をインストールします。(これもrpm入れるだけ。)
MADLibでは、PL/Pythonも必要になるので、こちらも一緒にインストールします。
# yum -y install rh-postgresql95-postgresql-server rh-postgresql95-postgresql-plpython
インストールできたら、DBの初期化をして起動します。scl enable rh-postgresql95 bash
を忘れないようにお願いします。
# scl enable rh-postgresql95 bash
# postgresql-setup --initdb
* Initializing database in '/var/opt/rh/rh-postgresql95/lib/pgsql/data'
* Initialized, logs are in /var/lib/pgsql/initdb_rh-postgresql95-postgresql.log
# systemctl start rh-postgresql95-postgresql
PostgreSQLが起動したら、DB上のpostgresユーザのパスワードを設定します。
# su - postgres
$ scl enable rh-postgresql95 bash
$ psql
psql (9.5.2)
"help" でヘルプを表示します.
postgres=# ALTER USER postgres with password '6zCYTSn4';
ALTER ROLE
postgres=#
$ exit
$ exit
#
パスワードを設定したら、localhostからの認証をmd5へ変更します。(MADlibをセットアップするときにパスワード認証しか受け付けてくれなかった。)
# vi /var/opt/rh/rh-postgresql95/lib/pgsql/data/pg_hba.conf
# IPv4 local connections:
host all all 127.0.0.1/32 md5
127.0.0.1/32からの認証はmd5と設定しています。
PostgreSQLでは、DateStyleがiso, ymd
がデフォルトとなっていますが、MADLibのinstall-checkではiso, myd
じゃないと失敗してしまうのでiso, myd
へ変更しておきます。
# vi /var/opt/rh/rh-postgresql95/lib/pgsql/data/postgresql.conf
# datestyle = 'iso, ymd'
datestyle = 'iso, mdy'
# systemctl restart rh-postgresql95-postgresql
MADLibのインストール
MADlibも公式からrpmでbinaryが提供されているので、こちらを利用してインストールします。
# yum -y install https://dist.apache.org/repos/dist/release/incubator/madlib/1.9.1-incubating/apache-madlib-1.9.1-incubating-bin-Linux.rpm
それでは、MADLibをPostgreSQLへセットアップしていきます。
(以降、ログを誤って消してしまったので、記憶で書いてます。間違ってるかも。。。)
# su - postgres
$ scl enable rh-postgresql95 bash
$ /usr/local/madlib/bin/madpack -p postgres -c postgres@127.0.0.1 install
Password for user postgres:
インストールしたPostgreSQLへセットアップしたMADLibが正しくインストールできているかチェックします。
$ /usr/local/madlib/bin/madpack -p postgres -c postgres@127.0.0.1 install-check
Password for user postgres:
全ての項目でOKであれば、問題ないと思います。
Quick Startしてみる
以降は概ね、
の内容になります。ロジスティック回帰を使って、学習と予測をしていきます。
このテスト問題では、心不全の患者のデータで、以下のようなデータを持っています。
- second_attack
- 1年以内に、心臓発作を再発したかどうか。
- treatment
- 患者がanger control(怒りのコントロール)の治療を受けたかどうか。
- trait_anxiety
- trait anxiety(特性不安)の係数。(高いほど多くの不安に成りやすい。)
少々良くわかりませんが、まぁ、だいたいこんな感じだと思います。
これを使って、treatment(怒りのコントロールできる/できない)とtrait_anxiety(どのぐらい不安症)からsecond_attack(心臓発作再発)が発生するかどうかを予測します。
まずは、学習用のデータを作ります。
# su - postgres
$ scl enable rh-postgresql95 bash
$ psql
psql (9.5.2)
"help" でヘルプを表示します.
postgres=#
DROP TABLE IF EXISTS patients, patients_logregr, patients_logregr_summary;
CREATE TABLE patients( id INTEGER NOT NULL,
second_attack INTEGER,
treatment INTEGER,
trait_anxiety INTEGER);
INSERT INTO patients VALUES
(1, 1, 1, 70),
(3, 1, 1, 50),
(5, 1, 0, 40),
(7, 1, 0, 75),
(9, 1, 0, 70),
(11, 0, 1, 65),
(13, 0, 1, 45),
(15, 0, 1, 40),
(17, 0, 0, 55),
(19, 0, 0, 50),
(2, 1, 1, 80),
(4, 1, 0, 60),
(6, 1, 0, 65),
(8, 1, 0, 80),
(10, 1, 0, 60),
(12, 0, 1, 50),
(14, 0, 1, 35),
(16, 0, 1, 50),
(18, 0, 0, 45),
(20, 0, 0, 60);
このデータを使って、ロジスティック回帰を使って学習していきます。
SELECT madlib.logregr_train(
'patients', -- source table
'patients_logregr', -- output table
'second_attack', -- labels
'ARRAY[1, treatment, trait_anxiety]', -- features
NULL, -- grouping columns
20, -- max number of iteration
'irls' -- optimizer
);
この辺まで来ると、私もまだよくわかりません。ドキュメント見てください!(この辺からだんだん適当になります。ごめんなさい。)
Logistic Regression
ロジスティック回帰を多少なりとも理解していないと、ちょっと難しいのですかね。
良く分かってないですが、これで、patients_logregr tableに学習結果(model)が出来上がっているはずです。見てみましょう。
postgres=# \x on
拡張表示は on です。
postgres=# SELECT * from patients_logregr;
-[ RECORD 1 ]------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
coef | {-6.36346994178187,-1.02410605239327,0.119044916668606}
log_likelihood | -9.41018298388876
std_err | {3.21389766375091,1.17107844860318,0.0549790458269303}
z_stats | {-1.9799852414576,-0.874498248699553,2.1652779686892}
p_values | {0.0477051870698109,0.381846973530448,0.0303664045046153}
odds_ratios | {0.00172337630923231,0.359117354054955,1.12642051220895}
condition_no | 326.081922791559
num_rows_processed | 20
num_missing_rows_skipped | 0
num_iterations | 5
variance_covariance | {{10.3291381930635,-0.474304665195729,-0.171995901260048},{-0.474304665195729,1.37142473278283,-0.00119520703381591},{-0.171995901260048,-0.00119520703381591,0.00302269548003971}}
なんか入ってるんで、出来てるに違いない。
それでは、この学習モデルを使って、second_attack(心臓発作再発)を予測してみましょう。とりあえずは、元データを使って、予測してみましょう。
postgres=# \x off
拡張表示は off です。
postgres=# SELECT id, second_attack, madlib.logregr_predict(coef, ARRAY[1, treatment, trait_anxiety]), madlib.logregr_predict_prob(coef, ARRAY[1, treatment, trait_anxiety])
FROM patients p, patients_logregr m ORDER BY id;
id | second_attack | logregr_predict | logregr_predict_prob
----+---------------+-----------------+----------------------
1 | 1 | t | 0.720223028941525
2 | 1 | t | 0.894354902502046
3 | 1 | f | 0.192269541755172
4 | 1 | t | 0.685513072239347
5 | 1 | f | 0.16774788150886
6 | 1 | t | 0.79809810891514
7 | 1 | t | 0.928568075752502
8 | 1 | t | 0.95930576369357
9 | 1 | t | 0.877576117431451
10 | 1 | t | 0.685513072239347
11 | 0 | t | 0.586700895943316
12 | 0 | f | 0.192269541755172
13 | 0 | f | 0.116032010632995
14 | 0 | f | 0.0383829143134989
15 | 0 | f | 0.0674976224147607
16 | 0 | f | 0.192269541755172
17 | 0 | t | 0.545870774302622
18 | 0 | f | 0.267675422387135
19 | 0 | f | 0.398618639285114
20 | 0 | t | 0.685513072239347
(20 行)
-
second_attack
は元データ上のsecond_attackです。つまり、心臓発作が実際に起きたのか、起きなかったのか。 -
logregr_predict
は予測結果で、true/falseが返ってきています。 -
logregr_predict_prob
は予測結果で、確率が返ってきています。50%以上が上記のtrueのようですね。
ということで、元データを使って予測してみると、20件中15件は予測が当たっていることが分かります。
最後に
ということで、ロジスティック回帰などがある程度わかっている人であれば、SQLを使って簡単に機械学習が出来ることがわかりました。
まぁ、僕の場合は「ある程度わかっている」の部分が結構問題ですけど。。。