Data Meshについての調査

この記事は?

Data Meshと呼ばれるデータアーキテクチャについて調査した記事です。

この記事のまとめです。 だいぶ意訳して、私の解釈が混じっているのでご注意ください。

現在の企業のデータアーキテクチャ

中央化された、モノシリックなアーキテクチャが一般的である。 著者がかかわってきたクライアントによると、データアーキテクチャには失敗してきた過去があるという。

  • 第一世代:独自仕様のエンタープライズDHWとBIツール
    高額で技術負債も多く、ビジネスに良い影響が与えられなかった。
    例:メンテナンスできないETL、少数しか理解できないレポート

  • 第二世代:銀の弾丸としてのビックデータエコシステムとデータレイク
    複雑なエコシステムを中央のスペシャリストが管理した。その結果、"データレイクモンスター"が発生した上に、PoC程度しか実現できなかった。

第三世代である今世代は、第二世代に似ているが、いくつか変更点がある。

  • Kappaのようにリアルタイムデータへの対応
  • Apache Beamのような統一化されたバッチ・ストリーミング処理フレームワーク
  • クラウドベースドマネージサービス(ストレージ、パイプライン処理、ML)

これらは前世代のリアルタイムデータ分析のギャップを埋め、インフラコストを抑えた。しかし、前世代の失敗につながった根本的な特徴を引き継いでいる。

データアーキテクチャ失敗パターン

SpotifySoundCloudApple iTunesのような仮想のインターネットメディアストリーミングビジネスのドメインを例として、失敗パターンを述べる。

一元化されモノシリック

f:id:wata101wata:20210115001024p:plain このアーキテクチャは次のようなことが目的である。

  • 企業のあらゆるデータを取り込む。運用データやトランザクション、または外部データまでに及ぶ。例えば、メディアストリーミングビジネス(spotify)では、ユーザがどの音楽を聴いたのか、どのアーティストをフォローしているのか、曲名とアーティスト、曲の購入履歴、外部のカスタマーデモグラフィックによる調査データなどである。

  • データを活用する人のために、データをクレンジングし, 充実させる。例えば、transformationの一つは、ユーザのクリックストリームをある特定のユーザーの詳細で充実した意味のあるセッションにすることである。これはそのユーザーのジャーニーを再構成することができる。

  • さまざまなニーズを持つさまざまな消費者にデータセットを提供する。 これは、分析的な消費から、洞察を探すデータの探索、機械学習ベースの意思決定、ビジネスのパフォーマンスを要約するビジネスインテリジェンスレポートにまで及ぶ。ディアストリーミングの例では、プラットフォームは、Kafkaなどの分散ログインターフェイスを介して世界中のメディアプレーヤーに関するほぼリアルタイムのエラーおよび品質情報を提供したりできる。

つまり、このデータプラットフォームはドメインの集合と見なることができる。 f:id:wata101wata:20210115003055p:plain

次のように、このアーキテクチャは2つのプレッシャーポイントがある。

  • データの急増:データの増加により単一のプラットフォームでコントロールできなくなる。例えば、「顧客情報」のドメインを考えると、顧客は増加しつつけるのでデータは膨らむ。それにより、分析者は膨大な(顧客情報以外のドメインすべてを含めた)データを取りまわさなければいけなくなる。

  • データのユースケースの急増:これにより、ETLパイプライン、そのテストが肥大化することを意味する。これは、データのに対する新しい要求を実装するレスポンスを悪化させる。

上記からわかることは、一元化されたチームが一元化されたプラットフォームですべてのドメインのデータをコントロールするのは難しいということである。

パイプラインの分割

2番目の問題はパイプラインの分割が難しいことである。一般的にデータの処理ステージに沿って分割されることが多い。例えば、収集、前処理、集約、サービングなどである。 f:id:wata101wata:20210115225946p:plain しかし、このアーキテクチャは前段階の対応が終わらなければ行動できないので、ある程度しかスケールしない。なぜならば、ドメインに対して直行しているからである。 f:id:wata101wata:20210115231032p:plain メディアストリーミングの例でいうと、”ポッドキャストの再生率”という特徴量を追加しようとすると、パイプラインのすべてを変更する必要がある。なぜならば、各ステージのチームから見ると新しいデータを取り込むならば影響範囲の特定などにより、そのステージ全体を確認する必要があるからである。このとき、構造的な最小単位(architectural quantum)は各ステージ全体である。これが、データに対して柔軟に反応することを阻害する。

分断されたオーナーシップ

