business-rulesを使ってルールエンジンを使った処理を書く
ルールエンジンをPythonで使えると仕事上便利なことがありそうなので調査してみたところ、 business-rules
が目的にあっているように思えたので、READMEを読みつつ試してみた。
使ったモジュール
Venmoが開発した business-rules
を使うことにした。VenmoのことはRebuildで聞いたことがあるぐらいで使ったことはない。
- Pythonで書かれたルールエンジンを探していた
- Venmoの中でも使われているのかも。と考えて使ってみたくなった
- READMEのサンプルコードが分かりやすかった
というのが選定理由。
コミットログを見るとしばらく活動がなさそうだけど、こういうのは一度書いて(安定して)動いてたら、よほどのことがなければ書き換えるものでもないかなと思って気にしないことにした。
サンプルコード
一度ルールエンジンを使って処理を書いたことがあれば、business-rules
がなにをするためにものなのかは容易に理解できると思う。
経験がなくても、動かしながらいろいろ試してみればどういったものなのかの感覚はつかめるはず。
仕事柄広告のデータを扱うことが多いので、広告っぽいデータを処理するルールを書いたのがこちら。
from business_rules import run_all from business_rules.actions import BaseActions, rule_action from business_rules.fields import FIELD_TEXT from business_rules.variables import BaseVariables, numeric_rule_variable class Ad(): def __init__(self, name, status, **kwargs): self.name = name self.status = status self.spend = kwargs.get('spend', 0) self.impressions = kwargs.get('impressions', 0) self.clicks = kwargs.get('clicks', 0) def save(self): print(self.name, self.status) class AdVariables(BaseVariables): def __init__(self, ad): self.ad = ad @numeric_rule_variable def spend(self): return self.ad.spend @numeric_rule_variable def cpc(self): return self.ad.spend / self.ad.clicks @numeric_rule_variable def ctr(self): return self.ad.clicks / self.ad.impressions class AdActions(BaseActions): def __init__(self, ad): self.ad = ad @rule_action(params={"status": FIELD_TEXT}) def change_status(self, status): self.ad.status = status self.ad.save() def main(): rules = [{ 'conditions': { 'all': [ {'name': 'spend', 'operator': 'greater_than_or_equal_to', 'value': 200000}, {'name': 'cpc', 'operator': 'greater_than_or_equal_to', 'value': 100}, {'name': 'ctr', 'operator': 'less_than', 'value': 0.03}, ] }, 'actions': [ {'name': 'change_status', 'params': {'status': 'PAUSED'}}, ], }] ads = [ Ad(name='Ad1', status='ACTIVE', spend=100000, impressions=10000, clicks=1000), Ad(name='Ad2', status='ACTIVE', spend=200000, impressions=10000, clicks=500), Ad(name='Ad3', status='ACTIVE', spend=400000, impressions=20000, clicks=500), ] for ad in ads: run_all(rule_list=rules, defined_variables=AdVariables(ad), defined_actions=AdActions(ad), stop_on_first_trigger=True) if __name__ == '__main__': main()
サンプルコードの説明
Ad
は広告そのものを表現するAdVariables
はAd
をbusiness-rules
が評価できる形式にするためのもの- ここではspend(消化金額)と合わせて、CPC(クリック単価)やCTR(クリック率)を評価対象にしている(簡略化のためにゼロ割は考慮していない)
- CPCやCTRのように、もとのオブジェクトに無いものでも、計算によって求められた値を評価できる
- どんな値でも
BaseVariables
を継承したクラスでラップするような形になるので、対象のデータの形式によらずルールを適用できる
AdActions
は評価した結果、ルールに一致したものをどのように処理するかを表現する- 今回はルールに一致した広告のステータスを変更するようなサンプルにしているので、ステータスを変更するような処理として
change_status
を定義した
- 今回はルールに一致した広告のステータスを変更するようなサンプルにしているので、ステータスを変更するような処理として
main
でルールを定義し、与えられたデータをルールに従って評価する- ルールには
conditions
とactions
が定義できる conditions
では、less_than
やgreater_than_or_equal_to
などの演算子を用いて、先に定義したAdVariables
の値を評価することができるactions
では、ルールに一致したものをどのように処理するかを定義する。今回はルールに一致した広告を停止するようなサンプルにしているので、AdActions
に定義したchange_status
のstatus
に、広告の停止状態を表すPAUSED
を渡したものを実行する
- ルールには
実行
サンプルコードでは、以下の conditions
すべてに一致したものを actions
に従って処理する。
- 消化金額が¥200,000以上
- CPC(消化金額 / クリック数)が¥100以上
- CTR(クリック数 / 表示回数)が3%未満
これらを満たすのは Ad3
(消化金額¥400,000、CTR¥800、CTR2.5%)なので、実行結果は以下となる。
$ python main.py Ad3 PAUSED
まとめ
Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎
- 作者: Andreas C. Muller,Sarah Guido,中田秀基
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/05/25
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る