🐯

「真の貢献」に思ふ

2023/07/31に公開

京都のリチョーは博学才穎、平成の末年、若くして博士号を取得、ついで都内某大手コンサルに内定したが、性、狷介、自ら恃むところすこぶる厚く、俗物(同僚)の間に伍することを潔よしとしなかった。彼は怏々として楽しまず、狂悖の性はいよいよ抑え難がたくなった。

いくばくもなく職を退いた後は、京都に帰臥し、人と交りを絶って、ひたすら研究に耽った。社畜となって長く膝を俗悪な文系学士卒クライエント及び上司の前に屈するよりは、研究者としての名を死後百年に遺そうとしたのである。

「真の貢献」を定量したい

「真の貢献」をどうやって測れば良いか

これがリチョーの研究であった。

社畜時代、博士号も持たぬ鈍物として歯牙にもかけなかった連中の下命を拝さねばならぬことが、往年の儁才のリチョーの自尊心を如何に傷つけたかは、想像に難くない。

「理由も分らずに会社から押付けられたものを大人しく受取って、理由も分らずに生きて行くのが、我々社畜のさだめだ」

リチョーの元上司はかつてこう言い、あろうことか期末評価で最低点をつけてきた。

リチョーは初め眼を信じなかった。次に、これは夢に違いないと考えた。夢の中で、これは夢だぞと知っているような夢を、自分はそれまでに見たことがあったから。どうしても夢でないと悟らねばならなかった時、茫然とした。そうして懼れた。全く、どんな事でも起り得るのだと思うて、深く懼れた。しかし、何故こんな事になったのだろう。分らぬ。

リチョーは考えた。自らの真の貢献を客観的に評価できる方法がないからであると。

仮に、リチョーの貢献を真に評価する定量的な手法があったのであれば、より適切な(即ち最高の)評価になったであろう。

リチョーは決意した。真の貢献を定量するのだと。

因果推論

真の貢献を定量することは、データサイエンスの文脈で言うところの因果推論と不可分であろう。

「この薬はどれくらい症状を抑える効果があるのか」

「この施策はどれくらい売上リフトをもたらしたのか」

こういったことを知りたいと言う需要はどこにでもあろう。しかし世は往々にして複雑怪奇であり、観察された現象をもたらしたものが何なのか、特定することは困難を極める。相関はわかるが、因果はわからぬことばかりだ。

薬を飲んだから症状が落ち着いたのかも知れぬし、単に時間が経って自然治癒が進んだのかも知れぬ。

肝煎りの施策が売上をもたらしたのかも知れぬし、たまたま季節等の別因子で売上が伸びただけかも知れぬ。

ChatGPTによると、因果推論が本質的に難しい理由が9つある。

因果推論は、効果の発生条件に基づいて因果関係についての結論を引き出す過程で、以下の理由により、本質的に困難とされています:

交絡変数: これらは、独立変数と従属変数の両方を引き起こす要素で、偽の関連性を生み出します。例えば、薬物の病気への影響を決定しようとするとき、患者の年齢は交絡変数になる可能性があります。これは、年齢が病気の結果に独立して影響を及ぼし、また薬物の使用と相関する可能性があるからです。交絡変数は、原因と結果の真の関係を歪め、因果関係を推測することを困難にします。

ランダム化実験の欠如: 理想的には、原因と結果の関係を決定するためには、制御されたランダム化実験を行いたいところです。しかし、これは特に社会科学、経済学、医学などの分野では実行可能であるとは限らず、また倫理的にも問題があります。このような実験がなければ、交絡変数を排除することは困難であり、相関と因果関係を区別することも困難になります。

逆因果関係: XがYを引き起こすのか、それともYがXを引き起こすのかは、特に観察データを扱う際には明らかでない場合があります。例えば、高収入が健康状態を向上させるのか、それとも健康状態が高収入を引き起こすのか? これは特に、2つの変数間にフィードバックループがある場合、特に判断が難しくなります。

時間的順序: 2つのイベント間に強い相関関係があっても、どちらが先に発生したのか、そしてこの順序がすべての観察で一貫しているかどうかを確立するのは困難な場合があります。

測定誤差: 私たちの観察やデータは、関心のある変数の真の値を完全には捉えられないかもしれません。測定誤差は誤った結果を引き起こし、誤った推論を引き起こす可能性があります。