3つ目の問題は、データのオーナーシップが分断されていることである。例えば、データエンジニアのグループは様々な場所で分断されている。例えば、データの発生する場所とデータが分析に活用される場所で。さらに、データツールなどの専門知識などによっても細分化されることもある。これらのエンジニアは、多くの場合ビジネスやドメインの知識はない。 f:id:wata101wata:20210115233647p:plain メディアストリーミングの例でいうと、サービスを運営しているチームがあり、そこから伸びているデータパイプラインの端にKPIを使って意思決定するチームがある。その真ん中でデータプラットフォームチームがサービスチームと隔離され、KPIチームからは要求をぶつけられて苦しんでいる。

次世代のエンタープライズデータプラットフォームアーキテクチャ

パラダイムシフトが必要である。分散ドメインアーキテクチャ、セルフサービスプラットフォーム設計、データ分析を前提としたプロダクトシンキング。これらを掘り下げていく。 f:id:wata101wata:20210116003121p:plain

データと分散ドメイン駆動アーキテクチャの出会い

ドメインに基づくデータ分解とオーナーシップ

エリック・エバンスの「ドメイン駆動設計」 はビジネスドメイン機能を中心としたマイクロサービスアーキテクチャを世に知らしめた。 データアーキテクチャドメインに基づいて考えてみよう。そうすると、逆の発想が生まれる。ドメインからデータレイクへデータを流すのではなく、ドメインがデータをホストして、提供するのである。 (ドメインがpushするのではなく、ドメインからpullする。)
メディアストリーミングの例を考えてみよう。ドメインが一元化されたデータレイクとそのチームにデータをながすのではなく、ホストとしてどのチームがどんな目的でも使用できるように提供する。つまり、オーナーシップはデータを生み出すドメイン自身が持つ。ドメイン同士のデータ連携も考えられる。”レコメンデーション”ドメインがあるデータベースを作成し、ほかのあるドメインがそのデータを使ってサービスを作り、新たにデータをホストすることもあるだろう。
これは伝統的なpush and ingestなETLから、ドメイン間のserving and pullへの発想の転換である。このとき、構造的な最小単位(architectural quantum)ドメインに基づくデータプラットフォームである。

ソース志向のドメインデータ

ソースドメインデータセットとは、ビジネスファクトを表す。ソースドメインデータセットは運用システムが生み出したものと密接にマッピングされたデータを捉える。例えば、”どのようにユーザがサービスとインタラクトするか”というビジネスの実態は、”ユーザクリックストリーム”というドメインデータセットを生み出す。これらの実態は、運用システムが最もよく理解している。例えば、メディアプレイヤーシステムは”ユーザークリックストリーム”について最もよく知っている。 理想的には、運用システムとそのチームはビジネスを提供するだけでなく、ソースドメインデータセットとして、ビジネスドメインの真実を提供する責任がある。企業レベルのスケールでは、システムとドメインは1対1で結びついているわけではなく、多対1で結びついており、レガシーなシステムもあれば、変更が容易なシステムもある。よって、このドメインに沿って、複数のシステムのデータが集計され、そのドメインのビジネスファクトを表す、ソースアラインドデータセット(またの名をリアリティデータセット) が存在するだろう。
ビジネスファクトはドメインイベントとして表現され、分析者がアクセスできる分散ログとしてストアされ提供される。
ソースドメインデータセットは最も基礎的で、変更されることは少ない。なぜならば、ビジネスファクトが変更されることは少ないからだ。これらのドメインデータセットは永遠にキャプチャされ、利用可能にされることが期待される。よって、いつでもビジネスファクトに戻って、新しい集計やプロジェクションを作成できる。 ソースドメインデータセットは生成された時点の生のデータを表し、分析向けに変換されたものではない。

分析者向けの共有されたドメインデータ

あるドメインで作成された分析データがほかのドメインで使われることもある。例えば、”ソーシャルレコメンドドメイン”は”ユーザのソーシャルネットワークのグラフ表現”というデータを作ったとする。このデータは”リスナーノーティフィケーション”ドメインで役に立つかもしれない。ソーシャルネットワークのユーザが何を聴いているか知らせる機能だ。つまり、”ユーザソーシャルネットワーク”は共有された具体的なドメインデータセットとして多数の分析者に使われる。”ユーザソーシャルネットワークドメインチームは、自身のビジネスでこのデータを使っているので、自然とデータがメンテナンスされる。
このような分析者に沿ったドメインデータセットはソースドメインデータセットとはことなる性質を持つ。ソースドメインデータセットを変換し、特定のアクセスモデルに適合するようにビューを集約する。ドメイン志向データプラットフォームはこれらの分析者用データセットをソースから簡単に再構成できる。

ドメインの内部実装としての分散パイプライン

ドメインそれぞれがETLパイプラインを持つ。これは、分散パイプラインとみさせる。 f:id:wata101wata:20210117114019p:plain これにより、従来ではETLパイプラインの集約ステージで一元化されていたロジックが、各ドメイン内のパイプラインにうまく分解できる。
しかし、「分散することにより、同じ処理を各ドメインのパイプラインでそれぞれ開発してしまい努力の無駄になるのでは」、という懸念もあるだろうが、DataAndSelf-servePlatformDesignConvergenceの章で解説する。

