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
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
Pythonでgoogle-cloud-bigqueryを使用してLegacy SQLを実行する
google-cloud-bigquery
はデフォルトでStandard SQLを使用することになっているため、Legacy SQLを使用する場合は明示的に指定する必要がある。
さっとソースを読んでみたところ、QueryJobConfigというのを使うといいらしい。
サンプル
from google.cloud import bigquery if __name__ == '__main__': client = bigquery.Client.from_service_account_json('./credentials.json') query = 'SELECT * FROM [project:dataset.table]' config = bigquery.QueryJobConfig() config.use_legacy_sql = True rows = client.query(query, job_config=config).result() for row in rows: print(row)
歴史があるサービスだとLegacy SQLを使うこともあるので覚えておく。
- 作者: Jordan Tigani,Siddartha Naidu,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/03/23
- メディア: 大型本
- この商品を含むブログを見る
React Nativeで買い物リストアプリを作ってiOS/Androidで動作させた
やりたかったこと
React Nativeに入門するも、Hello Worldより先になかなか進まなかったので、小さな物でもいいのである程度使えるアプリを作ってみることにした。
お題としてTODOリストのような一般的な物を作ることにしたため、どう実装するかはさておいて、機能については悩みどころがなかったのはよかったと思う。
何を作ろう?どんな機能が必要だろう?から考えてしまうとなかなか進まないので、おきまりの物を作ろうと割り切った。
スクリーンショット
iOS
iOSに合わせてレイアウトした。
Android
上に若干余白があるが、本来はプラットフォーム別に調整できるところをサボっているだけ。
リポジトリ
この記事を書いた時点ではREADMEすら書いてないけど、React Nativeの環境ができていれば、 git clone
して cd
して npm i
の後に react-native run-ios
とかやれば動くはず。
主に使ったコンポーネント/API
- AsyncStorage
- アイテムを保存するために使用
- FlatList
- いわゆるリストビュー
- Text
- TextInput
- TouchableOpacity
- Buttonは使わなかった
- View
悩んだところ
コンポーネントの分割粒度
今回は作りきることが目的だったのでざっくり分けたが、ネイティブもReactも経験が少ないので筋のいい分け方が知りたい。
FlatListの扱いに悩んだ
アイテムが追加されても、FlatListをスクロールするまで新しいアイテムが再描画されなかった。
extraDataというpropを設定し、その値も合わせて更新することで再描画してくれるようになったが、extraDataに配列を渡しても変更を検出してくれないようなので、数値などの値にする必要があるようだ。今回は表示対象のアイテムを保持する配列の長さをextraDataとして使用した。
thisの扱い
必要に応じてbindを使って解決したが、bindを使わずにスマートにかけるのであればその方法を知りたい。
まとめ
- ある程度JavaScriptが書ければ簡単なアプリは作れる
- 小さい規模であれば、差異をほぼ気にせずにクロスプラットフォーム対応できた
- 検索して得られる情報も増えていきたので、エラーや予期しない挙動があってもなんとか解決できる状況になってきた
- 環境構築やシミュレーターでの動作確認に躓くと厳しそう。その場合はネイティブの知識が必要になりそうな気がする
個人的にはもうちょっとJavaScriptとその周辺エコシステムを学んだら、もうちょっと気分良くかけるかも。
初めてのJavaScript 第3版 ―ES2015以降の最新ウェブ開発
- 作者: Ethan Brown,武舎広幸,武舎るみ
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/01/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
Pythonのリストを決まったサイズで分割するときはmore-itertoolsのchunkedを使う
いつも忘れては同じこと調べてるのでメモ。
More Itertools — more-itertools 3.2.0 documentation
pipでインストールして
$ pip install more-itertools
こんな感じで使うと
from more_itertools import chunked if __name__ == '__main__': items = range(28) print(list(chunked(items, 10)))
こんな結果になる。
$ python main.py [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [20, 21, 22, 23, 24, 25, 26, 27]]
これで忘れても大丈夫。
- 作者: Bill Lubanovic,斎藤康毅,長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/12/01
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
標準入力から受け取った文字列をSlackに通知するhouを作った
ぼんやりとみんGoを眺めていたら、horensoみたいに賢くなくていいから、標準入力をそのままSlackに投げるCLIツールが自分用にあったらいいような気がしてきた。
そこで作ったのがこれ。horenso(報・連・相)でいうところの「報」しかやらないのでhouという名前。
以下の記事のことも頭の片隅にあったかもしれないけど、nofify_slackのほうが対ISUCONを意識されてるっぽいし実戦的だと思う。くらべてhouはもっと雑。
使い方
READMEの通り。オプションで色々渡せるようにしてはあるけど、無くてもいいねって感じのオプションばかり。ついついオプションを増やしたくなってしまう悪い癖がどうも抜けない。
$ export SLACK_API_TOKEN=YOUR_SLACK_API_TOKEN $ w | hou -channel hello
環境変数にSlackのトークンを入れて、何らかの標準入力を受け取って -channel
で指定されたSlackのチャンネルにメッセージを投げる。
メッセージの受信イメージはこんな感じ。
せっかく作ったので、ちょっとしたバッチを crontab
に設定したときの動作確認とか、VMなどでちょっと重めのバッチを回しているときの完了通知とかに使おうかなと思っているところ。
余談
「ゆとりの法則 - 誰も書かなかったプロジェクト管理の誤解」読んでない気がするし、マーケットプレイスで送料込み500円ちょっとだったのでとりあえず買ってみた。
原題は「Slack: Getting Past Burnout, Busywork, and the Myth of Total Efficiency」らしい。
- 作者: トム・デマルコ,伊豆原弓
- 出版社/メーカー: 日経BP社
- 発売日: 2001/11/26
- メディア: 単行本
- 購入: 14人 クリック: 119回
- この商品を含むブログ (111件) を見る