盆暗の学習記録

データサイエンス ,エンジニアリング,ビジネスについて日々学んだことの備忘録としていく予定です。初心者であり独学なので内容には誤りが含まれる可能性が大いにあります。

SHAP valuesの論文を読んだのでメモする

Lundberg, S. M., & Lee, S. I. (2017). A unified approach to interpreting model predictions. Advances in neural information processing systems, 30.

2017年の論文なので今更ですが読んだのでメモします。

沢山の内容を10ページに詰め込んだような全体的に説明が少ない論文だったので、ふわっとした理解のまま書いてます。誤情報があったらごめんなさい。

概要

  • 「この予測値はどういう特徴量が影響してこうなったのか」という局所的説明(local explanation)を行う手法
  • 特徴量の貢献度の推定量としてゲーム理論のShapley valuesの概念を使用することで望ましい性質を持つ推定量を開発(望ましいという根拠は不明)
  • 計算量が多いShapley valuesを重み付き最小二乗法で線形近似することで実用的な計算量にした

内容まとめ

additive feature attribution methods

この分野の先行研究として、LIMEやDeepLIFTのような既存の説明手法が存在する。これらは数学的には似ていて

のような線形のモデルで表現する形をとる共通点がある。

ここでφは特徴量の貢献度(attribution)で、z'は特徴量の有無を示す二値変数(z' ∈ {0 ,1}^M)であり、Mは特徴量の数で、iは列のインデックス。

本論文ではこうした手法を総称してadditive feature attribution methodsとよぶ。

先行研究たちの構造(線形、というモデルの構造)は一緒で、φの推定量が異なるような状況。

定量の性質とShapley values

