MADlibを導入することによって、これらのアルゴリズムをPostgreSQLのユーザ定義関数の形で使うことのでき、データベースサーバの内部でデータ分析の処理できるようになります。
今回は、このMADlibの導入方法から動作確認、ロジスティック回帰分析における簡単な使い方までをご紹介します。
■MADlibとは何か
MADlibは、もともとはGreenplumというPostgreSQLをベースにしたMPP製品(DWH用RDBMS)を開発していた企業が開発していたライブラリで、Greenplumで利用できるように開発されていたものでした。
2015年9月に、Greenplum(を買収したEMC)がMADlib(や他のソフトウェア類)をApache Foundationに寄贈し、MADlib は Apache Incubator のプロジェクトとなりました。
そして、4月6日に Apache Incubator のプロジェクトになって最初の GA(Generally Available) リリースである1.9がリリースされました。
- MADlib
http://madlib.incubator.apache.org/ - MADlib 1.9 User Documentation for MADlib
http://madlib.incubator.apache.org/docs/latest/index.html
- Linear Regression
- Logistic Regression
- Multinomial Logistic Regression
- Cox Proportional Hazards Regression
- Principal Component Analysis (PCA)
- Association Rules (Apriori)
- Decision Trees
- Random Forest
- Clustering (K-means)
- Naïve Bayes
- Support Vector Machines (SVM)
このようなアーキテクチャを取ることによって、分析するデータをデータベースから取り出すことなくデータベース内で処理できるようになります。
なお、1月に開催された FOSDEM'16 でも MADlib が紹介されていたようですので、そちらのプレゼン資料も参考にしてください。
- MADlib: Distributed In-Database Machine Learning for Fun and Profit
https://fosdem.org/2016/schedule/event/hpc_bigdata_madlib/
■動作確認環境
今回の動作確認環境は以下の通りです。
- CentOS 6.6 (x86_64)
- PostgreSQL 9.5.2 (コミュニティ版RPM)
- cmake 2.8.12
# yum install -y cmake
MADlibは1.9ブランチの最新のコードを使っていますが、オリジナルのコードには
- ビルドスクリプト内で呼び出しているリダイレクト用URLが利用不可能でインストール失敗。
- PostgreSQL 9.5で動作させる場合に一部関数定義に不具合でインストール後のテストに失敗。
ソースコードは以下から確認・取得可能です。
- 修正版v1.9
https://github.com/snaga/incubator-madlib/tree/v1.9 - オリジナル版v1.9
https://github.com/apache/incubator-madlib/tree/v1.9 - 修正版とオリジナル版の差分
https://github.com/apache/incubator-madlib/compare/v1.9...snaga:v1.9
■ソースコードからのビルド
それではソースコードからビルドします。PostgreSQL 9.5が既にインストールされていることを前提としています。
手順をスクリプトにしたものは以下にありますので、詳細はそちらを参照してください。
- build_madlib.sh
https://gist.github.com/snaga/d77124c3cdf25abafb3ae4aca7fdc02a
- Installation Guide
https://cwiki.apache.org/confluence/display/MADLIB/Installation+Guide
[root@localhost madlib]# git clone https://github.com/snaga/incubator-madlib.git Initialized empty Git repository in /tmp/madlib/incubator-madlib/.git/ remote: Counting objects: 23090, done. remote: Compressing objects: 100% (55/55), done. remote: Total 23090 (delta 21), reused 0 (delta 0), pack-reused 23032 Receiving objects: 100% (23090/23090), 15.32 MiB | 1.23 MiB/s, done. Resolving deltas: 100% (15912/15912), done. [root@localhost madlib]# cd incubator-madlib [root@localhost incubator-madlib]# git checkout v1.9 Branch v1.9 set up to track remote branch v1.9 from origin. Switched to a new branch 'v1.9' [root@localhost incubator-madlib]# git log -1 commit a3c1eab2a92dd19c8a3f098e59cf56b8b974a3bb Merge: a152c25 054136b Author: Satoshi NagayasuDate: Sun Apr 10 12:26:28 2016 +0900 Merge pull request #3 from snaga/fix/v1.9-pg9.5 Fix to add support for PostgreSQL 9.5. [root@localhost incubator-madlib]# ls CMakeLists.txt LICENSE RELEASE_NOTES cmake doc methods DISCLAIMER NOTICE ReadMe.txt configure examples pom.xml HAWQ_Install.txt README.md ReadMe_Build.txt deploy licenses src [root@localhost incubator-madlib]#
次にconfigureスクリプトを実行します。この時、OSバンドル版のPythonとPostgreSQL 9.5を見つけられるように明示的にPATHを通して実行します。
[root@localhost incubator-madlib]# env PATH=/usr/bin:/usr/pgsql-9.5/bin:$PATH ./configure -- The C compiler identification is GNU 4.4.7 -- The CXX compiler identification is GNU 4.4.7 (...) -- Could NOT find Boost -- No sufficiently recent version (>= 1.47) of Boost was found. Will download. -- Found PythonInterp: /usr/bin/python (found version "2.6.6") -- Found PostgreSQL: /usr/pgsql-9.5/bin/postgres -- Found PostgreSQL_9_5: /usr/pgsql-9.5/bin/postgres >> Adding PostgreSQL 9.5 (x86_64) to target list... -- Could NOT find Greenplum (missing: GREENPLUM_EXECUTABLE) -- Could NOT find HAWQ (missing: HAWQ_EXECUTABLE) (...) -- Configuring done -- Generating done -- Build files have been written to: /tmp/madlib/incubator-madlib/build [root@localhost incubator-madlib]#
configureが終わったら、buildディレクトリに移動してmakeを実行します。すると、依存するライブラリ類をダウンロードしてビルドが始まります。
[root@localhost incubator-madlib]# cd build/ [root@localhost build]# make [ 0%] Performing download step (download, verify and extract) for 'EP_boost' -- downloading... src='http://sourceforge.net/projects/boost/files/boost_1_47_0.tar.gz' dst='/disk/disk1/snaga/madlib/incubator-madlib/build/third_party/downloads/boost_1_47_0.tar.gz' timeout='none' -- [download 0% complete] -- [download 1% complete] (...) [ 28%] Validating and copying svec_util/src/pg_gp/sql/svec_test.sql_in [ 28%] Validating and copying svec_util/src/pg_gp/svec_util.sql_in [ 29%] Validating and copying stemmer/src/pg_gp/porter_stemmer.sql_in [ 29%] Built target sqlFiles_postgresql Scanning dependencies of target madlib_postgresql_9_5 [ 29%] Building CXX object src/ports/postgres/9.5/CMakeFiles/madlib_postgresql_9_5.dir/__/__/__/modules/linear_systems/sparse_linear_systems.cpp.o [ 29%] Building CXX object src/ports/postgres/9.5/CMakeFiles/madlib_postgresql_9_5.dir/__/__/__/modules/linear_systems/dense_linear_systems.cpp.o [ 29%] Building CXX object src/ports/postgres/9.5/CMakeFiles/madlib_postgresql_9_5.dir/__/__/__/modules/assoc_rules/assoc_rules.cpp.o (...) [ 98%] Validating and copying svec_util/src/pg_gp/sql/svec_test.sql_in [100%] Validating and copying svec_util/src/pg_gp/svec_util.sql_in [100%] Validating and copying stemmer/src/pg_gp/porter_stemmer.sql_in [100%] Built target sqlFiles_hawq [root@localhost build]#
makeが終わったら、make packageコマンドでRPMファイルを作成します。
[root@localhost build]# make package [ 1%] Built target EP_boost [ 2%] Built target EP_eigen (...) CPack: Create package CPackRPM: Will use USER specified spec file: /tmp/madlib/incubator-madlib/deploy/madlib.spec.in CPack: - package: /tmp/madlib/incubator-madlib/build/madlib-1.9-Linux.rpm generated. [root@localhost build]# ls CMakeCache.txt Makefile doc third_party CMakeFiles _CPack_Packages install_manifest.txt CPackConfig.cmake cmake_install.cmake madlib-1.9-Linux.rpm CPackSourceConfig.cmake deploy src [root@localhost build]#
これでRPMパッケージの完成です。
■インストール
作成したRPMパッケージをrpmコマンドでインストールします。
[root@localhost build]# rpm -ivh madlib-1.9-Linux.rpm Preparing... ########################################### [100%] 1:madlib ########################################### [100%] [root@localhost build]#
■データベースへのデプロイと回帰テスト
それでは、MADlibをPostgreSQLのデータベースで使えるようにセットアップします。
まずデータベースを作成します。ここではtestdbとしています。
[snaga@localhost ~]$ createdb -U postgres -h 127.0.0.1 testdb
データベースを作成したら、MADlibをデータベースにデプロイします。デプロイするにはmadpackコマンドにinstallオプションを渡して実行します。
以下はtestdbで使えるようにMADlibをインストールしているところです。接続するデータベースにはホスト127.0.0.1、ポート5432、データベース名testdb、ユーザ名postgresを指定しています。
[snaga@localhost ~]$ /usr/local/madlib/bin/madpack -s madlib -p postgres -c postgres@127.0.0.1:5432/testdb install madpack.py : INFO : Detected PostgreSQL version 9.5. madpack.py : INFO : *** Installing MADlib *** madpack.py : INFO : MADlib tools version = 1.9 (/usr/local/madlib/Versions/1.9/bin/../madpack/madpack.py) madpack.py : INFO : MADlib database version = None (host=127.0.0.1:5432, db=testdb, schema=madlib) madpack.py : INFO : Testing PL/Python environment... madpack.py : INFO : > Creating language PL/Python... madpack.py : INFO : > PL/Python environment OK (version: 2.6.6) madpack.py : INFO : Installing MADlib into MADLIB schema... madpack.py : INFO : > Creating MADLIB schema madpack.py : INFO : > Creating MADLIB.MigrationHistory table madpack.py : INFO : > Writing version info in MigrationHistory table madpack.py : INFO : > Creating objects for modules: madpack.py : INFO : > - array_ops madpack.py : INFO : > - bayes madpack.py : INFO : > - crf (...) madpack.py : INFO : > - sample madpack.py : INFO : > - summary madpack.py : INFO : > - kmeans madpack.py : INFO : > - pca madpack.py : INFO : > - validation madpack.py : INFO : MADlib 1.9 installed successfully in MADLIB schema. [snaga@localhost ~]$
「MADlib 1.9 installed successfully in MADLIB schema」と表示されたらインストール成功ですが、インストールされたものが正しく動作するかどうか、madpackコマンドで回帰テストを実行します(install-checkオプション)。
[snaga@localhost ~]$ /usr/local/madlib/bin/madpack -s madlib -p postgres -c postgres@127.0.0.1:5432/testdb install-check madpack.py : INFO : Detected PostgreSQL version 9.5. TEST CASE RESULT|Module: array_ops|array_ops.sql_in|PASS|Time: 98 milliseconds TEST CASE RESULT|Module: bayes|gaussian_naive_bayes.sql_in|PASS|Time: 137 milliseconds TEST CASE RESULT|Module: bayes|bayes.sql_in|PASS|Time: 299 milliseconds (...) TEST CASE RESULT|Module: pca|pca_project.sql_in|PASS|Time: 533 milliseconds TEST CASE RESULT|Module: pca|pca.sql_in|PASS|Time: 2098 milliseconds TEST CASE RESULT|Module: validation|cross_validation.sql_in|PASS|Time: 1672 milliseconds [snaga@localhost ~]$
すべてのテストに「PASS」と出れば問題ありません。
なお、PostgreSQL 9.5でinstall-checkを実行している際、以下のようなエラーが出る可能性がありますが、ここでは特に気にしなくて構いません(手元の9.5の環境ではこのエラーが出て、9.4では再現しませんでした)。
TEST CASE RESULT|Module: validation|cross_validation.sql_in|PASS|Time: 1741 milliseconds madpack.py : ERROR : SQL command failed: SQL: DROP OWNED BY madlib_19_installcheck CASCADE; ERROR: could not open relation with OID 551341
最後に管理者でGRANTを発行して、他のユーザもmadlibスキーマのオブジェクトを使えるように設定します。(MADlib関連のオブジェクトはすべてmadlibスキーマにインストールされます)
testdb=# GRANT ALL ON SCHEMA madlib TO public; GRANT testdb=#
■ロジスティック回帰のサンプルによる動作確認
それでは、MADlibの Quick Start Guide for Users からロジスティック回帰のサンプルを動かしてみます。
- Quick Start Guide for Users
https://cwiki.apache.org/confluence/display/MADLIB/Quick+Start+Guide+for+Users
testdb=> CREATE TABLE patients( id INTEGER NOT NULL, testdb(> second_attack INTEGER, testdb(> treatment INTEGER, testdb(> trait_anxiety INTEGER); CREATE TABLE testdb=> INSERT INTO patients VALUES testdb-> (1, 1, 1, 70), testdb-> (3, 1, 1, 50), testdb-> (5, 1, 0, 40), testdb-> (7, 1, 0, 75), testdb-> (9, 1, 0, 70), testdb-> (11, 0, 1, 65), testdb-> (13, 0, 1, 45), testdb-> (15, 0, 1, 40), testdb-> (17, 0, 0, 55), testdb-> (19, 0, 0, 50), testdb-> (2, 1, 1, 80), testdb-> (4, 1, 0, 60), testdb-> (6, 1, 0, 65), testdb-> (8, 1, 0, 80), testdb-> (10, 1, 0, 60), testdb-> (12, 0, 1, 50), testdb-> (14, 0, 1, 35), testdb-> (16, 0, 1, 50), testdb-> (18, 0, 0, 45), testdb-> (20, 0, 0, 60); INSERT 0 20 testdb=> \d patients Table "public.patients" Column | Type | Modifiers ---------------+---------+----------- id | integer | not null second_attack | integer | treatment | integer | trait_anxiety | integer | testdb=> select * from patients limit 5; id | second_attack | treatment | trait_anxiety ----+---------------+-----------+--------------- 1 | 1 | 1 | 70 3 | 1 | 1 | 50 5 | 1 | 0 | 40 7 | 1 | 0 | 75 9 | 1 | 0 | 70 (5 rows) testdb=>
この例は患者の例で、treatmentとtrait_anxietyが説明変数で、treatmentは anger control の治療を受けたどうか(カテゴリカル変数)、trait_anxietyは不安症の度合い(数値が高いほど度合が高い連続型変数)です。second_attackは被説明変数で「1年以内に二度目の発作が起こったかどうか」です。
詳細は以下を参照してください。
- Logistic Regression
http://faculty.cas.usf.edu/mbrannick/regression/Logistic.html
testdb=> SELECT madlib.logregr_train( testdb(> 'patients', -- source table testdb(> 'patients_logregr', -- output table testdb(> 'second_attack', -- labels testdb(> 'ARRAY[1, treatment, trait_anxiety]', -- features testdb(> NULL, -- grouping columns testdb(> 20, -- max number of iteration testdb(> 'irls' -- optimizer testdb(> ); logregr_train --------------- (1 row) testdb=>
上記の例では、学習用データのテーブルを patients 、学習した結果の出力を patients_logregr テーブル、被説明変数を second_attack 、説明変数を切片(1)と treatment, trait_anxiety に指定して学習させています。
その他の引数の詳細は以下を参照してください。
- MADlib: Logistic Regression
http://madlib.incubator.apache.org/docs/latest/group__grp__logreg.html
testdb=> \x on Expanded display is on. testdb=> 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}} testdb=>
また、以下のように各説明変数の係数やp値だけを表形式で表示することもできます。
testdb=> \x off Expanded display is off. testdb=> SELECT unnest(array['intercept', 'treatment', 'trait_anxiety']) as attribute, testdb-> unnest(coef) as coefficient, testdb-> unnest(std_err) as standard_error, testdb-> unnest(z_stats) as z_stat, testdb-> unnest(p_values) as pvalue, testdb-> unnest(odds_ratios) as odds_ratio testdb-> FROM patients_logregr; attribute | coefficient | standard_error | z_stat | pvalue | odds_ratio ---------------+-------------------+--------------------+--------------------+--------------------+--------------------- intercept | -6.36346994178187 | 3.21389766375091 | -1.9799852414576 | 0.0477051870698109 | 0.00172337630923231 treatment | -1.02410605239327 | 1.17107844860318 | -0.874498248699553 | 0.381846973530448 | 0.359117354054955 trait_anxiety | 0.119044916668606 | 0.0549790458269303 | 2.1652779686892 | 0.0303664045046153 | 1.12642051220895 (3 rows) testdb=>
それではこの学習したモデルを使って予測をしてみましょう。
ここでは再度学習用データを使ってテストすることでトレーニングエラーを確認してみます。
実行するクエリは以下です。second_attack_predictは二回目の心臓発作が起こるかどうかの予測、second_attack_boolは実際に起こったかどうかのフラグ、correctは予測が当たったかどうかのフラグです。
WITH TEMP AS ( SELECT p.id, madlib.logregr_predict(coef, ARRAY[1, treatment, trait_anxiety]) as second_attack_predict, CASE p.second_attack WHEN 1 THEN true ELSE false END AS second_attack_bool FROM patients p, patients_logregr f ) SELECT id, second_attack_predict, second_attack_bool, second_attack_predict = second_attack_bool AS correct FROM temp ORDER BY id;
実行すると以下のような結果が得られ、20件中15件は予測が当たっていることが分かります。
testdb=> WITH TEMP AS ( testdb(> SELECT p.id, testdb(> madlib.logregr_predict(coef, ARRAY[1, treatment, trait_anxiety]) as second_attack_predict, testdb(> CASE p.second_attack testdb(> WHEN 1 THEN true testdb(> ELSE false testdb(> END AS second_attack_bool testdb(> FROM patients p, patients_logregr f testdb(> ) testdb-> SELECT id, testdb-> second_attack_predict, testdb-> second_attack_bool, testdb-> second_attack_predict = second_attack_bool AS correct testdb-> FROM temp testdb-> ORDER BY id; id | second_attack_predict | second_attack_bool | correct ----+-----------------------+--------------------+--------- 1 | t | t | t 2 | t | t | t 3 | f | t | f 4 | t | t | t 5 | f | t | f 6 | t | t | t 7 | t | t | t 8 | t | t | t 9 | t | t | t 10 | t | t | t 11 | t | f | f 12 | f | f | t 13 | f | f | t 14 | f | f | t 15 | f | f | t 16 | f | f | t 17 | t | f | f 18 | f | f | t 19 | f | f | t 20 | t | f | f (20 rows) testdb=>
■まとめ
以上、駆け足ではありましたが、MADlibの紹介から導入方法、簡単な使い方までを紹介してきました。
大量データを処理する場合、データベースからデータを取り出さずに(=クライアントに転送せずに)処理できる「In-Database処理」には非常に大きなアドバンテージがあります。今後はこのようなテクノロジーがさらに普及するのではないかと考えています。
この領域に興味がある方は、ぜひ一度試してみてください。PostgreSQLの可能性がより広がると思います。
では。
0 件のコメント:
コメントを投稿