シンプソンのパラドックス: これは、データの異なるグループにトレンドが現れるが、これらのグループが結合されると消失または逆転する現象です。これにより、因果関係を推測する際に誤った結論を引き出す可能性があります。

データの欠落: 多くの場合、完全なデータが得られない。欠落データは結果を偏らせ、因果推論を困難にする可能性があります。

多重因果: しばしば、ある効果には複数の原因があり、これらの原因は複雑な方法で相互作用する可能性があります。このような状況で特定の原因の影響を確定することは非常に困難です。

一般化の問題: 特定の文脈で因果関係を確立できても、これらの知見を他の文脈に一般化するのは困難な場合があります。

これらすべての課題が、因果推論をデータ分析と解釈の最も困難な側面の一つにしています。しかし、近年では因果推論の分野で進歩が見られ、これらの問題を解決するための新しい統計手法や機械学習技術が開発されています。

繰り返すが、ChatGPTが言うように因果推論は本質的に難しい。反実仮想という、この世に存在しない世界線を扱うからである。

リチョーが勤めていた某社は、因果推論が難しいことを逆手に取り、お金を稼いでいた。

「プロモーションから効果検証まで一気通貫のサービス」である。

まず自社サービスをなるべく低脳だが金のある日本企業に使ってもらう。そしてその効果を「因果推論」で定量し、そのサービスを使ったことでこれくらい良いことがありましたよ(だから今後も継続して使っていきましょう)と伝えることで、クライエントも幸福、リチョーの勤め先も幸福なwin-winの仕組みであった。

よくあるビジネスモデルではあるが、これの成功は効果検証によって「ポジティブな結果(売上効果があった等)」が得られるかどうかに大きく依存している。仮にネガティブな効果が出てしまえば、クライエントに切られてしまうからである。

そこでリチョーの会社は

「(現在の)因果推論では真の貢献はわかりっこない」

をいいことに、「効果」が得られるような手法を意図的に選択し、実行していた。

簡単なところだと、差が出るようにコントロール群とテスト群を調整したり、機械学習のseed値やハイパラを「効果」がなるべく大きく出るように実験を繰り返したり...

兎に角、上から「ポジティブな効果を数字で出すこと」が至上命令としてあったので、手に変え品を変え「効果」を作っていたのである。

もちろん見る人が見れば簡単にバレるインチキではあり、論文であれば査読に通りようがないが、クライエントの多くは俗悪な文系なので問題になったことはない。

「何とも感覚的には効果が出ているように感じぬが、定量分析までしていただいて効果が出ているというのであれば問題あるまい。上に良い報告ができる」

クライエントはその上司に良い施策を推進したと褒められ、サービス継続が決まりリチョーの勤務先も潤う。嘘で固められた幸せな世界であった。

「一体、数字のインチキを繰り返す社畜でも、もとは何か他のものだったんだろう。初めはそれを憶えているが、次第に忘れて了い、初めから今の形のものだったと思い込んでいるのではないか?」

一般的な因果推論手法で分析すると「効果」が観測されないプロモーションを、実際に効果があったかのように、博士課程で学んできたあらゆる統計知識を駆使して数字を作るのが、リチョーの社会人としての最初の経験であった。

それ以来今までにどんな所行をし続けて来たか、それは到底語るに忍びない。

True Contribution

近年では因果推論の分野で進歩が見られ、これらの問題を解決するための新しい統計手法や機械学習技術が開発されています。

ChatGPTが最後にコメントしたように、まだ人間の心を持つ研究者が仕事を続けている。

リチョーはNumeraiのTrue Contributionに注目した。

ありとあらゆる状況において、真の貢献を定量できる手法の開発は風呂敷を広げすぎである。まず特定の条件下で、真の貢献を定量する試みをまず学ぶべきだと考えたのである。

Numeraiは米国のヘッジファンドである。

一般的に、ヘッジファンドはポートフォリオ作成のためのシグナルを自社のクオンツが作成するが、Numeraiは自らが主催する株価予測コンペの参加者からシグナルを集めるという奇異なことをしている。参加者は、良い予測シグナルを提出すると、自らのstake額に応じて報酬が貰える仕組みである。

何故Numeraiはそのような異類なことをしているかは置いておいて、ここで興味深いのは

「どの予測シグナルがファンドパフォーマンスに真に貢献しているのか」

という問題である。

