pl/pythonで独自の集約関数を作ってみる

12

Click here to load reader

Upload: uptime-technologies-llc-jp

Post on 15-Apr-2017

2.480 views

Category:

Software


0 download

TRANSCRIPT

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

Copyright 2015 Uptime Technologies, LLC. All rights reserved. 1

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

アップタイム・テクノロジーズ永安 悟史

第6回 PostgreSQLアンカンファレンス

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

⽬次

• なぜPL/Pythonで集約関数なのか?• PostgreSQLにおける集約関数の作り⽅• PL/Pythonの関数の作り⽅• min(),max(),avg()を実装してみる• 単回帰分析を⾏う集約関数を実装してみる

Copyright 2015 Uptime Technologies, LLC. All rights reserved. 2

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

なぜPL/Pythonで集約関数なのか?

• Pythonとデータ処理

• データ処理と集約関数

• プロシージャ・UDFによるIn-Database処理

Copyright 2015 Uptime Technologies, LLC. All rights reserved. 3

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

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.htmlCREATE AGGREGATEhttps://www.postgresql.jp/document/9.4/html/sql-createaggregate.html

sfuncargs

state

sfuncargs

state

ffuncreturn

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

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

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

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 syssys.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;

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

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 = nreturn s

$$ LANGUAGE plpython2u;

CREATE AGGREGATE pymin (float8)(

sfunc = float8_pymin,stype = float8

);

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

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,counts = [0,0]

s[0] = s[0] + ns[1] = s[1] + 1

return s$$ LANGUAGE plpython2u;

CREATE FUNCTION float8_pyavg_final(s float8[])

RETURNS float8AS $$

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

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

単回帰分析を⾏う集約関数を実装してみる

• 単回帰分析のモデルは 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 | Courserahttps://www.coursera.org/learn/ml-regression/

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

単回帰分析を⾏う集約関数を実装してみる

Copyright 2015 Uptime Technologies, LLC. All rights reserved. 10

snaga=# ¥dList of relations

Schema |        Name         | Type  | Owner‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐public | kc_house_data | table | snagapublic | kc_house_test_data | table | snagapublic | 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/SimpleLinearRegressionhttps://github.com/snaga/SimpleLinearRegression

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

単回帰分析を⾏う集約関数を実装してみる

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 errorfrom kc_house_test_data;sqft_living | price  | price_predicted | error‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐

1430 | 310000 |          356085 |  0.152950 | 650000 |          784662 |  0.211710 | 233000 |          435034 |  0.87

(...)2310 | 400000 |          604209 |  0.511020 | 402101 |          240482 | ‐0.40

(4229 rows)

• デモ

snaga/SimpleLinearRegressionhttps://github.com/snaga/SimpleLinearRegression

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

Q&A

Copyright 2015 Uptime Technologies, LLC. All rights reserved. 12

コメント、質問など

Twitter: @snagaE-Mail: [email protected]