Copyright 2015 Uptime Technologies, LLC. All rights reserved. 1
PL/Pythonで独⾃の集約関数を
作ってみる
アップタイム・テクノロジーズ
永安 悟史
第6回 PostgreSQLアンカンファレンス
⽬次
• なぜPL/Pythonで集約関数なのか?
• PostgreSQLにおける集約関数の作り⽅
• PL/Pythonの関数の作り⽅
• min(),max(),avg()を実装してみる
• 単回帰分析を⾏う集約関数を実装してみる
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 2
なぜPL/Pythonで集約関数なのか?
• Pythonとデータ処理
• データ処理と集約関数
• プロシージャ・UDFによるIn-Database処理
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 3
PostgreSQLにおける集約関数の作り⽅
• CREATE AGGREGATEコマンドによる定義
– 実⾏中の内部状態を処理するUDF:sfunc
– 内部状態を保持するデータ型:state_data_type
– 最終的な結果を出⼒するUDF:ffunc
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 4
CREATE AGGREGATE myagg (arg1, arg2, ...)
(
SFUNC = sfunc,
STYPE = state_data_type,
FINALFUNC = ffunc
);
ユーザ定義の集約
https://www.postgresql.jp/document/9.4/html/xaggr.html
CREATE AGGREGATE
https://www.postgresql.jp/document/9.4/html/sql-createaggregate.html
sfunc
args
state
sfunc
args
state
ffunc
return
PL/Pythonの関数の作り⽅
• CREATE FUNCTION
– 単に中⾝がPythonスクリプトになるだけ
• データベースにアクセスする場合には plpy モジュール
– CのUDFで⾔うところのSPI関数のようなもの
– import plpy
• 注意すべきところ
– plpython.soからリンクされているPythonのバージョン
– データの相互マッピング(+エンコーディング)
– ステート変数の global 宣⾔(変更するには global が必要。後述)
– そもそも superuser しか使えない(untrusted なので)
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 5
PL/Python - Python⼿続き⾔語
https://www.postgresql.jp/document/9.4/html/plpython.html
PL/Pythonの関数の作り⽅
• 外部のPythonモジュールを使うUDFの例
– ⽇本語⾃動要約ライブラリ
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 6
⾃動要約API「summpy」を使ってPostgreSQLに⽂章の要約機能を追加する
http://pgsqldeepdive.blogspot.jp/2015/11/pgsummpy.html
CREATE FUNCTION lexrank_summarize(p text, t text, s_limit integer)
RETURNS SETOF text
AS $$
import sys
sys.path.append(p)
from summpy import lexrank
res = lexrank.summarize(unicode(t, 'utf‐8'), sent_limit=s_limit)
for s in res:
yield(s.encode('utf‐8'))
$$ LANGUAGE plpythonu;
min(),max(),avg()を実装してみる
• 組み込みのmin(), max(), avg() の機能を再現
– 集約関数名は pymin(), pymax(), pyavg()
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 7
‐‐ min()
‐‐ sがstate変数、nが入力値、最後の計算は不要なのでffuncは無し
CREATE FUNCTION float8_pymin(s float8, n float8)
RETURNS float8
AS $$
global s
if n is not None:
if s is None or n < s:
s = n
return s
$$ LANGUAGE plpython2u;
CREATE AGGREGATE pymin (float8)
(
sfunc = float8_pymin,
stype = float8
);
min(),max(),avg()を実装してみる
• avg() のPL/Python実装
– ffunc を追加して、最後に平均値を計算して出⼒
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 8
‐‐
‐‐ avg()
‐‐
CREATE FUNCTION float8_pyavg(
s float8[], n float8)
RETURNS float8[]
AS $$
global s
if n is not None:
if s is None:
# sum,count
s = [0,0]
s[0] = s[0] + n
s[1] = s[1] + 1
return s
$$ LANGUAGE plpython2u;
CREATE FUNCTION float8_pyavg_final(
s float8[])
RETURNS float8
AS $$
global s
if s is not None:
return s[0]/s[1]
return None
$$ LANGUAGE plpython2u;
CREATE AGGREGATE pyavg (float8)
(
sfunc = float8_pyavg,
stype = float8[],
finalfunc = float8_pyavg_final
);
pyagg.sql https://gist.github.com/snaga/7c3940e72fad172cca6f
単回帰分析を⾏う集約関数を実装してみる
• 単回帰分析のモデルは y = w0 + w1 * x
• データを⼆種類⽤意する(訓練⽤、評価⽤)
• 訓練⽤データのテーブルから y と x を拾う
– w0 と w1 を集約関数で計算して出⼒する
• 別のテーブルの評価⽤データの x から y を予測する
• 結果および誤差を確認する
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 9
Machine Learning: Regression - University of Washington | Coursera
https://www.coursera.org/learn/ml-regression/
単回帰分析を⾏う集約関数を実装してみる
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 10
snaga=# ¥d
List of relations
Schema |        Name         | Type  | Owner
‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐
public | kc_house_data | table | snaga
public | kc_house_test_data | table | snaga
public | kc_house_train_data | table | snaga
(3 rows)
snaga=# select simple_linear_regression(price,sqft_living) from 
kc_house_train_data;
simple_linear_regression
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
{‐47116.0791388,281.958839662}
(1 row)
• デモ
snaga/SimpleLinearRegression
https://github.com/snaga/SimpleLinearRegression
単回帰分析を⾏う集約関数を実装してみる
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 11
snaga=# select sqft_living,
price,
round(‐47116.0791388 + 281.958839662 * sqft_living) as 
price_predicted,
round((((‐47116.0791388 + 281.958839662 * sqft_living) ‐ price) / 
price)::numeric, 2) as error
from kc_house_test_data;
sqft_living | price  | price_predicted | error
‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐
1430 | 310000 |          356085 |  0.15
2950 | 650000 |          784662 |  0.21
1710 | 233000 |          435034 |  0.87
(...)
2310 | 400000 |          604209 |  0.51
1020 | 402101 |          240482 | ‐0.40
(4229 rows)
• デモ
snaga/SimpleLinearRegression
https://github.com/snaga/SimpleLinearRegression
Q&A
Copyright 2015 Uptime Technologies, LLC. All rights reserved. 12
コメント、質問など
Twitter: @snaga
E-Mail: snaga@uptime.jp