このφの求め方は色々あるが、以下に述べる3つの性質を持つような解はひとつしか存在せず、その解はShapley valueである。

  1. Local accuracy: 説明モデルg(x')と元の予測モデルf(x)の出力値が一致する
  2. Missingness: ある特徴量が欠損しているとき、その特徴量は予測に貢献しない
  3. Consistency: 予測モデルf(x)の出力値を増加あるいは維持する(下げない)特徴量があるとき、その特徴量の貢献度も下がらない

(Missingnessはadditive feature attribution methodsであれば満たされる。Local accuracyとConsistencyはShapley valueに関する研究で性質が明らかになっている)

以下の式がShapley valuesとして知られるもので、これは特徴量を追加したときの予測値の変化を、特徴量の有無のすべての組み合わせにわたって加重平均したものである。

SHAP values

Shapley valuesを条件付き期待値で表現したもの。

Kernel SHAP

先行研究にはLIMEという局所線形近似によって説明モデルを作る手法がある。LIME推定量がShapley valueになるかどうかは損失関数L、重みカーネルπ、正則化項Ωに依存する。

以下のΩ, π, Lを使えば推定量がShapley valueになる

誤差関数は重みつきの二乗誤差 → 重み付き最小二乗法で推定できる。

数値例

「重み付き最小二乗法で求める」という方法について論文中ではさらっと説明が終わったので、こんな感じかな?と推測しながら書いたもの。

それっぽい値が出ているものの、なんか違う気もする。間違っている可能性が結構あるので話半分にみていただければと思います。

一番間違ってそうな箇所は予測値 y = f(h_x(z)) の部分で、特徴量が欠損している場合にどうやって予測させるかです。線形回帰なら特徴量をゼロとおけばいいけど欠損値を扱えない機械学習アルゴリズムの場合はこれができないので間違ってる気がする。でも正解の形がわからない・・・。

CSVとFeather, Parquetを比較してみる

最近Parquetというファイルフォーマットを知りました。S3にデータを置いてDWHを作ったりする際などに使うようです。

pyarrowパッケージをインストールしていればpandasからFeatherやParquetにお手軽に保存できることに気づいたので試してみてCSVと比較してみます。

比較方法

以下のようなランダムな値を入れたレコードを生成させてテストデータに使用します。

import random
from time import time
from string import ascii_letters
import pandas as pd
from pathlib import Path


def random_datetime():
    return pd.Timestamp(
        year=int(random.uniform(1990, 2020)),
        month=int(random.uniform(1, 12)),
        day=int(random.uniform(1, 28)),
        hour=int(random.uniform(1, 23)),
        minute=int(random.uniform(1, 59)),
    )

def gen_data(n=100):
    return pd.DataFrame({
        "int": list(range(n)),
        "float": [random.random() for _ in range(n)],
        "bool": [random.choice([True, False]) for _ in range(n)],
        "string": [''.join(random.choices(ascii_letters, k=10)) for _ in range(n)],
        "date": [random_datetime().date() for _ in range(n)],
        "datetime": [random_datetime() for _ in range(n)]
    })

そして、

  1. ファイルの保存(ディスクの書き込み)にかかった時間
  2. ファイルの読み込みにかかった時間
  3. ファイルサイズ

を比較してみます。

保存と読み込みは10回繰り返して平均をとります。

レコード数は [10_000, 100_000, 1_000_000, 10_000_000, 20_000_000] で試します。

保存時のオプション引数はデフォルトから変更せず(圧縮アルゴリズムなどは変えず)以下のように保存します。

df.to_csv('df.csv', index=False)
df.to_feather('df.feather')
df.to_parquet('df.parquet', index=False)

なお検証時のバージョンは以下の通りです。

  • python == 3.8
  • pyarrow == 7.0.0
  • pandas == 1.2.0

結果

保存速度

ファイルの保存にかかった時間は実数では上のグラフのようになりました。

f:id:nigimitama:20220305223754p:plain

CSVに比べた変化率は以下の表のようになります。

n feather parquet
10,000 -78.4% -69.6%
100,000 -95.0% -90.1%
1,000,000 -95.9% -93.9%
10,000,000 -96.0% -94.8%
20,000,000 -96.0% -94.8%

featherで78%~96%削減、parquetで70%~95%削減されました。レコード数が10,000のときが最も削減効率が悪かったです。

featherもparquetもcsvに比べると段違いに速いですが、featherのほうがparquetよりも若干速いですね。

読み込み速度

読み込みにかかった時間は次のグラフのようになります。

f:id:nigimitama:20220305223809p:plain

CSVに比べた変化率は以下の表のようになります。featherもparquetもcsvに比べると段違いに速いです。featherのほうがparquetより速いですね。

n feather parquet
10,000 -48.9% -22.0%
100,000 -73.0% -66.9%
1,000,000 -73.4% -71.3%
10,000,000 -70.0% -65.1%
20,000,000 -68.1% -53.4%

ファイルサイズ

ファイルサイズはCSVの半分程度になりました。

f:id:nigimitama:20220305222415p:plain

parquetはレコード数が増えるほどファイルサイズの削減効率が高まるようです。

n feather parquet
10,000 -47.2% -39.1%
100,000 -48.0% -41.9%
1,000,000 -48.7% -52.7%
10,000,000 -49.4% -54.6%
20,000,000 -49.8% -55.0%

(参考)グラフの元データ

上記のグラフの元となった具体的な数値の表も載せておきます。

n format write_mean write_std read_mean read_std size
10000 csv 0.044 0.001 0.013 0.001 0.683
10000 feather 0.010 0.009 0.007 0.000 0.360
10000 parquet 0.014 0.009 0.010 0.008 0.416
100000 csv 0.425 0.005 0.101 0.003 6.929
100000 feather 0.021 0.001 0.027 0.001 3.606
100000 parquet 0.042 0.002 0.033 0.004 4.024
1000000 csv 4.268 0.030 1.060 0.018 70.248
1000000 feather 0.175 0.007 0.282 0.004 36.026
1000000 parquet 0.261 0.008 0.304 0.006 33.239
10000000 csv 43.220 0.294 11.146 0.245 711.997
10000000 feather 1.709 0.023 3.346 0.108 360.235
10000000 parquet 2.257 0.050 3.895 0.106 323.421
20000000 csv 86.777 0.370 26.038 1.720 1434.600
20000000 feather 3.458 0.054 8.299 0.439 720.470
20000000 parquet 4.518 0.137 12.126 0.866 645.739

まとめ

データ分析時に前処理済みの訓練データの保存を行う際はcsvよりもfeatherやparquetのほうが良さそうですね。

「レコード数が極端に多いデータで、書き込み・読み込みの速度よりもファイルサイズの圧縮を重視したい」という場合はparquetのほうが良さそうですが、そうでない場合はfeatherが扱いやすそうです。

note.comを読みやすくするChrome拡張機能を作った

皆さんはnote.comを使っていますか?

最近は利用者がどんどん増えていて記事数も多いため、なにか興味深い記事を見かけた際にアクセスする機会も増えているのではないでしょうか。少なくとも私はそうです。

noteはいいサービスだなと思う一方で、記事を読みづらいUIだと感じています。その理由は

  1. 記事の幅が狭いこと(620px固定)
  2. サイドバーに固定表示される目次が無いこと

の2点です。

例えば1920 x 1080のディスプレイで見ると、以下のようになってしまいます。

(例として使わせていただいた記事:https://note.com/keisemi/n/nc2c374fad8d6

短い記事だったらいいんですが、長い記事だとこのUIで読むのは辛いです。

そこで上記2点を改善するChrome拡張を作りました。

https://chrome.google.com/webstore/detail/note-toc/dddpojfjpcidbebhjijlchdkfmegoidgchrome.google.com

これを導入するとこんなUIになります。

もし同じ不満をお持ちの方がいらっしゃいましたら使ってみてください。そのうちnoteがアップデートされてこんな拡張は不要になると思いますが、それまでの間を多少は快適に過ごせるかと思います。

「150 successful machine learning models: 6 lessons learned at booking. com」を読んだ

KDD19で発表されて一時期話題になっていたBernardi et al. (2019) 150 Successful Machine Learning Models: 6 Lessons Learned at Booking.comを読みました。

これは宿泊施設を検索して予約できるウェブサイト「Booking.com」における機械学習の活用事例と、その過程で得たノウハウについての論文です。

機械学習のビジネス活用に焦点を当てていて良い論文でした。

以下にざっくり内容をまとめてメモしていきます。

機械学習はビジネスに貢献する

まず、機械学習の活用事例について。

Booking.comでは多数の機械学習モデルを利用しているのですが、例えば、

  • お客様の旅行のcontextを予測して、子供がいたらその情報も検索欄に入れるようにリマインドする(Figure 1 (a))
  • 各宿泊施設についてのレビューを要約する(Figure 1 (b))
  • 特定の都市の価格のトレンドなど有益な情報を提示する(Figure (c))

みたいなことをしているそうです。

f:id:nigimitama:20211227224734p:plain

また、Booking.comにおいては機械学習モデルはRCTによってビジネス指標で評価しているらしいのですが、機械学習は十分なビジネス貢献をしていることを述べていました。

f:id:nigimitama:20211227224744p:plain

Figure 2のBenchmark以外の各バーは機械学習の活用の各カテゴリ(model family)で、Content Curation以外はBenchmark(これらの機械学習の活用以外のプロジェクト)を上回っています。

Offline Metricsはビジネス指標とは相関しない

モデルのOffline EvaluationにおけるMetric(ROC-AUCとか)の改善がビジネス貢献につながるとは限らない、という発見について。

f:id:nigimitama:20211227224805p:plain

Figure 4は機械学習モデルの改善を行った23個のペア(46モデル)についての図です。横軸がOffline EvaluationのMetrics(classifierについてはROC-AUCでrankerについてはMean Reciprocal Rank)の相対差で、縦軸がOnline EvaluationにおけるConversion Rateの相対差になります。

これについての著者らの考察は次のようなものでした:

  1. パフォーマンスの増加によるビジネス価値の増加は逓減する
  2. 不気味の谷現象:ユーザーの行動をピッタリ予測しすぎて気味悪がられる
  3. 中間的な指標への過度な最適化:例えばクリック率を最適化するようにモデルを作っていった結果、コンバージョンにつながらない「単にクリックさせるだけ」のモデルになっていった

Booking.com内では他の領域の実験でも一貫して同様の結果が得られたそうです。

Latencyの増加がビジネスに悪影響を与える

latency(待ち時間)が増えるとビジネス指標を下げるし、逆にlatencyを下げる努力をすることでビジネスを改善できたという報告。

Figure 6は横軸がlatencyの処置群と対照群の相対差で、縦軸がConversion Rateの相対差です。図の右下の象限は程度の異なる人工的なlatencyを処置した実験のもので、左上の象限は独立した4つの実験の結果です。

f:id:nigimitama:20211227224823p:plain

機械学習は計算コストが多いためlatencyとも関わってきます。Booking.comでは計算量を下げるために、様々な工夫をしているそうで、個人的に印象的だったのは次のものでした:

  • 自社開発した線形予測エンジン: 予測時間を最小化するように徹底して調整した線形予測を自社で開発した。これはナイーブベイズ、一般化線形モデル、k-NN、Matrix Factorization modelなどの全てのモデルを内積に緩和することができる。
  • Precomputation and caching: 特徴空間が小さい時、すべての予測値を単純にkey-value storeに分散することができる。特徴空間が大きすぎるときもよくあるリクエストはメモリにキャッシュすることができる。

線形予測エンジンについてはどうやって計算量を下げているんだろう…という感じですが、論文中では詳しくは書かれていませんでした。precomputationは言われてみれば確かに当たり前なんですが徹底してるなーと感じました。

予測値のみでモデルの品質を監視する

デプロイして稼働させている機械学習モデルが変な値を予測していないかは気になるところだと思います。

しかし少なくともデプロイしてすぐには正解データ(教師ラベル)がない状態なので、予測値が正しいかどうかがわからないという問題があります。

Booking.comではこうした「単純に予測値だけを見てモデルの品質についての情報を得たい」という問題に取り組み、二値分類に関してはResponse Distribution Analysisという方法を考案して使用しているそうです。

この方法は単純に分類器の出力({0, 1}の値ではなく、スコアのほう)のヒストグラムを作り、

  • 理想的な二値分類器は0付近と1付近にピークを持つ二峰の分布になるはず(Good discriminator)
  • 二値分類なのに単峰の分布になっていたら、全然分類できていない(High Bayes error)

といった感じに診断していくというものです。

f:id:nigimitama:20211227224839p:plain

実験設計の重要性

例えば、「別の目的地をレコメンドする」という処置は、Booking.com上では「この人は目的地についてレコメンドしても邪魔にならない」と判断されたユーザーに対してしか行うことができません。そのため実験もそのようなユーザーにしか行うことができません。

このようにモデルに依存して処置が利用可能かどうかが決まる場合、処置群の一部の個体しか処置されないため、標準的なRCTの枠組みをそのまま適用すると、検出される効果を薄めてしまいます。

そこでBooking.comではTriggered AnalysisDeng & Hu, 2015)という改良版のRCTを利用しているそうです。これは処置群と対照群に割り振られた個体のうち、モデルの出力に照らして処置が利用可能だった個体のみを使用して実験を行うという枠組みです(Figure 8)。

f:id:nigimitama:20211227224852p:plain

さらに、3グループに分けて実験を行うことで、モデル導入時の効果を「latencyの増加による影響」と「モデル自体の純粋な効果」に分解できます。 2つに分けた処置群の両方ともモデルを動かすものの、結果を使うのはTreatment group 1にすることで、

  • ControlとTreatment 1の比較=モデル導入の全体的な効果
  • ControlとTreatment 2の比較=モデル導入のlatency増加による効果
  • Treatment 1とTreatment 2の比較=モデル自体の純粋な効果

という風に分解できるようになります。

f:id:nigimitama:20211227224901p:plain

新旧モデルの比較時も3群で実験を行い、両モデルで結果が異なった(Models Disagree)個体だけを分析に使うようにしているそうです。

f:id:nigimitama:20211227224920p:plain

まとめ

ざっくりいうと

  • 機械学習の活用はビジネス上の価値をもたらした
  • offline evaluationのmetricsの改善はビジネス上の利益とあまり相関しなかった
  • latency(待ち時間)が多いとビジネスに損害をもたらす。逆にlatencyを削減することで利益を増加させることができた。
  • 標準的なRCTが合わない状況もある。実験設計をしっかり行うことで「機械学習の導入の効果」から「導入によるlatency増加による負の効果」と「機械学習自体の純粋な効果」に分離することができた
  • 機械学習モデルの品質の監視のためのResponse Distribution Analysisという方法を考案し、活用した

という感じでした。

Online Evaluationの重要性と、その際の実験設計(latencyの効果とモデルの効果との分離など)の重要性がわかるよい論文でした。

参考

Deng, A., & Hu, V. (2015, February). Diluted treatment effect estimation for trigger analysis in online controlled experiments. In Proceedings of the Eighth ACM International Conference on Web Search and Data Mining (pp. 349-358). https://dl.acm.org/doi/abs/10.1145/2684822.2685307

『データ分析と意思決定理論』を読んだ

『データ分析と意思決定理論』を読みました。

この本は経済学者が書いた一般向け(非専門家向け)の本で、第1部がデータ分析、第2部が意思決定理論という構成になっています。

要点や印象的だった点などをメモしておきます。

第1部(データ分析)について

世の中のさまざまな分析・推論は信頼できない仮定に基づいている

  • 基本的に、分析で強い結論を得るためには強い仮定を置いて分析する必要がある
  • 多くの人は点推定のように強い結論を好むため、世の中の様々な分析は分析者の強い仮定の下で行われている
  • 仮定の置き方によって導かれる結論が変わることはよくあることなので(本書中で時々引用されるManskiの研究でもそういうものは少なくない)、どういう仮定を置いた分析なのかに注意する必要がある

RCTも仮定の下での分析

  • ランダム化比較試験(RCT)も(経済学にとっては)強い仮定の下の分析である
  • RCTには、「処置に対する反応は個人だけで、他のメンバーに影響を与えあうような社会的相互作用(social interaction)がない」とする仮定がある。
    • 例えば「職業訓練プログラム」を処置として扱うなら処置によって労働市場の状態が変わってしまうので仮定が満たされない
  • 実際のRCTはゴールドスタンダードと呼ばれるほどの理想とは程遠い。しかし、信頼できる区間予測を作ることはできる。

部分識別

  • 部分識別(partial identification)は効果の推定を点ではなく区間で行い、仮定を置かない状態から徐々に仮定を追加していって分析する。

f:id:nigimitama:20211226161905p:plain

f:id:nigimitama:20211226161911p:plain

(出所:奥村(2015)「部分識別とその応用: 処置効果を中心に」

第2部(意思決定理論)について

意思決定理論とは

  • 意思決定の価値(効用や厚生とよぶ)が部分的にしかわからない状況下で、意思決定者がどう振る舞うのが妥当なのかを考える分野。
    • もし厚生がすべて既知なら単にそれを最大化するようにすればよいので、不確実性が前提

用語

  • 意思決定の結果は、選択した行動と環境特性によって決まると定式化する。この環境の特性を自然状態と呼ぶ。
  • 意思決定者が起こりうると考える自然状態をすべて網羅するリストは状態空間と呼ばれ、部分的な知識を表す。
  • 行動選択から生じる結果の厚生を、行動C、自然状態sからW(C, s)と表す。これを厚生関数という。状態空間は意思決定者のもつ知識(情報)を表すのに対し、厚生関数は意思決定者の選好を表す。

意思決定基準

(1) 「支配される行動」を消去する

  • 行動CとDがあるとし、すべての自然状態のもとで W(C, s) ≧ W(D,s) のとき、DはCに支配される行動だと言われる。支配される行動は選ぶべきではない。

(2) 支配される行動以外の行動の選択肢が複数個残った場合:

  • 期待厚生基準:各自然状態が発生すると考える信念の強さ(意思決定者の主観確率)で重み付けして加重和(期待値)を計算し、その厚生の期待値が最も高くなる行動を選択するという基準。
  • マキシミン基準(maximin criterion):行動が生み出す厚生の最小値(各行動の最悪ケース)でその行動を評価し、その厚生の最小値のなかで最も大きい厚生を生む行動を選択する。
  • ミニマックス・リグレット基準(minimax regret criterion):リグレットとは各自然状態の下での最高と最悪の結果の差。起こりうるすべての自然状態にわたってその行動が生み出すリグレットの最大値を求め、その値でその行動を評価する。
  • (※常にこれを選べばいい、みたいな最高の基準はないので妥当な基準を選ぶ必要がある)

適応的分散:処置を順次施していく場合

  • いくつかの時点に分けて意思決定できる場合、対象の集団をいくつかのグループ(コホート)に分けて順次処置を施していき、前のコホートの結果に応じて後のコホートの意思決定の参考にすることができる
    • 適応的ミニマックス・リグレット(Adaptive Minimax Regret: AMR)基準:プランナーは処置の時点でわかっている処置反応のデータを使って、各コーホートミニマックス・リグレット基準を適用する。

集団による意思決定

  • 意思決定者が複数人からなり、個々人で意思決定基準が異なる場合はどうなるのか
  • 投票で意思決定する場合は社会選択理論の話になっていく(どういう選好を持つ人々がいるのかの前提によって結果は変わる。特定の前提の下での理論は例えばアローの不可能性定理、ブラックの中位投票者定理などがある)
  • 議会内での投票など、戦略的相互作用が存在する場合は、自分の選好通りに投票しないことが有利になることがあり得る
  • 投票ではなく二者間の交渉の場合、エッジワースボックスのパレート最適な配分に落ち着くことが考えられる

感想

  • 読んでいくなかで、Manskiは分析の仮定に非常に注意を払っている方だなというのが感じられて、科学者の態度として勉強になりました。
  • 部分識別の「仮定を置かない状態から徐々に強めていく」というアプローチは非常に良いと感じました。

  • 意思決定についてはバンディット問題みたいな感じもあり興味深いですね。

    • ただ、個人ならまだしも集団の意思決定となると参加者の選好も未知ですしなかなか複雑で分析も難しそうなチャレンジングな感じですね。
  • 一般向けの本ということで全体的に広く浅く書かれた本ですが、各分野に興味を持つきっかけになるという分にはいい本かなと思います。
    • 一つ文句をいうとすれば、この本は何故か縦書きになっていまして、縦書きに書かれた数式が読みにくくて仕方ありませんでした…

NGBoostの理論のまとめ

NGBoost: Natural Gradient Boosting for Probabilistic Predictionの論文を読んだのでメモしておきます。

ざっくり要約すると以下のような感じでした。

  • NGBoostは予測を点ではなく分布で予測するための機械学習アルゴリズム
  • 勾配ブースティングの枠組みで最尤推定する
  • 最適化にはニュートン法を改良したフィッシャーのスコア法をベースにしており、指数分布族以外の分布や特殊なパラメータを仮定する指数分布族でも使えるよう一般化している
  • 予測を点で推定した場合の精度はRandom Forestに匹敵するが通常の勾配ブースティングに劣るくらい

もう少し詳しい話は以下に述べていきます。

理論の概要

私の考察を交えつつ、NGBoostの理論の概要を述べます。

解きたいタスク

機械学習を使うタスクでは、予測の不確実性が評価できると嬉しい場合が結構あります。

例えば「この予測対象については訓練データにも類似する事例がないので、この予測値の信頼性は低いです」みたいな情報を予測器が述べてくれると、その予測結果を使う人間にとって便利だったりします。

そこで、予測を点ではなく分布で行いたいとします。

NGBoostでは扱う分布をパラメータで規定される分布のみに限定することで分布の推定問題をパラメータの推定問題へ緩和します。例えば予測分布が正規分布であると仮定する場合、平均μと分散σの2つのパラメータの推定問題になります。

ただし、このパラメータはxの関数です。通常の勾配ブースティングで誤差関数がMSEのときはxの条件付き平均E[y|x]を推定するわけですが、NGBoostではそれに加えてxの条件付き分散も求める、という感じです。

スコア関数

パラメータ推定のためには通常の機械学習アルゴリズムの誤差関数に相当するものを定義する必要があります。

ただし、今回は分布を推定したいので、真の分布との距離を測れるような関数を定義する必要があります。

具体的には対数尤度関数や、尤度を拡張したCRPSという関数がスコア関数にあたります。

自然勾配

勾配はパラメータを微小に変化させたときに目的関数を最も変化させる方向です。しかし、本当は分布を微小に変化させたときの目的関数を最も変化させる方向が知りたいため、NGBoostでは勾配をより一般化した自然勾配を使います。

自然勾配(natural gradient)はリーマン計量の逆行列を勾配に乗じたものです。

f:id:nigimitama:20210529145206p:plain

スコア関数が対数尤度の場合、このリーマン計量はフィッシャー情報行列(符号を反転させたヘッセ行列の期待値をとったもの)になります。

つまり、最尤推定法におけるフィッシャーのスコア法(Fisher's scoring method)に相当することを勾配ブースティングでやっているのだと思われます

ニュートン法との違い

フィッシャーのスコア法を使うメリットはなんなのか?という点について、NGBoostの論文では

確率分布が指数分布族のものであり、分布のパラメータ化をその族の自然なパラメータで行うとき、Newton-Raphson stepはnatural gradient descent stepと等しい。

という感じのことが書かれております。

NGBoostは一般化のために自然勾配を使っていますが、逆に言うと、指数分布族の分布で通常のパラメータを使うのであればニュートン法で十分なのかなと思います。

例えばXGBoostやLightGBMはニュートン法による勾配ブースティングを行っているはずなので、それらのアルゴリズムでも誤差関数を尤度関数にすればNGBoostと同じような結果が得られて分布での予測ができそうな感じがします。

実用に関する考察

NGBoostは通常の機械学習のように点推定で結果を出した場合の予測精度がscikit-learnの勾配ブースティングの実装にも劣るようなので、使用上はそこがネックになりそうな感じがします。「多少精度を落としてでも予測の不確実性が評価できるような予測を行いたい」というニーズがある状況では活きるかもしれません。

NGBoostはライブラリが公開されているのですが、XGBoostのように正則化をしたりといった精度向上のための細かなパラメータ調整ができなかったり、LightGBMのような計算の高速化がなくて大規模データへの対応がしにくかったりする欠点があります。これらの点については先述のようにLightGBMを使って最尤推定することで解決できるかもしれません。

参考

詳しい理論の解説はこちらのブログがわかりやすいかと思います。

NGBoostを読んで、実装する。 - nykergoto’s blog

pystanの環境構築で詰まったときのメモ

変なつまり方をしたのでメモ

まとめ

  • dockerのpython:3.9をベースイメージに環境を作ろうとしていたが、動かなくて困っていた
  • pystan 3.0 は gcc ≥ 9.0 が必要であるにも関わらず、python:3.9のイメージに入っているgccはver.8系だったのが原因と思われる
  • ubuntu:20.04をベースにしたら治った

症状

ドキュメントのQuick Startにあるコードを実行しようとしていたが、次のようなエラーが起こっていた

Building... This may take some time.
Messages from stanc:
Warning:
  The parameter mu has no priors.
Warning:
  The parameter tau has no priors.
Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/aiohttp/web_protocol.py", line 422, in _handle_request
    resp = await self._request_handler(request)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/web_app.py", line 499, in _handle
    resp = await handler(request)
  File "/usr/local/lib/python3.9/site-packages/httpstan/views.py", line 253, in handle_show_params
    services_module = httpstan.models.import_services_extension_module(model_name)
  File "/usr/local/lib/python3.9/site-packages/httpstan/models.py", line 90, in import_services_extension_module
    module: ModuleType = importlib.util.module_from_spec(spec)  # type: ignore
  File "<frozen importlib._bootstrap>", line 565, in module_from_spec
  File "<frozen importlib._bootstrap_external>", line 1108, in create_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
ImportError: /root/.cache/httpstan/4.4.2/models/dnt4r2yw/stan_services_model_dnt4r2yw.cpython-39-x86_64-linux-gnu.so: undefined symbol: _ZNSt19basic_ostringstreamIcSt11char_traitsIcESaIcEEC1Ev
Traceback (most recent call last):
  File "/src/getting-started.py", line 27, in <module>
    posterior = stan.build(schools_code, data=schools_data, random_seed=1)
  File "/usr/local/lib/python3.9/site-packages/stan/model.py", line 450, in build
    return asyncio.run(go())
  File "/usr/local/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/local/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.9/site-packages/stan/model.py", line 439, in go
    raise RuntimeError(resp.json()["message"])
  File "/usr/local/lib/python3.9/site-packages/stan/common.py", line 24, in json
    return simdjson.loads(self.content)
  File "/usr/local/lib/python3.9/site-packages/simdjson/__init__.py", line 61, in loads
    return parser.parse(s, True)
ValueError: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.

原因

おそらく、python:3.9のイメージに入っているgccが古すぎた

# gcc --version
gcc (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

apt-get updateして新しいgccを入れようとしても「これが最新」と言われてしまい、このイメージでなんとかしようとするのは手間がかかりそうだった

対処

もっと新しいgccが入ったものを使うことにした

例えばubuntu 20.04はgcc 9.3.0がデフォルトで入っているのでこれを使うことにした

# gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

これにより問題なくpystanが動くようになった