Numeraiとしても無闇矢鱈に報酬を参加者に配るわけにはいかぬ。ファンドに貢献しているシグナルにのみ、報酬を弾みたいのである。

無論、将来の株価を完璧に予測しているシグナルがあれば、間違いなく一番ファンドに貢献しているであろう。しかし、Numeraiの売買候補である5,000もの世界株全ての個別銘柄において、株価の完璧な予測はタイムマシンでもない限り不可能である。

では実際の株価との相関が高いシグナルを提出した参加者が、真にファンドに貢献しているだろうか

是...と思いがちだが、必ずしもそうではない。

Numeraiは (Tournamentと呼ばれるコンペでは)特徴量とターゲットを参加者に公表している。そのため、極端なケースでは、ある単一特徴量が最も将来株価と相関の高いシグナルであることもある。ある参加者が、その単一特徴量を「予測シグナル」としてずっと提出していたとしよう。そしてたまたま、相場がその単一特徴量で最も説明できる市況に入ったとき、Numeraiは彼、彼女に最も報酬を出すべきだろうか。

否である。その特徴量は元々Numeraiから提供したもので、すなわちNumeraiが既に持っているシグナルである。Numeraiが既に持っているものを提出されても、それはNumeraiにとって既知であるから、Numeraiに真に貢献しているとは言えないであろう。

また、ある予測シグナル単体での株価説明力が小さくても、その他の提出されたシグナルとの交互作用や、ポートフォリオ作成時の制約条件により、最終的にファンドパフォーマンスに貢献するということもないとは言えぬ。

これは会社に置き換えて考えた方がわかりやすいかもしれぬ。

会社に真に貢献している社員は誰だろうか。

誰でもできる仕事を他の社員より多くこなす社員だろうか。否、その人がいなければ会社がまわらない、そんな仕事をしている社員であろう。

Numeraiも同じである。そのシグナルがなければファンドパフォーマンスが大きく下がってしまう。そんなシグナルを作った参加者に、最も報酬を与えたいのだ。

そんな真の貢献を表す指標として、Numeraiが考案したのが True Contribution (TC) である。

TCの計算

Numeraiは参加者のシグナルを参加者のstake量で加重平均することで、最終的なシグナル(メタモデルと呼ばれる)を作成し、ポートフォリオに変換して、株式市場で運用している。ではもし、

ある参加者のstake量が1単位増えたとき、最終的な運用リターンがX%改善する

ことがわかったらどうだろう。

これは、各シグナルの真の貢献度を定量した数字であると言える。

会社で言うなら、ある社員の仕事時間を月1時間増やしたとき、会社の売上が最も上がった社員を、真の貢献者とするようなものである。

以下がTC計算の概略図である。

stake額において運用リターンの勾配の計算を試みるもので、技術としてはFacebook AIがNeuroIPSに2019年に発表したcvxpylayersを使っている。この技術は微分可能な凸最適化レイヤーをneural network (NN) に組み込むものである。

Numeraiは、

  • 参加者が提出する予測シグナル -> NNへの入力
  • 参加者のそのシグナルに対するstake額 -> 入力への重み
  • 参加者のシグナルを加重平均したメタモデルを、さまざまな制約条件で最適なポートフォリオに変換する -> NNの最適化関数 (optimizer)
  • ファンドの運用リターン -> NNの出力

自身を大きな1つのNNと見なすことで、cvxpylayersのoptimizer部分への組み込みを正当化したのである。

なぜここで従来のNNのoptimizerでは不可なのかと言えば、それではポートフォリオ作成時の制約条件(国、セクター、ベータ、サイズ、モメンタム等のファクターに直交でなければならない等)を考慮できないからである。

様々なファクターをコントロールしたポートフォリオを作成することは、リスク抑制のためファンドとしては必須である。これをやらねば低俗な投資家以外には金を出してもらうことはできぬ。

このような複数の制約条件の中で、シグナルを最適な(= リターンが最大となる)ポートフォリオに変換するoptimizerの工程は、

という凸最適化の数学の問題と捉えられ、cvxpylayersを使うことで(各シグナルの勾配が得られるようになり)、結果、真の貢献の定量化が達成されるというわけである。

Numeraiより、TC計算の概略がPytorchのコードとして共有されている。これはあくまでTC計算のイメージを掴むためのもので、実際には動かぬ。