データとプロダクトシンキングの出会い

データのオーナーシップとパイプラインをビジネスドメインの手に分散させることにより新たな懸念が生まれる。アクセシビリティユーザビリティ、データ同士の調和などである。ここは、プロダクトシンキングが役に立つ。

製品としてのドメインデータ

運用ドメインは、機能をAPIとして提供することがある。そして、APIのドキュメントがまとめれ、テストされ、使用経過をKPIとして確認する。
分散データプラットフォームを成功させるには、ドメインデータを提供するときにも同じ思考を適用する必要がある。データ資産を製品とみなし、組織のほかのデータサイエンティスト、MLモデル、データエンジニアを消費者とみなす。
f:id:wata101wata:20210117181235p:plain メディアストリーミングの例を考える。重要なドメインとして、”再生イベント”がある。だれが、いつ、どこで、どの曲を再生したかである。このドメインには、組織内の様々な消費者がいる。例えば、カスタマーサポートのためにリアルタイムにアクセスする消費者もいれば、日次や月次で分析するためにアクセスする消費者もいる。この場合、それぞれの要望に応えるため”再生イベント”ドメインは2つの異なるデータセットを提供する。
サービス運用の目的が、市場の消費者を喜ばせることであるように、ドメインデータを社内に公開することの目的は、社内の消費者、データエンジニア、MLエンジニア、データサイエンティストを喜ばせることである。このとき、ドメインデータプロダクトは次のような品質を備えている必要がある。

発見可能

データプロダクトは簡単に見つけられなければならない。一般的な実装は、データカタログを作ることである。所有者、ソース、リネージュ、サンプルデータセットが記載されている。この一元化されたカタログにより、組織内のデータ消費者は簡単にデータセットを見つけられる。すべてのドメインデータプロダクトは、このデータカタログに登録しなければならない。データリネージュメタデータとして提供することも、消費者の信頼を得るのに役だつ。

アドレッサブル

データプロダクトは一意のアドレスを持つ必要がある。すべてのデータプロダクトに共通した命名規則を開発する必要がある。

信頼して使えるデータ

そのドメインデータがどれだけ信頼できるかをSLOで保証する。SLOを保証するため、データ作成時に、データクレンジングや自動データバリデーションを作成することは有効である。

自己記述型のセマンティクスと構文

サンプルデータセットと、データスキーマを提供しよう。

相互運用可能であり、グローバルスタンダードに準拠

分散ドメインデータアーキテクチャの主な懸念事項の1つは、ドメイン間でデータをどうやって結合させるかである。これには、全社で一つの標準に従う必要がある。この標準化は、フォーマッティング、同音異義語の区別、データのアドレス規則、共通メタデータCloudEventsのイベントフォーマットなどである。

安全にアクセスできる

ドメインデータプロダクトごとにアクセス制御される。SSOやロールベースアクセスコントロールポリシー定義はアクセス制御の実装として便利である。

ドメインデータのクロスファンクショナルチーム

ドメインは新しいスキルセットが必要である。データプロダクトオーナーとデータエンジニアである。データプロダクトオーナーは、データプロダクトのロードマップを決定し、消費者の満足度に関心を持ち、ドメインデータプロダクトのKPIを継続的に測定し改善する。ドメインデータセットのライフサイクル、データスキーマの変更、廃止を担当し、消費者のニーズに応じて優先度付けをする。
データプロダクトオーナーは、データプロダクトとビジネスそれぞれのKPIを定義する。例えば、消費者がデータを発見して使い始めることができるリードタイムは前者のKPIとして適当だろう。
分散パイプラインをドメインの内部に構築するため、チームはデータエンジニアを必要とする。素晴らしい副次効果として、エンジニア間のスキルの融合がある。例えば、データエンジニアはデータツールの使い方走っているが、CI/CDや自動テストには疎いことがある。逆にソフトウェアエンジニアはデータエンジニアツールを使ったことがないことがある。スキルセットのサイロを取り除くことにより、組織に深いエンジニアリングスキルセットが構築される。
f:id:wata101wata:20210117232817p:plain

データとセルフサービスプラットフォームデザインの出会い

データのオーナーシップをドメインに分散することの主な懸念点の1つに、各ドメインで作業が重複することである。解決策はドメイン横断で使えるインフラを作ることである。 f:id:wata101wata:20210117233444p:plainこのようなデータインフラストラクチャを構築するポイントは、次の点である。

