2011年12月6日火曜日

PostgreSQLで統計解析 PL/R 基礎編 : PostgreSQL Advent Calendar #6


PostgreSQL Advent Calendar 12/6 です。

ネタを決めるにあたり、analyticsをテーマに何かないものかと探してみたら、
PL/R(R手続き型言語)なるものがあるそうで。

Rは統計解析分野で人気のプログラミング言語。
オープンソースで、コミュニティの活動も活発なようです。
参考:R Advent Calendar 2011 : ATND

では、PL/Rを導入して、ちょこっと触ってみます。


Install
今回構築した環境は下記。
・Mac OS X 10.6 Snow Leopard
・gcc 4.2.1
・postgresql 9.0.4
・R 2.14.0
・plr-8.3.0.13

Windows,Linuxへのインストールは下記をご参考
R と PostgreSQL - RjpWiki

まずRをインストール。
(macのhomebrewを使用)
brew install r
Error: This formula requires a fortran compiler
失敗。fortranコンパイラをインストールして再チャレンジ。
brew install gfortran
brew install r
OK。インストール時に一般的なインストール先に
リンクさせた方がいいよとメッセージが出るので、
sudo ln -s "/usr/local/Cellar/r/2.14.0/R.framework" /Library/Frameworks
これでRのインストールは完了。
なお、パッケージインストールも可能。
参考:R for Mac OS X

次にPL/Rをインストール。
ソースは→ http://joeconway.com/plr/ から入手。
su - postgres
cd /path-to-postgres_source/contrib #ここにPL/Rのソースを配置
tar zxf plr-8.3.0.13.tar.gz
cd plr
export R_HOME=/Library/Frameworks/R.framework/Resources
make
make install
PL/Rのインストール完了。テスト用のDBを作成して言語を登録。
createdb r_test
cd /path-to-pgsql/contrib
psql r_test < plr.sql
psql -c "SELECT * FROM pg_language WHERE lanName = 'plr'" r_test #確認
これで導入完了。


Try working

PL/Rのドキュメントにある集約関数をテストしてみます。
(中央値を返す集約関数medianを作成)
create or replace function r_median(_float8) returns float as '
  median(arg1)
' language 'plr';
CREATE AGGREGATE median (
  sfunc = plr_array_accum,
  basetype = float8,
  stype = _float8,
  finalfunc = r_median
);

SELECT median(v)
FROM (values(1.0),(2.5),(5.7),(3.4),(-0.9)) AS t(v);
-- => select 2.5
集約関数はfloat8を配列に集約して最後にr_median(_float8)を呼び出し、
Rの関数medianを計算しています。

ポイントはデータ型の違い。
R言語はベクトル処理言語であり、データはベクトルで持ちます。
例えば、上記のmedianの計算は、Rでは下記のように行います。
x <- c(1.0, 2.5, 5.7, 3.4, -0.9) #ベクトルを作成してxに代入
median(x) # => [1] 2.5
postgresからRへの引数の受け渡しについては、
・スカラ ⇒ 単一要素のベクトル(例外あり)
・ 一次元配列 ⇒ 複数要素のベクトル
・二次元配列 ⇒ 行列
・三次元配列 ⇒ 三次元配列
・三次元以上の配列 ⇒ サポートせず
・ 複合型 ⇒ データフレーム
となります。
参考:Passing Data Values

では最後に、統計解析の基礎として相関係数を計算する関数を作成してみます。
参考:R-Source
CREATE OR REPLACE FUNCTION correlation(_float8, _float8) RETURNS float8 AS '
 cor(arg1, arg2)
' LANGUAGE 'plr';
列xと列yの相関係数を計算する場合は下記で。
SELECT correlation(array_agg(x),array_agg(y))
FROM (values(0.7,1.9),(-1.6,0.8),(-0.2,1.1),(-1.2,0.1),(-0.1,-0.1)
      ,(3.4,4.4),(3.7,5.5),(0.8,1.6),(0.0,4.6),(2.0,3.4)) AS t(x,y);
-- => select 0.795102...

以上、簡単にさわってみました。
それほど敷居は高くないように感じますが、どういう用途に使ったものか...


Be continued
応用編に続く ...のか?


Next
明日はs87さんです。よろしくお願いします。