class SWMModel(nn.Module):
    # 単純かされたend-to-endのStake-weighted meta modelのクラス
    def __init__(self, num_stakes, context, optimizer):
        super().__init__()
        
        self.optimizer = optimizer
        self.context = context

        # ポートフォリオを0で初期化
        self.context.current_portfolio[:] = 0
        
        # stake weighted Meta Modelをlinear layerで作成
        self.lin1 = nn.Linear(num_stakes, 1, bias=False)

    def forward(self, user_predictions):
        # メタモデルのシグナルを計算
        x1 = self.lin1(user_predictions)

        xin = cp.Parameter(x1.shape)

        # optimizerよりcvxpy problemを取得
        self.context.alpha_scores = xin
        self.optimizer._build_optimization_routine(self.context.current_portfolio, self.context, True)
        problem = self.optimizer._optimization_routine

# stake weighted meta modelを定義
swmm = SWMModel(len(stakes), context=context, optimizer=n1_optimizer)

# linear layerの重みをユーザのstakeにする
swmm.lin1.weight.data=stakes.T

# 勾配を0に初期化
swmm.zero_grad()

# 最適化されたポートフォリオとメタモデルのシグナルを取得
swmm_port, swmm_signal = swmm(user_preds)

# ポートフォリオリターンを計算
portfolio_returns = swmm_port.T @ stock_returns

# 勾配計算
portfolio_returns.backward()

# linear stake weighting layerより勾配を取得
stake_grads = swmm.lin1.weight.grad.numpy().copy()

この簡易実装を見るとわかるように、得られる勾配の値は自分の提出したシグナルとstake額だけで決まるわけではなく、他の参加者の提出したシグナルやstake額に大きな影響を受ける

そういったある種の外的要因にTCが大きく影響されないよう、全体のstakeの50%をランダムにdropoutし、勾配を計算することを100回繰り返している。実際にはこの100回の試行で得られた勾配の平均がTCとなる。


for i in range(100):
    print(f'bag {i}', end='\r')
    # stakeの半分をdropoutする
    swmm.lin1.weight.data=F.dropout(stakes.T, .5)
    
    swmm.zero_grad()

    # ポートフォリオとシグナルを得る
    swmm_port, swmm_signal = swmm(user_preds)

    # ポートフォリオリターンと勾配を計算する
    portfolio_returns = swmm_port.T @ stock_returns
    portfolio_returns.backward()
    stake_grads.append(swmm.lin1.weight.grad.numpy().copy())

TCにstakeしてみる

TCの概略を掴んだリチョーは、Numeraiにいくつか予測シグナルを提出し、stakeしたNMR(Numeraiトークン)をTCに賭けてみた。

...。

人間は誰でも猛獣使であり、その猛獣に当るのが、各人の性情だという。

己の場合、自分ほど優秀な人間が真に貢献していないはずがないという思い込みが猛獣だった。

「真の貢献などわかりようがない」ことをいいことに、いい加減な分析で金を巻き上げる低俗な会社を軽蔑しながら、

「真の貢献などわかりようがない」ことをいいことに、自分だけは真に貢献しているはずだと何の根拠もなく信じていた。

人生は何事をも為なさぬには余りに長いが、何事かを為すには余りに短いなどと口先ばかりの警句を弄ろうしながら、

事実は、才能の不足を暴露するかも知れないとの卑怯な危惧と、

刻苦を厭う怠惰とが己の凡てだったのだ。

堪え得ざるが如き悲泣の声が洩れた。

その夜半、急に顔色を変えて寝床から起上ると、何か訳の分らぬことを叫びつつそのまま下にとび下りて、闇の中へ駈出した。

彼は二度と戻って来なかった。

附近の山野を捜索しても、何の手掛りもない。

その後どうなったかを知る者は、誰もなかった。

引用

https://www.aozora.gr.jp/cards/000119/files/624_14544.html

https://docs.numer.ai/numerai-tournament/scoring/true-contribution-tc

https://forum.numer.ai/t/true-contribution-details/5128

https://medium.com/numerai/alien-stock-market-intelligence-numerais-true-contribution-6bc7652bd6ac

https://github.com/cvxgrp/cvxpylayers

https://locuslab.github.io/2019-10-28-cvxpylayers/

https://tech.curama.jp/entry/2018/04/20/120000

https://qiita.com/taka_horibe/items/0c9b0993e0bd1c0135fa

Discussion