データインフラストラクチャコンポーネントは次のようなものである。

  • スケーラブルなポリグロットビッグデータストレージ
  • 保存中および移動中のデータの暗号化
  • データプロダクトのバージョン管理
  • データプロダクトスキーマ
  • Data product de-identification
  • 統合されたデータアクセス制御とロギング
  • データパイプラインの実装とオーケストレーション
  • データプロダクトの発見、カタログの登録および公開
  • データガバナンスと標準化
  • データプロダクトリネージュ
  • データプロダクトの監視/アラート/ログ
  • データプロダクトの品質メトリクス(収集と共有)
  • インメモリデータキャッシング
  • フェデレーションID管理
  • 計算とデータの局所性

データインフラストラクチャの目的は、新しいデータプロダクトを作成するためのリードタイムを短縮することである。このために、製品としてのドメインデータの章で説明されている、データプロダクトを実装するために必要な自動化を実現する。

データメッシュに向けたパラダイムシフト

データメッシュの全体像を以下に示す。 f:id:wata101wata:20210117234433p:plain エンタープライズ規模の採用にはまだ長い道のりがあるだろうが、その原因はテクノロジーではないと思う。現在のツールで複数のチームによるオーナーシップと分散は可能である。特に、バッチの統一やストリーミングへのシフトとツール、Apache BeamGoogle Cloud Dataflow、は簡単にaddressable polyglot datasetsを簡単に処理できる。
Google Cloud DataCatalogなどのデータカタログプラットフォームは、分散ドメインデータセットの一覧化、アクセスコントロール、ガバナンスを提供する。

パラダイムシフトの要点は次である。

  • かき集めるのでなく、提供する(serving over ingesting)
  • 抽出して読み込むのではなく、発見して使う(discovering and using over extracting and loading)
  • 一元化されたパイプラインにデータを流すのではなく、ストリームとしてイベントを発行する
  • 一元化されたデータプラットフォームではなく、データプロダクトのエコシステム

追記

データメッシュの企業採用の一例としてAirbnbの記事があります。

競馬予測システムでMLOps実践~回収率140%でぬか喜びした話~

要点

  • 競馬予測で儲けることを目的に、データ収集・モデル開発からMLOpsまで全部やってみたという記事です。
  • 過去5年間の競馬データをもとに学習し、回収率140%超えを達成しました!!!!!!!!

    • 釣りです。間違ってはいないが、最適ではない評価方法でこうなりました。時系列データのテストデータの評価って気を付けないといけないねっていう話題です。
  • 実運用を目指した機械学習システムを作っていく中で、要点が見えてきたのでまとめました。
  • 機械学習で解きたい問題を明確にする
  • 継続的データ収集
  • データバリデーション
  • モデル性能監視・可視化
  • パイプライン化して自動化

回収率140%..?(時系列データの評価方法って難しいねという話)

時系列データって時系列に沿ってトレインデータをテストデータを分ければいいと思っていたんですよね。ので、2015/01/01~2020/08/31のレース結果をトレインデータとしてモデルを作りました(内容は後述)。このモデルの評価のために、2020/09/01~2020/09/31をテストデータをして回収率を計算しました*1。結果は次のようになりました。

買った馬券数 投資額  勝ち数 配当金総額 利益 回収率
101 10100 4 14290 4190 140%

回収率140%です。ヤッター。しかし、良すぎる結果が出たら疑うことにしているので、この検証が正しいか調べてみました。すると、この検証はもの足りないことがわかりました。 こちらを参考にすると、時系列データの検証は3つあり、

  1. Train-Test Splits
  2. Multiple Train-Test Splits
  3. Walk-Forward Validation

私が行ったのは1のようです。より信頼性の高い方法として2,3があります。複数のテストデータを疑似的に作ることにより、より信頼性の高いモデルの評価をできるようになるようです。2を実際にやってみました。

トレインデータ期間 テストデータ期間 買った馬券数 投資額  勝ち数 配当金総額 利益 回収率
~2019/12/31 ~2020/01/31 8 800 1 430 -370 53%
~2019/01/31 ~2020/02/31 38 3800 0 0 -3800 0
~2019/02/31 ~2020/03/31 51 5100 1 930 -4070 18%
~2019/03/31 ~2020/04/31 65 6500 3 1830 -5670 28%
~2019/04/31 ~2020/05/31 48 4800 0 0 -4800 0%
~2019/05/31 ~2020/06/31 74 7400 3 1510 -5990 20%
~2019/06/31 ~2020/07/31 55 5500 1 410 -5090 20%
~2019/07/31 ~2020/08/31 79 7900 5 2170 -5730 20%
~2019/08/31 ~2020/09/31 101 10100 4 14290 4190 140%

もしnか月前にこのモデルを運用していたら、どうっだったか。という検証をnをずらしながらしているわけですね。一見してわかるように140%はたまたま引いたラッキーだっただけで、全然ですね。