PL/Pythonで独自の集約関数を作ってみる

  • 1.
    Copyright 2015 UptimeTechnologies, LLC. All rights reserved. 1 PL/Pythonで独⾃の集約関数を 作ってみる アップタイム・テクノロジーズ 永安 悟史 第6回 PostgreSQLアンカンファレンス
  • 2.
    ⽬次 • なぜPL/Pythonで集約関数なのか? • PostgreSQLにおける集約関数の作り⽅ •PL/Pythonの関数の作り⽅ • min(),max(),avg()を実装してみる • 単回帰分析を⾏う集約関数を実装してみる Copyright 2015 Uptime Technologies, LLC. All rights reserved. 2
  • 3.
    なぜPL/Pythonで集約関数なのか? • Pythonとデータ処理 • データ処理と集約関数 •プロシージャ・UDFによるIn-Database処理 Copyright 2015 Uptime Technologies, LLC. All rights reserved. 3
  • 4.
    PostgreSQLにおける集約関数の作り⽅ • CREATE AGGREGATEコマンドによる定義 –実⾏中の内部状態を処理するUDF:sfunc – 内部状態を保持するデータ型:state_data_type – 最終的な結果を出⼒するUDF:ffunc Copyright 2015 Uptime Technologies, LLC. All rights reserved. 4 CREATE AGGREGATE myagg (arg1, arg2, ...) ( SFUNC = sfunc, STYPE = state_data_type, FINALFUNC = ffunc ); ユーザ定義の集約 https://www.postgresql.jp/document/9.4/html/xaggr.html CREATE AGGREGATE https://www.postgresql.jp/document/9.4/html/sql-createaggregate.html sfunc args state sfunc args state ffunc return
  • 5.
    PL/Pythonの関数の作り⽅ • CREATE FUNCTION –単に中⾝がPythonスクリプトになるだけ • データベースにアクセスする場合には plpy モジュール – CのUDFで⾔うところのSPI関数のようなもの – import plpy • 注意すべきところ – plpython.soからリンクされているPythonのバージョン – データの相互マッピング(+エンコーディング) – ステート変数の global 宣⾔(変更するには global が必要。後述) – そもそも superuser しか使えない(untrusted なので) Copyright 2015 Uptime Technologies, LLC. All rights reserved. 5 PL/Python - Python⼿続き⾔語 https://www.postgresql.jp/document/9.4/html/plpython.html
  • 6.
    PL/Pythonの関数の作り⽅ • 外部のPythonモジュールを使うUDFの例 – ⽇本語⾃動要約ライブラリ Copyright2015 Uptime Technologies, LLC. All rights reserved. 6 ⾃動要約API「summpy」を使ってPostgreSQLに⽂章の要約機能を追加する http://pgsqldeepdive.blogspot.jp/2015/11/pgsummpy.html CREATE FUNCTION lexrank_summarize(p text, t text, s_limit integer) RETURNS SETOF text AS $$ import sys sys.path.append(p) from summpy import lexrank res = lexrank.summarize(unicode(t, 'utf‐8'), sent_limit=s_limit) for s in res: yield(s.encode('utf‐8')) $$ LANGUAGE plpythonu;
  • 7.
    min(),max(),avg()を実装してみる • 組み込みのmin(), max(),avg() の機能を再現 – 集約関数名は pymin(), pymax(), pyavg() Copyright 2015 Uptime Technologies, LLC. All rights reserved. 7 ‐‐ min() ‐‐ sがstate変数、nが入力値、最後の計算は不要なのでffuncは無し CREATE FUNCTION float8_pymin(s float8, n float8) RETURNS float8 AS $$ global s if n is not None: if s is None or n < s: s = n return s $$ LANGUAGE plpython2u; CREATE AGGREGATE pymin (float8) ( sfunc = float8_pymin, stype = float8 );
  • 8.
    min(),max(),avg()を実装してみる • avg() のPL/Python実装 –ffunc を追加して、最後に平均値を計算して出⼒ Copyright 2015 Uptime Technologies, LLC. All rights reserved. 8 ‐‐ ‐‐ avg() ‐‐ CREATE FUNCTION float8_pyavg( s float8[], n float8) RETURNS float8[] AS $$ global s if n is not None: if s is None: # sum,count s = [0,0] s[0] = s[0] + n s[1] = s[1] + 1 return s $$ LANGUAGE plpython2u; CREATE FUNCTION float8_pyavg_final( s float8[]) RETURNS float8 AS $$ global s if s is not None: return s[0]/s[1] return None $$ LANGUAGE plpython2u; CREATE AGGREGATE pyavg (float8) ( sfunc = float8_pyavg, stype = float8[], finalfunc = float8_pyavg_final ); pyagg.sql https://gist.github.com/snaga/7c3940e72fad172cca6f
  • 9.
    単回帰分析を⾏う集約関数を実装してみる • 単回帰分析のモデルは y= w0 + w1 * x • データを⼆種類⽤意する(訓練⽤、評価⽤) • 訓練⽤データのテーブルから y と x を拾う – w0 と w1 を集約関数で計算して出⼒する • 別のテーブルの評価⽤データの x から y を予測する • 結果および誤差を確認する Copyright 2015 Uptime Technologies, LLC. All rights reserved. 9 Machine Learning: Regression - University of Washington | Coursera https://www.coursera.org/learn/ml-regression/
  • 10.
    単回帰分析を⾏う集約関数を実装してみる Copyright 2015 UptimeTechnologies, LLC. All rights reserved. 10 snaga=# ¥d List of relations Schema |        Name         | Type  | Owner ‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐ public | kc_house_data | table | snaga public | kc_house_test_data | table | snaga public | kc_house_train_data | table | snaga (3 rows) snaga=# select simple_linear_regression(price,sqft_living) from  kc_house_train_data; simple_linear_regression ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ {‐47116.0791388,281.958839662} (1 row) • デモ snaga/SimpleLinearRegression https://github.com/snaga/SimpleLinearRegression
  • 11.
    単回帰分析を⾏う集約関数を実装してみる Copyright 2015 UptimeTechnologies, LLC. All rights reserved. 11 snaga=# select sqft_living, price, round(‐47116.0791388 + 281.958839662 * sqft_living) as  price_predicted, round((((‐47116.0791388 + 281.958839662 * sqft_living) ‐ price) /  price)::numeric, 2) as error from kc_house_test_data; sqft_living | price  | price_predicted | error ‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐ 1430 | 310000 |          356085 |  0.15 2950 | 650000 |          784662 |  0.21 1710 | 233000 |          435034 |  0.87 (...) 2310 | 400000 |          604209 |  0.51 1020 | 402101 |          240482 | ‐0.40 (4229 rows) • デモ snaga/SimpleLinearRegression https://github.com/snaga/SimpleLinearRegression
  • 12.
    Q&A Copyright 2015 UptimeTechnologies, LLC. All rights reserved. 12 コメント、質問など Twitter: @snaga E-Mail: snaga@uptime.jp