競馬予測システムの作り方

モデルの高度化は今後の課題として、まずは運用までやってしまおうと思います。以下に概要を載せます。

f:id:wata101wata:20210101224209p:plain

netkeiba.comからレース結果をクローリングしてきます。
➁学習マートを作り、モデルを作成します。
➂モデルに予測対象レースのデータを投入し、どの馬券を買うか推論します。
④自分のメールアドレスに買い目データを送信します。
➄レース結果確定後、予測と実績を対照して、モデルの性能をモニタリングしていきます。
こんな感じです。このシステムを作っていく中で感じたことを書いていきます。

機械学習で解きたい問題を明確にする

今回の目的は馬券を買って利益を最大化することですが、これのどこに機械学習が役立つのでしょうか。また、そのためにどのようなデータが必要なのでしょうか。回帰をするのでしょうか分類をするのでしょうか。それを明らかにするために問題を明確にしてみます。 競馬は様々な馬券の買い方がありますが、今回は単勝だけ考えます。アイデアとしては、馬ごとの勝つ確率が分かれば、オッズと比較して買い目の馬券だけを買っていくことにより、利益の最大化を狙います。例えば、オッズが10倍なら、勝利確率が0.1以上なら買い目です。インスタンスの特徴量をx (馬や競馬場の情報)、単勝したかどうかのフラグをyとします。二値分類としてとらえると、勝利確率p機械学習で予測できそうです。オッズをx_oとすると、p * x_o >1 となるような馬券を買っていけば利益が最大化できる気がします。
ここまでいったん整理しておくと、

  • 二値分類を行う
  • 1レースで複数買う場合もあるし、1枚も買わない場合もある
  • 二値分類の精度が最終目的ではないので、評価は利益自体で行うほうが良い

などがわかります。この問題のほかの捉え方ではランク学習をして1位の馬券を買うアルゴリズム強化学習の問題に落とし込むことなども考えられるので、このようにまとめておくと認識を合わせることができ有用です。*2

継続的にデータを収集する

netkeiba.comよりクローリングしたHTMLを持ってきて、スクレイピングしてデータベースに突っ込んでいます。この場合、初回にデータ集めるときと、2回目以降データ集めるときでプログラムが変わってくるので注意が必要です。
例えば、レースのページならば更新されることはないので、初回のみクローリングすれば良いです。しかし、競走馬のページは、過去の出走データがあるので更新されます。全部の競走馬ページもう一回クローリングすることは無駄が多いので、更新すべき競走馬のみを抽出してクローリングするなどの工夫が必要です。
また、次のセクションにもかかわることですが、データを収集するたびにデータバリデーションを走らせました。

データバリデーションをする

このシステムを作っていて一番時間がかかったところが、「あれ、データおかしくない?」というところです。例えば、全部の馬のデータを取ったつもりが、昔の分がうまく取れていなかったり、1:1で結びつくデータのはずなのにかなり落ちてしまったりしていました。特に今回はWebページからのクローリングでデータを収集したので、失敗するトラップが多く、大変でした。 そもそも、データがどのような状態になったら収集がうまくいったと判断するのでしょうか?

  • 件数が過不足ないか
  • カラムの内容は正しいか
  • データの期間が想定内か
  • データが正しく結びつくか

などなど様々な観点が思い浮かびます。このような観点を自動テストで書いておいて、データバリデーションとして活用しました。
例を挙げると、レースのデータベースと競走馬のデータベースを正しく作成できたことを確かめるため、レースのデータベースに記録されている競走馬IDをすべて抜き出し、それらが競走馬データベースに含まれるかどうかをテストしています。
GoogleからTFDVというライブラリが出ており、単カラムの統計量やデータスキーマの検証をクイックに行うことができるので便利です。

モデルの性能監視・可視化を行う

モデルは運用を始めると劣化します。データバリデーションではデータの形式の変化やカラムごとの統計的性質の変化を検知しますが、それだけではモデルの劣化を防げません。機械学習モデルは特徴量xと 目的変数yの関数fを推定しますが、このfって時間で変わってしまいそうですね。これをコンセプトドリフトといいます。競馬で例を挙げると、

  • 体重の軽い馬に有利な走法が開発される。
  • 実はある競馬場では外側から走ったほうが有利だが、その競馬場が閉鎖される。

などなど様々な可能性が思いつきます。このような変化は、モデルの性能の劣化前に検知することは難しいこともあります。よって、予測がおかしくなり始めたことをいち早く察知して対応することが必要です。AWSとかでもこれに対応したサービスがありますね
今回は、愚直に利益をグラフにプロットすることにしました。Dashを使うと簡単にダッシュボードを作るとこができます。特に、pandasとの相性がよいと感じます。こんな感じに作りました。 f:id:wata101wata:20210102093615p:plain

これを毎週確認して、劣化していることが確認出来たらデータバリデーションやモデルの再開発などをします。

パイプライン化・自動化して運用を楽にする

今回のモデルは、出走直前にデータをとり、推論する必要があります*3。レースは一日中開催されるので、手作業でやろうとすると大変です。また、毎週レース結果をクローリングして再学習する必要があるので、それも手でやりたくないです。
要件としては最低限それぞれの.pyファイルの実行をスケジュールできれば十分と考えました。MLOpsにおいて最もメジャーなのは*4Airflow だと思いますが、今回はJenkinsでやりました*5

不労所得を目指して

僕も1億5000万円もうけたい

モデルの高度化

掛け金も最適化する

今回のモデルは掛け金の額はスコープ外でした。一旦、100円しか掛けない想定で評価をしています。買い目の程度によってこの辺は最適化できる気がしているので、そこもやってみたいです。

特徴量を追加する

パドックの様子を見て馬の調子を予測するのは一般的にするそうです。ということはパドックの映像も取り込めばもっと精度よく予測できるかも?

ドメイン勉強する

そもそも競馬場に行ったこともないし、競馬中継すら見てないです。逆にこのようなデータ分析をせずに買う馬券を決めるメカニズムを知らないです。競馬で儲けるためには、ほかのみんなの買い方をうまく捉えて活用する必要があるので、このメカニズムを知ることは役に立つはず。

運用の低コスト化

オートスケール

今はEC2をスポットで借りっぱなしにしてその中で開発から運用を行っています。ダッシュボードやjenkinsのために常時起動する必要はありますが、普段はもっと小さいインスタンスにしたて、ETLなどの重い処理をするときだけインスタンスを起動して分散処理することが考えられます。

分散処理

今は全部pandasでETLしており、メモリが余っているにも関わらずCPUが100%に張り付いてしまっています。こういう場合はメモリベースの分散処理するためにsparkを使えばいい(はず?)なので、これもありかと思っています。

別のドメインへ転用

機械学習システムの要素一通り触った感があるので、ほかのドメインへ低コストで展開できるかも。

競輪

netkeibaは競輪もやっている

感想

いままでもMLOpsやデータサイエンスの適用事例は追ってきていましたが、自分で作ってみることによって読み込める力が上がったような気がしています。システムを作るうえでの課題を身をもって感じたので、要点がつかめたことが理由でしょうか。
今回の競馬のように

  • 個人レベルで開発・運用できて
  • うまくいっているか実運用で評価することができる

機械学習システムの適用先ってなかなか思いつかないですよね。ほかにも見つけていろいろ作っていきたいです。

*1:1か月単位で再学習しようと思っていたため

*2:今回の方法だと、レースで出走するすべての馬の単勝確率を足しても1にならないので、和が1になるようスケーリングしました。

*3:モデルに確定オッズを使用しているため、なるべくオッズをそれに近づけたいから

*4:主観です。

*5:DAG書いて管理するほど複雑ではないと考えたため

因果推論の構造化 実践編

このページの目的

前回は因果推論の構造化を試みました。今回は実際のデータに適用する際にどのようになるかを確かめてみたいと思います。 コード全文はこちらに上げておきます。

データの準備

今回のデータは効果検証入門で紹介されていたこちらを使います。*1このデータで興味のあることは、「広告メールを打つことによりその顧客の購入額が増加するか」という因果です。 まずは、カラムの確認をします。

カラム名 説明
recency 最後の購入からの経過日数
history_segment 昨年の購入額の階層
history 昨年の購入額
women 顧客が女性か
zipcode zipcodeをもとに地区を分類したもの
newbie 過去12か月以内に新しく追加されたユーザーか
channel 昨年においてどのチャネルから購入したか
visit メールが配信されてから2週間以内にサイトへ来訪したか
conversion メールが配信されてから2週間以内に購入したか
spend 購入した際の購入額
treatment メールを配信したか

では、このデータの背景にある因果ダイアグラムから考えていきましょう。なお、このデータはRCTデータを加工して非データを作成しているので、推定した因果効果がどれだけ真の因果効果と近かったかを測ることができます。

因果ダイアグラムの構築

専門家の知識による構築

この方法は人間の頭で考えて因果ダイアグラムを構築します。本来なら、広告マーケティングの知識を背景に変数間の因果関係を考えていかなければなりません。しかし、今回はデータが生成された過程(真の生成過程)を知っているのでそれを因果ダイアグラムに反映します。今回のメール配信戦略はrecency・channel ・history に基づいて優良顧客を判断しています。詳しくは冒頭で紹介した本をご覧ください。*2   f:id:wata101wata:20200913220431p:plain

因果効果の推定

前回紹介した傾向スコアマッチングを用いて因果効果を推定します。[dowhy]https://github.com/microsoft/dowhy)を用いると、フレームワークの力で簡潔なコードにできます!基本的にはdowhyのチュートリアルに沿って動かしているのでぜひそちらをご覧ください。

推定の部分だけ転載すると、

causal_estimate = model.estimate_effect(identified_estimand,
                                            method_name="backdoor.propensity_score_weighting",
                                            target_units = "ate",
                                            method_params={"weighting_scheme":"ips_weight"})
print(causal_estimate)
print("Causal Estimate is " + str(causal_estimate.value))

INFO:dowhy.causal_estimator:INFO: Using Propensity Score Weighting Estimator
INFO:dowhy.causal_estimator:b: spend~treatment+channel+history
*** Causal Estimate ***

## Identified estimand
Estimand type: nonparametric-ate
### Estimand : 1
Estimand name: backdoor
Estimand expression:
     d                                          
────────────(Expectation(spend|channel,history))
d[treatment]                                    
Estimand assumption 1, Unconfoundedness: If U→{treatment} and U→spend then P(spend|treatment,channel,history,U) = P(spend|treatment,channel,history)
### Estimand : 2
Estimand name: iv
No such variable found!

## Realized estimand
b: spend~treatment+channel+history
Target units: ate

## Estimate
Mean value: 0.8234131441089386

Causal Estimate is 0.8234131441089386

となり約0.823の因果効果があると推定されました。真の効果は0.77でした。

まとめ

因果ダイアグラムを構築して、因果効果を推定する方法を紹介しました。次のステップとしては、この分析の評価を行いどれほど信頼できるかを考えていきたいと思います。

*1:一部データ変形をして、説明のため解釈を変えています。

*2:正確に言えば、recency・channel ・historyからspendに矢印が伸びるかは不明ですが、今回はとりあえず引いています。

因果推論の構造化

このページの目的

因果推論を構造化して、自分の理解をまとめるためのページです。どこまでわかっていてどこからわかっていないのかを明確にします。

因果推論の構造

機械学習も前処理→学習→評価のようにステップに構造化できますよね。因果推論でもできるかもと思ってるのでやってみます。それぞれでのステップでの問題点と対処法も合わせてまとめていきます。次のようなステップに分解していきます。 f:id:wata101wata:20200709212356p:plain

因果グラフの構築

目的

因果グラフを作成するのがこのステップの目的です。 「相関は因果ではない」は有名な言葉ですね。例えば、入門統計的因果推論では、シンプソンのパラドックスを用いてこれがわかりやすく説明されています。少しだけ紹介します。ある薬が病気を回復させるかどうかを知りたく、投薬するグループとしないグループに分け、病気から快復した割合を集計しました。(出典:入門統計的因果推論)

薬投与 薬投与なし
男性 81/87人が回復(93%) 234/270人が回復(87%)
女性 192/263人が回復(73%) 55/80人が回復(69%)
前代 273/350人が回復(78%) 289/350人が回復(83%)

男性をみると、投薬すると93%回復して、投薬しないと87%回復するので、投薬することは病気の回復に効果がありそうです。女性をみても同じく効果がありそう。
全体をみると、、、あれ?回復率が減ってる???
結局投薬は効果があるのでしょうかないのでしょうか、少なくとも相関を見るだけでは因果がわからないということが理解できる例ですね。面白そうだと思った方は是非出典をご参照ください。

もう一つ例として、国ごとのチョコレートの消費量とノーベル受賞者数を挙げたいです。(出典:チョコレート摂取量が多いほどノーベル賞受賞者が増える : 呼吸器内科医f:id:wata101wata:20200710000826p:plain

p値もばっちりだし、強い相関があると言えますね!さて、これはチョコレートを消費することによって、ノーベル受賞者数が増えることを意味するのでしょうか?直感的にはNOですね。もしかしたら、ノーベル賞を受賞するとチョコレートをたくさん食べるようになるということもあるかもしれません :) しかし、相関を見るだけでは上記のどちらの因果関係があるかは議論することができないですね。

以上からデータ以外に何かを仮定しないと、因果を推定することはできなさそうです。因果を推定するためには、因果グラフを用いて変数間の関係を表現する必要があります。例えば、チョコレートの例では次のような因果グラフを書くことができます。

f:id:wata101wata:20200710002903p:plain
チョコレートを食べるとノーベル受賞者数が増える
f:id:wata101wata:20200710003007p:plain
ノーベル賞をもらうとチョコレートをたくさん食べる
f:id:wata101wata:20200710003136p:plain
GDPが高いことによって、チョコレートの消費量が多くなる。GDPが高いことによって、ノーベル受賞者数が多くなる。

では因果グラフをどのように構築するのでしょうか。正しい因果グラフはどれでしょうか。

どのように因果グラフを構築していくか?

専門家知識による構築

この方法は人間の頭で考えながら作成するという方法です。例においては、「チョコレートを消費することで頭がよくなるはずがない。よってチョコレートの消費量からノーベル受賞者数への矢印は伸ばさない。」「GDPが高ければ、教育にかける費用も大きくなり質の高い研究者が排出され、ノーベル受賞者数が増えると考えられる。よって、GDPからノーベル受賞者数へ矢印を引く。」などどいうように、納得できる理由をもって因果グラフを構築していきます。

有用な点

  • 人間が考えていくので、納得感を反映した因果グラフができる。

  • データを実際に取る前に因果グラフを構築することができるので、これからどのデータを取るべきか議論できる。

アルゴリズムによる構築

データが与えられている場合、アルゴリズムによりそれらの変数間の因果グラフを自動で構築することもできます。次のようなアルゴリズムがあります。

ですが、もちろんそれぞれのアルゴリズムについて満たすべき仮定が増えるので、注意が必要です。

有用な点

  • 比較的因果グラフを構築するコストが小さい。

作成した因果グラフは正しいのか?

第一に、常識で判断するというのが有力な手法であると思います。チョコレートを食べて頭がよくなることはないでしょう。 また、因果グラフが正しいかどうかを直接考えてはいませんが、分析が一通り終わった後、いろいろな観点から、結論に影響がでるかどうかを確認することが多いようです。これを感度分析といいます。これは、評価のステップに後回ししたいと思います。

因果効果の推定

目的

因果グラフが与えられると、どの変数を測定すれば因果効果を測定できるか導けます。そのうえで、それらの変数のバランスを介入・非介入グループでバランスを取らせるのがこのステップの目的です。 たとえば、治験で、投薬、年齢が発病の原因となりうると考えられている場合、次の因果グラフが与えられます。
f:id:wata101wata:20200711192324j:plain
このとき、バックドア基準によって因果効果の推定に必要な変数は投薬の有無、年齢と証明できます。
しかし、まだ問題があります。得られたデータが次のようになっている場合を考えましょう。

f:id:wata101wata:20200711190104p:plain
年齢が偏っていて投薬の効果か分からない

これでは、目的変数への影響が、介入によるものなのか年齢によるものなのかわからない、ということは直感的に理解できますね。 では、それぞれのグループで年齢がバランスするように整えればよいのではないでしょうか。

では、どのようにして整えればよいのでしょうか。この整え方もいろいろあるのでいくつか紹介したいと思います。

最近傍マッチング

「似ているグループをつくるには、似ているペアを作っていけばよい。」というのがアイデアです。あるサンプルを選んで、それと一番似ているサンプルをペアにします。これを繰り返してグループをバランスさせます。

f:id:wata101wata:20200711191235p:plain
似ているものを選んでくる
問題点としては、サンプル数が少なくなってしまうことが挙げられます。

傾向スコアマッチング

「データの数が少ない層を疑似的に増やす。」というのがアイデアです。例えば、60代男性が、介入グループには数人しかいないけど、非介入グループには数十人いる場合、介入グループの20代男性を10倍ぐらいにコピーして水増しすればバランスが取れそうですね!それをすべてのサンプルに対して行います。

f:id:wata101wata:20200711191756p:plain
赤枠で囲われた人が疑似的に増やされた人
これならば、サンプル数を減らさずにグループをバランスさせることができそうです。具体的にどのような計算で増やすかは、こちらの講座をご覧ください。

評価

目的

ここでは次の疑問に対して示唆を得ることが目的です。

  • 結論はどれほど確からしいか?

  • グループ間のバランスはとれているか?

感度分析

様々な観点から、分析結果がどれほど信頼できるかを考察します。
* 一部のデータに対して同じ分析をして、推定値がばらけないか見る。
* 観測できなかった原因を追加する
* プラセボ効果だったとしてシミュレーションする

などなど様々な方法があります。
(因果推論ライブラリdowhyに実装はあるのですが、理論的なところはまだ勉強中です。。。)

グループ間のバランスを見る

二つのグループの分布が似ているかどうかを測れればなんでも良いとは思うのですが、一般的には、指標として、Standerlized Defferenceというものを見るようです(この講座による)。グループ感の差が大きくなるほど、値が大きくなります。これをマッチング前後で比較して小さくなっていることを確かめます。0.1より小さくなっていればバランスしているといってよいです。

f:id:wata101wata:20200711181704p:plain
マッチング前後でのSDの比較 マッチング後に小さくなっていることがわかる

具体的なデータを使って動かしてみる

上記のステップを実際のデータを分析しながら確認していきたいと思います。 が、量が多くなったので、この部分は後日にしようと思います。