Lecture 1:実証産業組織論/quantitative marketingへようこそ

計量経済学II

作者

Kei Ikegami

重要この講義で押さえたいこと
  1. 実証ビジネス・エコノミクス、実証産業組織論(IO)、quantitative marketingという3つの隣接分野の関係を整理し、企業の意思決定が抱える4つの問い(需要と代替性・因果効果・顧客異質性・最適化)とこのコース全体の対応関係を頭に入れる。
  2. 広告費と価格設定の例を通じて、従来の仕組みが続く世界で予測がよく当たっても、制度を変えた世界の「いいシミュレーション」になるとは限らないことを理解する。
  3. 何を変え、何を固定した世界を計算したいのかを明確にし、意思決定に使える「いいシミュレーション」を作るために構造推定を学ぶ、という見取り図を持つ。

計量経済学Iでは、OLS・標準誤差・検定といった一般の推定・推論の道具を学び、さらに固定効果モデル、DiD、操作変数法、RDDなどを、それぞれの識別仮定のもとで因果効果を測る設計として学んだ。

計量経済学IIはその続編である。ただし今回は、「ある施策の効果を測る」だけでなく、モデルを使って「もしこうしていたら」を計算するというところまで踏み込む。例えば、次のような「もしこうしてたら」を計算の対象とする。

  1. 値上げをしたら需要はどう変わるか。
  2. 新製品を出したら既存製品からどれだけシェアを奪うか。
  3. 2つの企業が合併したら価格はどう動くか。
  4. 広告予算をどう配分すれば利益をもっと上げられただろうか。

こうした問いに答えるには、単に「過去にこうだった」というデータの記述や、ある1つの施策の因果効果を測るだけでは足りない。まだ観測されていない世界の状態をモデルで作り出す必要がある。これが構造推定(structural estimation)とそれに基づく反実仮想シミュレーション (Counterfactual Simulation)であり、そのための方法論を作り出してきた実証産業組織論(empirical IO)やquantitative marketingが企業や政策当局の意思決定に使われる最大の理由となっている。

計量Iからシミュレーションこそが計量経済学の最終目標という話をしてきたが、計量経済学の教科書でそのような主張が明記されることは少ないと思う。大体は計量経済学の目的は経済モデルを統計的にテストをするとか書いてある。ここでは池上の主張しているシミュレーションこそが最終目的説が池上独自のものではなく、計量経済学の王道であることを説明しておく。

ちょっと勉強したことのある人なら知っているだろうが、経済学の実証研究には誘導形(Reduced form analysis)と構造推定(structural estimation)という対立(?)する2つの流派がある。

構造推定はこの授業が扱うもので、経済モデルを書いて、それをデータから識別、推定し、反実仮想シミュレーションをするものを目指すものだ。その意味で、シミュレーションが最終目的であるという主張は構造推定に慣れ親しんだものからすると全く違和感はないはずだ。構造推定では「もしこうなっていたら」を、その変化に対して不変なモデルの一部をデータから推定しておくことで、システムの一部を変更したシミュレーションをして「もしこうなっていたら」を計算する。

この営みの始祖はTrygve Haavelmo(1989年ノーベル経済学賞)の博論(!?)で議論されている同時方程式バイアスの話である。需要関数と供給関数の交点での「数量」と「価格」が均衡として実現するというのが経済学の根本原理である。だとするならば、観測された数量を価格に回帰分析しても、その結果は需要関数にも供給関数にもならないだろう、というのが同時方程式バイアスと呼ばれるものである。これが1940年代の研究で、Haavelmoによって経済学に「内生変数」「外生変数」「誤差項」とそれらを組み合わせて「統計モデル」が持ち込まれた。同時方程式バイアスへの対処として外生変数を使って片方の式(例えば供給関数)だけを動かしてそれによってもう片方の式(例えば需要関数)を推定しようという発想も提案されており、これは50年後ぐらいにAngristによってIVを使った2SLSによる因果推論というアイディアに結実する(というのは言い過ぎかも?)。これ以前経済モデルに統計分析をまともに使うことはなかったらしいので、現代的な意味での計量経済学という分野それ自体の起こりは間違いなく構造推定だったと言える。

構造推定はHaavelmo以降、多様な進化を始める。まず特筆すべきはDaniel McFadden(2000年ノーベル経済学賞受賞)による離散選択モデルの確立である。“Conditional Logit Analysis of Qualitative Choice Behavior” (1974)という伝説の論文で離散選択モデルを経済学に導入した。これは財に対する「効用関数」という不変のオブジェクトを推定し、その一部を変更したときの人々の選択行動をシミュレートするものである。この授業の前半は全てこれに捧げられる。

さらに、産業組織論ではTimothy Bresnahan(間違いなく今年こそ絶対にノーベル賞を取る)やRobert Porter(こいつも絶対にとる)らが構造推定の導入を進めていた。これは1970年代以前のSCPパラダイムと呼ばれる暗黒の時代を超克するための必然であった。SCPパラダイムでは、あらゆる業界(鉄鋼、自動車、食品など)のデータをごちゃ混ぜにした「業界横断クロスセクションデータ」を使い、「市場集中度(HHIなど)が高い業界ほど、利益率(成果)が高い」といったマクロな相関関係を普通の最小二乗法(OLS)で回帰していた。これらの分析はまさにHaavelmoが、またその後にLucasが指摘したような問題、特に「因果関係が逆(有能な企業が成長したから集中度が高まった)ではないか?」という内生性の問題に全く答えられず、分野ごと崩壊した。BresnahanやPorterはHaavelmo流の構造推定を持ち込んで、ゲーム理論に基づくモデリングで答えようとしていた。

しかし、彼らのアプローチには限界があった。特に有名なのは財多すぎ問題である。詳しくは次回以降述べていくが、差別化された財が多い時(例えばトヨタ・プリウス、日産・ノート、ホンダ・フィットなど、多種多様な車種)に需要関数をいい感じに実行可能な時間と計算資源で推定することが障壁となっていた。

ここで登場するのがAriel Pakes(こいつは絶対に絶対にノーベル賞をとる)とSteven Berry(こいつもおそらく一緒にノーベル賞を取る)である。UW-Madison最強の時代(この時期UW-MadisonにはJohn Rust, Charles Manski, Gary Chamberlainなどもいたらしい。ついでの我らがNobu Kiyotakiもいた。)に指導教官と指導学生だったこの二人によって現代的な需要推定(demand estimation)は完成される。彼らはDaniel MsFaddenの離散選択モデルをBresnahan流の実証IOにおける構造推定に持ち込んだ。これによって差別化財の需要推定が可能になり、需要関数というシステムの一部を固定して他の要素(例えば価格)を動かしたときに、どのような需要が実現するかをシミュレートする、という反実仮想がかなりいろんな場所でできるようになった。

ということで、パラダイム崩壊に苦しんでいた産業組織論が自らを超克するために構造推定を取り入れて、見事使えるものに昇華させた。これ以降構造推定といえば実証産業組織論、実証産業組織論といえば構造推定、というような感じになる。今や産業組織論の問題関心から外れ、実証産業組織論は構造推定のツールボックス的な立ち位置にある。そのツールは実際、労働経済学、環境経済学、実験経済学、などなど多くの他分野に輸出されている。

一方で誘導形の分析では今風に言えば因果推論が最終目的である。因果推論の目的は「もしこうしていたらどうなっていたか」を知ることなので、一見シミュレーションじゃん!という気もするが、そうではない。こちらの流派では変化に対して不変なパーツまで還元してから一部を変えるなんていうまどろっこしいことはしない。というか、そんなことはできない!という立場と言える。そうではなく、「もしこうなっていたら」という時のデータが欠損していると考え、データの欠損をなんとかして埋めることで、「もしこうしていたらどうなっていたか」を知るというアプローチをとる。それは純粋に統計的な問題、識別のための仮定の話であり、モデルのパーツとかそういう話は出てこない。Joshua Angrist, David Card, そしてAlan Kruegerといった労働経済学者たち、またAbhijit BanerjeeとEsther Dufloなどの開発経済学者たちによる因果推論の経済学への導入が1990年代から始まる。大規模なRCTやキャッチーなIVの利用というとっつきやすさも相まって、2010年代ぐらいは完全に彼らの流派が主流という感じだった。こちらの歴史は池上より詳しい人がいそうなのでその辺りの人に聞いてみましょう。

とにかく、この7,80年間、計量経済学はこの2つの流派が入り乱れて発展してきた。現在研究の最前線にいる人々はどっちの流派だ〜とかはあんまり気にしてないと思う。実際このレクチャーでも、構造推定を基本的には教えるが、誘導系のPotential outcomeのアプローチ、というか発想は普通に有益なのでその言葉を使うこともある。逆もまた然りで、もはや回帰分析一発!という論文は少なくなり、何らかのモデルを念頭においた反実仮想が多くの論文で求められ出している。こういった構造推定の受容を踏まえて、池上はシミュレーションこそが計量経済学の最終目標だと言っている。

余談、というか自分があんまり知らないので深いことは言えないのだが、この誘導系と構造推定の対立は、より広い分野である統計的因果推論における、Rubin流とPearl流の対立とalignする。Angristたちが導入した因果推論が紛れもなくRubinのpotential outcome approachであるし、Pearlは確かHaavelmoこそ我が起源みたいなことを言ってた気がする。の割に現代の経済学がやる構造推定における均衡制約などはPearlのDAG(因果ダイアグラム)でかきにくい、などの問題もあり別に構造推定の人たちが俺たちはPearl派だぜ!と言っているわけではないのだが。

先ほどから雑に反実仮想を「システムの一部を変えてシミュレーションする」というように書いているが、これはあんまり伝わない表現なため、Haavelmo自身による有名な説明を引用する。

反実仮想(Counterfactual)シミュレーションとは、「もし現実とは違う行動や政策をとっていたら、結果はどう変わっていたか?」をデータに基づいて予測する手法で、Haavelmoはこれを自動車の運転に例えて説明した。

  • 現実のデータ: ある人が車を運転しています。アクセルを踏み込む量(原因)と、車のスピード(結果)のデータを集めて散布図を書くと、そこには綺麗な関係(ここでは右上がりな関数)が見られます。
  • 構造の破壊(反実仮想): では、「もしこの車に重い荷物を積んで、急な坂道を登ったらどうなるか?」という未知のシミュレーション(反実仮想)をしたいとします。過去の平地での「アクセルとスピードのデータ」をそのまま当てはめても、正しい予測はできません。なぜなら、環境が変わることで、その表面的な関係性が崩れてしまうからです。つまり、先ほどの右上がりの関数は重い荷物を積んでいたらもう使えないということです。
  • Autonomy(自律性)の必要性: Haavelmoは、環境や政策が変わっても「壊れない不変的な関係性」 のことを Autonomy(自律性)と呼びました。自動車の例で言えば、アクセルと速度の表面的な関係ではなく、「エンジンの馬力」「車体の重量」「重力」といった物理法則レベルの『自律的な構造(Autonomous structure)』をデータから逆算して突き止めておく必要があります。

これこそが、彼が同時方程式モデルを提唱した理由です。システムの根底にあるAutonomy(自律性)を持つパラメータを正しく推定して初めて、「もし政策を変えたらどうなるか?」という反実仮想シミュレーションが可能になるのです。

1. 実証IOについてと授業の進み方、授業の聞き方

このコースが扱う内容は、いくつかの名前で呼ばれる。呼び方によって強調点が少し違うので整理しておこう。

  • 実証産業組織論(empirical industrial organization, empirical IO):企業の価格設定行動、製品差別化、参入・退出、合併といった市場構造を、需要と供給の構造モデルを使って分析する経済学の一分野。伝統的には独占禁止政策(合併審査など)との結びつきが強い。
  • quantitative marketing:マーケティングサイエンスの分野で、消費者の購買行動(ブランド選択、購入タイミング、数量選択)を統計・計量モデルで分析し、価格設定、広告、品揃え、顧客管理(CRM)といった企業のマーケティング施策に応用する。
  • 実証ビジネス・エコノミクス(empirical business economics):上記2つを包含しつつ、より広く「データを使って企業の意思決定を支援する」実務的な分析全般を指すことが多い言葉である。近年は多くの企業が経済学PhDホルダーを「データサイエンティスト」「エコノミスト」として採用しており、この講義で学ぶ内容はまさにその実務と直結している。

3つの分野は使う道具(離散選択モデル、最尤法、因果推論)を共有しており、明確な境界線があるわけではない。このコースでは言いやすいので大体は「実証IO」と呼ぶことが多いが、要するに「データを使って、企業や政策当局の意思決定に資する形で、需要・競争・顧客行動を分析する」分野だと思ってもらえばよい。

企業の意思決定を4つの問いに分解する

データ分析チームや政策当局が直面する意思決定は、突き詰めると次の4つの問いに集約できる。このコースの13回は、この4つの問いに対応する形で設計されている。

問い 具体例 対応する回
(a) 需要と代替性を知る この商品の価格を上げたら売上はどれくらい減る? 競合と自社製品はどれくらい代替的? 第2回(logit需要)、第3回(nested logit・IIA・価格内生性)、第4回(random coefficient logit・合併分析)
(b) 施策の因果効果を知る この広告キャンペーンは本当に売上を増やしたのか? この値下げの効果は? 第7回(コンジョイントの属性ランダム化)、第10回(施策の実験評価)
(c) 顧客の異質性と価値を知る どの顧客が優良顧客か? この顧客の生涯価値(CLV)はどれくらい? 第6回(個人の購買履歴)、第8〜9回(階層ベイズ)、第11回(BG/NBD・CLV)
(d) 最適に配分・価格付けする 誰に割引クーポンを配るべきか? いつ・いくらで値付けすべきか? 第10回(個人別需要とクーポン配布)、第13回(動学的離散選択)、第14回(state dependence)、第15回(dynamic pricing)

ゲスト講義で、実務の現場でこれらの問いがどう扱われているかを直接聞く回になる。

ノートビジネスの現場で:「この4つの問い、実際どう降ってくるか」

実務でデータ分析チームに来る依頼は、たいてい次のような形を取る。

  • 「新製品Xを出したら、既存製品YとZからどれくらい食われる(カニバリゼーション)か教えてほしい」→ (a) 需要と代替性
  • 「先月のテレビCM、本当に効果あったんですか? 感覚では『あった気がする』んですが」→ (b) 施策の因果効果
  • 「解約しそうな顧客を先に見つけて、リテンション施策を打ちたい」→ (c) 顧客の異質性
  • 「この夏のセールで、どの商品をどれだけ値下げすれば利益が最大になるか」→ (d) 最適化

依頼した本人は「これは需要分析です」「これは因果推論です」とラベル付けして持ってくるわけではない。曖昧な言葉で降ってきた依頼を、この4つの問いのどれに当たるかに翻訳する力こそが、実務で最初に鍛えられる勘所である。

実証IOの現代的な立ち位置

実証IOは企業行動、および消費者行動の分析である。その方法論は疑いようもなくこれらのトピックの分析のために作られてきた。

しかし、現代的にはその方法論の応用先は企業行動に限られるものではない。環境経済学、労働経済学、開発経済学、などなど、およそ実証IOが当初想定していた分析対象ではない場面でも実証IOの方法論は広く用いられるようになっている。

したがって、現代的な実証IOは、その分析対象を指す言葉というよりは、経済モデルとデータを使って何かを主張するときによって立つ統合的な分析ツールボックスを指す言葉としての側面の方が強い。このツールを知って、自分の好きな分野の分析をする、みたいな使われ方をしている。

この授業でも基本的には企業行動や消費者行動についての話をしていく。ただ、池上自身の研究関心もこういった古典的なIOのトピックとはちょっとずれているし、受講者の皆さんもあくまでもツールを理解する上でのexampleと思って企業行動や消費者行動の話を聞いてほしい。「自分の関心のある分野だったらこの話はこういうふうに使えそうだな〜」と考えながらこれらの例を理解していければベストだと思う。

2. 実証研究の3ステップとシミュレーションの使い方

計量経済学Iを貫いていた枠組みをもう一度確認しておこう。

  • モデルとは「観測変数の条件付き分布の束」であった。
  • 「モデルを条件付き分布として書き下せれば、コンピュータの中でそのモデルに従うデータを生成(シミュレーション)できる」というのが計量Iで繰り返してきたポイントで、これによってシミュレーションができれば、推定量が真値を回収できるかを実験で確かめられるし、標準誤差の妥当性などもモンテカルロで検証してきた。
  • そしてこの「モデル」を念頭に置いて、実証分析は次の3ステップで進む。
    1. 識別(identification):無限にデータがあれば、知りたいモデルのパラメータや効果は一意に定まるか。定まるための仮定は何か。
    2. 推定(estimation):手元の有限データから、そのパラメータの値をどう計算するか。
    3. 推論(inference):推定値には誤差がある。その誤差の大きさをどう測り、どこまで確信を持って良いかをどう表現するか。

計量経済学IIでもこの枠組みは変わらない。ただし、シミュレーションの使い道が一段階進む。計量Iでは主に「推定量の性質を確認するための道具」としてシミュレーションを使ってきたが、このコースでは意思決定のための「いいシミュレーション」を作ることを目指す。これが、構造推定を学ぶ根本的なモチベーションである。

ここでいうシミュレーションは、モデルを使って、指定した状況の下で何が起こるかを計算することだと思ってほしい。モデルに従って乱数を発生させる場合もあれば、平均や変化率を数式から直接計算できる場合もある。「来月の売上はどうなるか」という通常の予測にもシミュレーションは使う。

では、どんなシミュレーションなら「いい」のか。知りたい世界の結果を、適切な根拠に基づいて予測できるものである。このコースで特に知りたいのは、「もし価格を10%上げたら」「もしこの2社が合併したら」「もし本部の広告配分ルールを変えたら」という、企業や政策当局が意思決定を変えた世界である。

従来の仕組みが続く世界で予測がよく当たることは、そのための十分条件ではない。意思決定の変更によって、データの中で見えていた関係そのものが変わることがあるからだ。したがって、何を変え、何が変わらないと考えるかをモデルに書き、変更後にも使えるパラメータをデータから推定する。これが構造推定と、それに基づく反実仮想シミュレーションの出発点になる。

以下の広告費の例では、「旧制度の予測としては優秀なのに、制度を変えた世界のシミュレーションには失敗する」という状況を見ていく。さらに、旧制度の予測関数を無限のデータで完全に学べたとしても、この失敗が残ることを確かめよう。

3. Rシミュレーション1:広告費と売上の罠

あなたはある小売チェーンのデータサイエンティストである。 今月の仕事は、店舗ごとの月間広告費と月間売上のデータを分析して、広告費を2倍にしたら月間売上がどれくらい増えそうかを計算することである。このレポートは社長が直接チェックして、実際の経営判断に使われる。間違ったことは言えない。

あなたはデータ基盤課と協力して店舗ごとの月間広告費と月間売上のデータを作成した。そして素朴に散布図を描いて回帰直線を引くと、

広告費が多い店ほど売上が高い

という綺麗な右上がりの関係が見えたとしよう。

例えば以下のようなものである。横軸は広告費、縦軸は売上の対数である。以下では、同じ300店舗を3か月にわたって追う。

1か月目:広告費と売上(log)の散布図とOLS回帰直線

ここから「広告費を増やせば売上が増える」と結論に飛びついていいものだろうか?また、その分析をもとに、広告費を2倍にした効果をレポートして良いだろうか。

ノート「AなほどB」という言葉について

ここで池上は「広告費が多い店ほど売上が高い」という日本語には一切の因果関係を含めていないつもりである。あくまでも広告費と売り上げに正の相関がある、という意味で使っている。

しかし、山口慎太郎教授の散布図がXで燃えたとき、「AなほどB」とかくと、AがBに対して因果的な効果をもたらす、というように読んでしまう層がいるという気づきを得た。

確かにそう言われるとその感覚もわからないのではないが、「相関」という専門用語を使わずにどのようにして「AとBに正の相関関係がある」という意味内容を書けばいいのか、池上はわからない。

いい案があれば求む。

モデルの検証

あなたは慎重な人間だ。何事も石橋は叩いて渡る派の人間である。

なのでここで安易にこの回帰分析の結果を信頼するようなことはしない。まずはこのモデルのフィットを検証しようと考えた。in-sampleでのフィットの良さである決定係数は 0.77 とそんなに低くない(そもそもぱっと見でよくフィットしてる)ので、out-of-sampleのフィットも確かめてみることにした。つまりこのモデルがちゃんと売上を「予測」できれば、このモデルを信じてもいい気がするというわけである。

具体的には、レポートの報告を1か月遅らせてもらう。今手元にある1か月目のデータでモデルを推定し、すでに決まっている2か月目の広告予算を入れて、同じ300店舗の「来月」の売上を予測する。そして、翌月に新しく届いた売上データと比べてみよう、という算段である。翌月のデータでモデルを推定し直すことはしない。

実際にやってみた結果、予測と実現値を比べる以下の散布図を得た。

2か月目:通常の広告配分が続く月には、予測値と実現値はおおむね45度線付近に並ぶ

悪くない。大体45度線上にきていて、もちろん完全に予測できてるわけじゃないが、大はずしもしてないようである。

これをもってついに石橋を叩いて渡り切ったあなたは、広告費を2倍にした時の売上増加分を以下のように計算し、レポートすることとなった。

推定した回帰式は、店舗 \(i\) の広告費を \(a_i\)(万円/月)として、

\[ \widehat{\log(\text{sales}_i)}=\hat\beta_0+\hat\beta_{\mathrm{ad}}a_i, \qquad \hat\beta_0=3.971,\quad \hat\beta_{\mathrm{ad}}=0.01215 \]

である。3か月目は2か月目と同じ予算を続ける予定だったので、それを \(a_i\) として、\(a_i\) を入れた予測と \(2a_i\) を入れた予測の差を取る。

\[ \widehat{\Delta\log(\text{sales}_i)} =(\hat\beta_0+\hat\beta_{\mathrm{ad}}\,2a_i) -(\hat\beta_0+\hat\beta_{\mathrm{ad}}a_i) =\hat\beta_{\mathrm{ad}}a_i. \]

対数の差を売上の変化率に直すと、\(100\{\exp(\hat\beta_{\mathrm{ad}}a_i)-1\}\%\) である。例えば広告費100万円の店舗なら、200万円に増やしたときの売上増加率は 237.1%。全300店舗について計算して平均すると、「広告費を2倍にすると、店舗別の売上は平均 260.1% 増える」というレポートになる。

現実

さて、めでたくあなたのレポートは承認され、その売上増加を見込んで広告費の倍増が決定され、3か月目に実行された。その月の売上が店舗ごとに集計され、あなたのモデルとの比較のために予測値との散布図が作成された。その結果が以下の通りである。

3か月目:広告費を2倍にすると、実現した売上は予測を大きく下回る。前の図と軸の範囲は同じ

全然ダメである。点は45度線よりもずっと下にあり、売上を過大予測している。「店舗別の売上は平均 260.1% 増える」とレポートされていたのに、実際に観測された前月比の増加率は平均 27% にとどまった。介入後の売上予測は大きく外れたということである。

この問題に気づいた社員はあなたになぜこんなことになったのかを問い詰めようとするだろう。しかしあなたは先ほどのレポートを提出した功績でめでたく栄転。気軽に話を聞けなくなってしまい、社員は途方に暮れることとなる。

ノートやりっぱなし分析について

民間企業でこういうことはあまりないかもしれないが、こういうやりっぱなし分析は官僚の世界では多々あるらしい。2年ごとぐらいにジョブをくるくるしているので、分析の妥当性を検証するタイミングでは本人は全く関係ない部署にいて、そのパフォーマンスについてはどこ吹く風、という感じである。

じゃあ責任をどこまでも追求しろということではないのだが、それではデータ分析なんて最初からやらないでいいのでは…?データ分析の妥当性をどのように検証して、それを社内でどのように有機的に活かすか(例えば人事評価などに)は気になるトピック。みなさんどのようにしてますか??

なぜこんなことが起きたか:予測と介入、2つのシミュレーション

問題点をクリアにするために、ここまでのデータを作ったDGP(データ生成過程)を種明かししよう。以下のような状況をシミュレートしていた。

  • もともと立地が良く接客力もある「地力の強い店舗」ほど、本部が広告予算を多めに配分する。

地力が強い店舗は、広告を出そうが出すまいが売上が高い。つまり地力(quality)という観測されない変数が、広告費と売上の両方に影響を与えている。

まず、1か月目のモデルを数式で書いておこう。店舗 \(i\) の地力を \(Q_i\)、広告費を \(A_i\)(万円/月)、売上を \(S_i\)、対数売上を \(L_i=\log S_i\) とする。地力と2種類のノイズを

\[ Q_i\sim N(0,1),\qquad V_i\sim N(0,15^2),\qquad U_i\sim N(0,0.15^2) \]

から発生させる。\(Q_i,V_i,U_i\) は互いに独立で、店舗間でも独立とする。\(V_i\) は本部の広告配分のばらつき、\(U_i\) は売上のノイズである。その上で、広告費と売上を

\[ \begin{aligned} A_i&=\max\{100+30Q_i+V_i,\;10\},\\ L_i&=5+0.4Q_i+0.002A_i+U_i,\\ S_i&=\exp(L_i) \end{aligned} \]

によって決める。これが、この例の真のモデル(DGP)である。

最初の式では、地力が高い店舗ほど広告費が多く配分され、広告費の下限は10万円になっている。次の式では、広告費も地力も売上を押し上げる。つまり、\(Q_i\) が広告費と売上の両方に入っていることが、交絡の源泉である。地力を固定して広告費だけを1万円増やしたときの対数売上の変化は、\(0.002\) である。

分析担当者が最初に見ていたのは \(A_i\) と \(S_i\) だけで、\(Q_i\) は見えていなかった。しかし、データを作った私たちは、この仕組みを知っている。この違いを念頭に置いてコードを見ていこう。

1か月目のデータを作ったコードは次の通りである。ここでは分析担当者には見えていなかったqualityも表示している。

n_stores <- 300

# 店舗の地力(立地・接客力など)。同じ店舗の地力は3か月間変わらない
quality <- rnorm(n_stores, mean = 0, sd = 1)

# 1か月目の広告費(万円/月):地力が高い店ほど多く配分される
ad_spend <- 100 + 30 * quality + rnorm(n_stores, mean = 0, sd = 15)
ad_spend <- pmax(ad_spend, 10)

# 真の広告効果は小さく、地力の効果は大きい
true_beta_ad <- 0.002
true_beta_quality <- 0.4
log_sales_mean <- 5.0 + true_beta_quality * quality + true_beta_ad * ad_spend
log_sales <- log_sales_mean + rnorm(n_stores, mean = 0, sd = 0.15)

store_df <- data.frame(
  store_id = 1:n_stores,
  quality = quality,
  ad_spend = ad_spend,
  sales = exp(log_sales),
  log_sales = log_sales
)
head(store_df)
  store_id    quality  ad_spend     sales log_sales
1        1  1.0972203 158.32229 327.77992  5.792342
2        2  1.1241860 126.36172 215.34060  5.372221
3        3  0.6843835 120.59105 221.17181  5.398940
4        4 -1.9351903  20.35547  73.25654  4.293968
5        5 -1.9368942  10.00000  65.86206  4.187563
6        6  0.8246515 151.59929 278.07868  5.627904

予測というシミュレーション

先ほどの右上がりの回帰直線には、広告自体の効果だけでなく、店舗の地力の差も入り込んでいたのである。広告費だけを説明変数にしたOLS(地力を見ない「素朴な」分析)と、地力も入れたOLSを比較してみる。

fit_short <- lm(log_sales ~ ad_spend, data = store_df)
fit_long  <- lm(log_sales ~ ad_spend + quality, data = store_df)

beta_short <- unname(coef(fit_short)["ad_spend"])
beta_long  <- unname(coef(fit_long)["ad_spend"])
comparison_df <- data.frame(
  model = c("素朴なOLS(広告費のみ)", "地力を調整したOLS", "真の値"),
  beta_ad = c(beta_short, beta_long, true_beta_ad)
)
knitr::kable(comparison_df, digits = 5,
             col.names = c("モデル", "広告費の係数"))
モデル 広告費の係数
素朴なOLS(広告費のみ) 0.01215
地力を調整したOLS 0.00225
真の値 0.00200

素朴なOLSでは広告費の係数が真の値よりもかなり大きく出る。地力という交絡因子を無視した結果、広告費が地力の効果まで「代わりに」拾ってしまっているからだ。地力をコントロールした回帰では、係数は真の値にかなり近づく。

計量Iの復習がてら数式で書くと、真の式を

\[ \log(\text{sales})=\beta_0+\beta_{\mathrm{ad}}\,\text{ad}+\beta_q\,\text{quality}+u, \qquad E[u\mid\text{ad},\text{quality}]=0 \]

と書けば、qualityを落とした単回帰の係数は、大標本では

\[ \operatorname{plim}\hat\beta_{\mathrm{ad}}^{\mathrm{short}} =\beta_{\mathrm{ad}}+\beta_q\frac{\operatorname{Cov}(\text{ad},\text{quality})}{\operatorname{Var}(\text{ad})} \]

に近づく。このDGPでは \(\beta_q>0\) かつ \(\operatorname{Cov}(\text{ad},\text{quality})>0\) なので、欠落変数バイアスは上向きになる。散布図や推定結果は、この符号予想と整合的である。

この素朴なモデルは、「来月の売上を予測する」というタスクには実はよく機能する。なぜなら、地力の強い店舗には広告費も多く配られるという関係が、本部の予算配分方針が変わらない限り続くからだ。広告費という変数は「地力の強さのシグナル」として機能し、予測の役には立つ。

地力を見ずに広告費だけに回帰した場合を考える。つまり、

\[ L_i = a + b A_i + \epsilon_i \]

のような回帰である。

こういう回帰を見たらまず考えるのは売り上げの広告費についての条件付き期待値である。

\[ E[L_i\mid A_i=a]=5+0.002a+0.4E[Q_i\mid A_i=a] \]

これは「広告費から読み取れる地力」(\(E[Q_i\mid A_i=a]\))の効果も含んでいる。一般には、この条件付き期待値が広告費の線形関数になるとは限らない。実際今のモデルでは広告費 \(A\) と地力 \(Q\) はmax operatorを介して繋がるので線形な関係ではない。

それでも先の線形回帰には、最良線形予測(best linear prediction)という性質がある。

母集団で最良の直線の係数を、

\[ (b_0^*,b_A^*) =\arg\min_{b_0,b_A}E[(L_i-b_0-b_A A_i)^2] \]

と定義する。これは、切片と広告費だけからなる直線で予測する、という制限の中で、平均二乗誤差を最小にする係数である。2次モーメントが有限で \(\operatorname{Var}(A_i)>0\) なら、

\[ b_A^*=\frac{\operatorname{Cov}(A_i,L_i)}{\operatorname{Var}(A_i)},\qquad b_0^*=E[L_i]-b_A^*E[A_i] \]

となる。標本のOLSは期待値を標本平均に置き換えて計算するもので、独立同分布の標本を増やすと、その係数はこの母集団の最良線形予測の係数に近づく。なので、たとえ真の関係性に \(E[Q_i\mid A_i=a]\) のような非線形かも知れない項が入っていても、linear regressionすれば大体OKという感じである。

この例では、広告費が地力のシグナルになるので、地力の効果を拾うことは従来の運用の下での予測には役立つ。上の欠落変数バイアスの式は、「広告費の因果効果」を知りたいときのずれを表しているが、その係数が「広告費だけを使った予測」にとって悪いという意味ではない。

2か月目のデータも、次のコードで作っていた。2か月目には同じ店舗の地力を保ち、本部の通常の配分ルールで広告予算を新しく決め、売上にも新しい月のノイズを加える。

# 2か月目:同じ店舗に、従来のルールで来月の広告予算が配分される
# この予算は、来月の売上が実現する前に決まっている
next_ad_spend <- pmax(
  100 + 30 * quality + rnorm(n_stores, mean = 0, sd = 15), 10
)
next_log_sales <- 5.0 + true_beta_quality * quality +
  true_beta_ad * next_ad_spend + rnorm(n_stores, mean = 0, sd = 0.15)
next_month_df <- data.frame(
  store_id = store_df$store_id,
  quality = quality,
  ad_spend = next_ad_spend,
  log_sales = next_log_sales,
  sales = exp(next_log_sales)
)

先ほどの「モデルの検証」を計算で再現してみよう。1か月目で推定済みの fit_short に、翌月の広告予算を入れる。翌月に届く売上は、予測の答え合わせにだけ使う。

pred_next <- predict(fit_short, newdata = next_month_df)

# 2か月目の実現値で予測精度を評価する(売上はすべてlog)
ss_res <- sum((next_month_df$log_sales - pred_next)^2)
ss_tot <- sum((next_month_df$log_sales - mean(next_month_df$log_sales))^2)
r2_next <- 1 - ss_res / ss_tot

# ベースライン:1か月目の平均売上(log)だけで予測する
baseline_pred <- rep(mean(store_df$log_sales), nrow(next_month_df))
r2_base <- 1 - sum((next_month_df$log_sales - baseline_pred)^2) / ss_tot

knitr::kable(
  data.frame(method = c("広告費を使う予測モデル", "平均だけのベースライン"),
             next_month_R2 = c(r2_next, r2_base)),
  digits = 3, col.names = c("予測方法", "翌月データでのR²")
)
予測方法 翌月データでのR²
広告費を使う予測モデル 0.752
平均だけのベースライン 0.000

広告費を使うモデルの翌月R²は 0.752 で、平均だけの予測よりずっと当てはまりが良い。データは新しくなっているが、広告費が地力のシグナルになる仕組みは続いているのである。したがって、これは確かにout-of-sampleの予測検証になっている。

ただし、従来の運用が続く月の予測を検証したのであって、広告費を倍増させた世界を検証したわけではない。

介入というシミュレーション

ここから介入という新しいシミュレーションの設定に入る。

広告費を \(A\)、地力を \(Q\)、対数売上を \(L\) と書く。広告費の配分倍率を表すパラメータ \(\lambda\) を導入すると、先ほどのDGPは次のように書ける。

\[ \begin{aligned} A_\lambda&=\lambda\max(100+30Q+V,\;10), &&\text{広告費を配るルール},\\ L_\lambda&=5+0.4Q+0.002A_\lambda+U, &&\text{売上が決まる仕組み}. \end{aligned} \]

ここで \(Q\sim N(0,1)\)、\(V\sim N(0,15^2)\)、\(U\sim N(0,0.15^2)\) は互いに独立である。\(V\) は広告配分のばらつき、\(U\) は売上のノイズを表す。下付きの \(\lambda\) は月ではなく、広告配分のルールを区別する記号である。

通常の配分は \(\lambda=1\)。広告費倍増は \(\lambda=2\) への変更であり、

\[ A_2=2A_1=\max(200+60Q+2V,\;20) \]

となる。地力にかかる係数だけでなく、切片・ノイズの尺度・下限も倍にする政策である。一方、店舗の地力と、売上を決める式の係数は変えない。何を変えて、何を固定するかが、これで明確になった。

従来のルールの下で、広告費だけを使って対数売上を予測するとしよう。二乗誤差を最小にする予測関数は、条件付き期待値

\[ \begin{aligned} m_1(a)&\equiv E[L_1\mid A_1=a]\\ &=5+0.002a+0.4E[Q\mid A_1=a] \end{aligned} \]

である。広告費が \(a\) の店舗は、平均的にはどのくらい地力があるか。それも使って売上を予測している。

では、広告費を倍増した制度で、広告費が \(a\) の店舗の売上はどうなるか。\(A_2=a\) になるのは、もともと \(A_1=a/2\) だった店舗なので、

\[ \begin{aligned} m_2(a)&\equiv E[L_2\mid A_2=a]\\ &=5+0.002a+0.4E[Q\mid A_1=a/2] \end{aligned} \]

となる。同じ \(a\) を入れているが、地力について平均を取っている店舗の集団が違う。もともと広告費200万円の店舗と、100万円から200万円に増やされた店舗は、同じ200万円でも地力が違うのである。

この違いを図で見よう。ここからの2本の線は、300店舗から推定した回帰直線ではなく、DGPから直接計算した母集団の条件付き平均そのものである。つまり、「データ不足や推定誤差がなくなって、旧制度の最良の予測関数を完全に学べた」ところまで考えている。

図 1: 旧制度の最良の予測関数m1と、広告費倍増後に必要な関数m2。青い線を完全に学べても、AからCへの変化は青い線に沿って移動することでは計算できない。

図の3点は、次のように読む。数値はすべて対数売上の条件付き平均である。

点 どの店舗の、どの世界の売上か 広告費 対数売上の平均
A 従来のルールで100万円を配分されている店舗 100万円 5.20
B 従来のルールでもともと200万円を配分されている店舗 200万円 6.47
C Aの店舗集団の広告費だけを200万円に増やした場合 200万円 5.40

旧制度の予測関数をそのまま使うと、Aから青い線に沿ってBへ進んでしまう。だが、シミュレーションしたかったのはAの店舗の広告費を倍にすることであり、正しい行き先はCである。AからCへの変化は、地力を固定した広告費の効果 \(0.002\times100=0.20\)。同じ広告費200万円でのBとCの縦の差は、政策後の予測のずれであり、同じ店舗への広告費倍増の効果ではない。

「でも、100万円も200万円も旧制度で生じ得る。無限にデータがあれば、どちらの額についても予測できるのでは?」と思うかもしれない。確かに、どちらも従来制度の支持域内である。しかし、それによってわかるのは青い線上のAとBであって、オレンジの線上のCではない。旧制度でも生じる広告額なのに、その広告額がどのような仕組みで決まったかによって、予測する関数自体が変わる。

このDGPでは、下限の影響を受けない \(a>20\) について、正規分布の条件付き平均の公式から

\[ E[Q\mid A_\lambda=a] =\frac{30}{30^2+15^2}\left(\frac{a}{\lambda}-100\right) \]

となる。これを売上の式に代入すると、

\[ \begin{aligned} m_1(a)&=3.93333\ldots+0.012666\ldots\,a,\\ m_2(a)&=3.93333\ldots+0.007333\ldots\,a. \end{aligned} \]

図ではこの2つの関数を描いている。これは母集団の条件付き平均なので、個々の店舗の売上はそれぞれの地力やノイズによって線の周りにばらつく。無限にデータがあっても、個別店舗の予測誤差がゼロになるという話ではない。

さらに、値が生じ得る範囲を意味する支持域(support)で考えると、従来の広告費は \([10,\infty)\)、倍増後は \([20,\infty)\) にある。つまり、介入後の広告額はすべて元の支持域にも含まれる。有限の標本で見た最大広告額を超えることはあっても、この例の失敗は「支持域外の広告額を予測したから」だけでは説明できない。

ここはもう一段、丁寧に確認しておこう。従来制度で広告費が \(a/2\) の店舗の対数売上の平均、すなわち \(m_1(a/2)\) は、データから学べる。 そこについて何もわからないわけではない。

足りないのは、その店舗集団の広告費だけを \(a/2\) から \(a\) に増やしたときの上乗せである。真のモデルでは、

\[ \underbrace{m_2(a)}_{\text{新制度の対数売上の平均}} = \underbrace{m_1(a/2)}_{\text{旧制度の対数売上の平均}} + \underbrace{\beta_{\mathrm{ad}}\frac a2}_{\text{広告費だけを増やした効果}}, \qquad \beta_{\mathrm{ad}}=0.002. \]

AからCへ進むには、この最後の因果効果が必要になる。青い線上でAからBへ進むと、広告費の効果に加えて、地力が高い店舗への入れ替わりまで含めてしまう。

旧制度で売上をよく当てるように学習することと、この上乗せを正しく求めることは、同じではない。 旧制度の予測精度だけでは、広告費の因果効果の大きさや、それが制度変更後にも使えることは保証されない。実験、適切な交絡調整、あるいは追加の識別仮定などによって、介入後にも使える関係を取り出す必要がある。

重要汎化性能がよくても、目的に対して「悪いシミュレーション」になり得る

機械学習的な予測で、従来と同じ配分ルールの下の新しい店舗・新しい月でも売上を当てられるようにすることを考えよう。この意味での汎化性能を高め、無限のデータで \(m_1\) を完全に学べたとしても、それをそのまま広告費倍増後に使うとBを答えてしまう。求められている答えはCである。

旧制度の売上予測としては最良でも、意思決定で知りたい制度変更後の世界を計算するという目的には、悪いシミュレーションになっている。学習方法を高度にしたり、同じ制度のデータを増やしたりするだけでは、この予測対象の違いは埋まらない。

この講義で目指す「いいシミュレーション」は、何を変更した世界を計算したいのかに合わせて、変更後にも使える関係を識別・推定し、その世界を計算することである。機械学習もその推定に使える。問題は手法の名前ではなく、何を学び、それをどの世界の予測に使っているかである。

ここで、冒頭の「現実」で見た3か月目のデータを作るコードを見てみよう。2か月目の広告予算を据え置く予定だったところ、全店でその2倍にする。店舗の地力と売上の決まり方はそのままで、3か月目には新しい売上ショックが発生する。

# 3か月目:2か月目の広告予算を据え置く予定だったところ、全店で2倍にする
# 売上ショックは新しく発生する。地力や売上の決まり方は変わらない
intervention_noise <- rnorm(n_stores, mean = 0, sd = 0.15)
intervention_df <- next_month_df
intervention_df$ad_spend <- 2 * next_month_df$ad_spend
intervention_df$log_sales <- 5.0 + true_beta_quality * quality +
  true_beta_ad * intervention_df$ad_spend + intervention_noise
intervention_df$sales <- exp(intervention_df$log_sales)

次に、この3か月目について「予算を据え置いた世界」と「広告費を2倍にした世界」を作り、比べる。同じ店舗の地力と、同じ月の売上ショックを固定して、広告費だけを入れ替えるのがポイントである。\(a_i\) を据え置いた場合の予算、\(q_i\) を地力、\(u_{i3}\) を3か月目のショックとすると、真のモデルでは

\[ \begin{aligned} \log(\text{sales}_{i3}^{\mathrm{据え置き}})&=5+0.4q_i+0.002a_i+u_{i3},\\ \log(\text{sales}_{i3}^{\mathrm{倍増}})&=5+0.4q_i+0.002(2a_i)+u_{i3}. \end{aligned} \]

この2つの差は \(0.002a_i\) であり、売上の増加率は \(100\{\exp(0.002a_i)-1\}\%\) となる。広告費100万円の店舗なら、真の効果は約 22.1% である。

つまり今回は、効果を計算するために新しく乱数を振ってシミュレーションを繰り返す必要はない。同じ \(q_i\) と \(u_{i3}\) は引き算で消えるので、数式に広告費を代入するだけでよい。冒頭の図を作るには各月の実現値をシミュレートしたが、この単純なモデルの反実仮想効果は直接計算できるのである。

いいシミュレーションのために、何を推定するか

では、どうすればよかったのか?qualityの変数も新たに手に入れられれば最高である。

このDGPなら、qualityと広告費の2つに回帰することで、より真の値に近いパラメータの推定値をゲットすることができる。上で推定した fit_long がそれである。

これを元に、qualityを元の値に保ったまま、広告費だけを2倍にするという計算をしてみよう。

# qualityは変えず、広告費だけが異なる2つのデータをモデルに渡す
adjusted_effect <- predict(fit_long, newdata = intervention_df) -
  predict(fit_long, newdata = next_month_df)
adjusted_mean_pct <- mean(exp(adjusted_effect) - 1) * 100

effect_summary <- data.frame(
  method = c("真の効果", "素朴なOLS", "地力を調整したOLS"),
  mean_pct_change = c(true_mean_pct, ols_mean_pct, adjusted_mean_pct)
)
knitr::kable(effect_summary, digits = 1,
             col.names = c("計算方法", "店舗別の売上増加率の平均(%)"))
計算方法 店舗別の売上増加率の平均(%)
真の効果 22.1
素朴なOLS 260.1
地力を調整したOLS 25.2

広告費2倍の効果を同じ尺度で比較する。地力を調整すると真の効果に近づく

地力を調整したモデルの予測は 25.2% の増加で、真の効果 22.1% に近い。単に予測の当てはまりを良くするだけでなく、広告費を変えたときに何が変わり、何が変わらないのかをモデルに組み込んだからである。

もちろん、現実にはqualityがそのまま手に入るとは限らないし、何か変数を追加すれば必ず解決するわけでもない。この例では、qualityを調整した後に広告費と売上のノイズが独立であり、介入後も売上の決まり方が変わらない、というDGPの仮定が効いている。このような仮定を吟味して、意思決定の変更後にも使える関係を識別・推定する。構造推定を学ぶ目的は、こうして知りたい世界の「いいシミュレーション」を作れるようになることである。

4. Rシミュレーション2:需要を推定して、値付けを提案する

さて、めでたく栄転したあなたは、今度はある店舗の主力商品について来期の予算を考えることになった。というのも、仕入先から連絡があり、この商品の仕入費用が来期から1個500円から650円に上がることになったのだ。

あなたの上司は、この店の店長である。毎週の販売価格を決めるのも、この店長だ。その店長から、次のような依頼が来た。

仕入れが高くなるので、値付けを見直したい。販売記録や価格実験のデータを使って、粗利益をできるだけ確保できる値付けを提案してほしい。その値付けで来期13週間をシミュレーションして、販売数量、売上、粗利益がどうなりそうかも報告してほしい。四半期の粗利益が250万円を下回る確率も知りたい。

ここでいう粗利益は、売上から仕入費用を引いたものだ。人件費や家賃を引いた最終的な利益ではない。

この店では、その週が暇になりそうか、普通か、忙しくなりそうかを週初に判断し、それを見てから価格を決めている。あなたの仕事は、この見通しごとにどんな価格にすればよいかを店長に提案することである。店長がその提案を採用したら、来期の業績はどうなりそうか。平均だけでなく、下振れの可能性まで計算する。

手元のデータ

価格を変えたら何個売れるのか、その関係をデータから推定するところから始める必要がある。

データ基盤課から、次の2つのデータを受け取った。

  • 価格実験のデータ:対象店舗を含む同種店舗で集めた600件の「店舗×週」の記録。価格決定前の需要の見通し、無作為に割り当てた価格、販売数量が入っている。暇・普通・忙しい週をそれぞれ200件ずつ集めている。
  • 対象店舗の通常営業の記録:過去208週について、週初にどの需要の見通しだったかを記録したもの。

「忙しい週」は、売れた後に販売数量を見て付けたラベルではない。価格を決める前にわかっていた見通しである。

たとえば、価格実験のデータの一部は次のようになっている。low、normal、high がそれぞれ暇・普通・忙しい週を表す。

knitr::kable(head(experiment_df), digits = 1,
             col.names = c("需要の見通し", "実験で割り当てた価格(円)", "販売数量"))
需要の見通し 実験で割り当てた価格(円) 販売数量
low 800 636.1
low 900 300.6
low 1300 73.8
low 850 514.5
low 1450 59.8
low 1550 49.9

普段の価格は、暇な週に700円、普通の週に850円、忙しい週に1,000円である。

あなたは同じ需要の見通しの中で価格を無作為に変えた実験を使って、価格への反応を推定することを考えた。

需要関数を推定する

需要の見通しを \(S\in\{\text{暇},\text{普通},\text{忙しい}\}\)、価格を \(p\)、販売数量を \(q\) とする。次の需要モデルを置こう。

\[ \log q=\alpha_S-\eta_S\log(p/1000)+\varepsilon, \qquad \varepsilon\sim N(0,\sigma^2). \]

\(\alpha_S\) は需要の水準、\(\eta_S\) は価格への反応の強さを表すパラメータで、どちらもまだわかっていない。見通しごとに別の値を認める。\(\eta_S>0\) なら価格が上がると需要は減り、このモデルの価格弾力性は \(-\eta_S\) である。\(p/1000\) とするのは、1,000円を基準にして式を読みやすくするためだ。

\(\varepsilon\) は価格決定後に実現する需要のぶれであり、その大きさを表す \(\sigma\) もデータから推定する。実験では、見通しを条件に価格が \(\varepsilon\) と独立に割り当てられる。この設定の下で、価格の係数を因果的な需要反応として推定できる。なぜなら実験だからである。正規分布・共通の分散という部分は、業績の分布まで計算するために追加するモデルの仮定である。

まずは計量Iで使ったOLSで推定する。状態別の切片と、状態別の価格の係数を入れればよい。

experiment_df$log_q <- log(experiment_df$quantity)
experiment_df$log_price_ratio <- log(experiment_df$price / 1000)

# 0 + stateで状態別の切片、state:log_price_ratioで状態別の傾きを入れる
fit_demand <- lm(log_q ~ 0 + state + state:log_price_ratio,
                 data = experiment_df)
alpha_hat <- unname(coef(fit_demand)[paste0("state", state_levels)])
eta_hat <- -unname(coef(fit_demand)[paste0("state", state_levels, ":log_price_ratio")])
sigma_hat <- summary(fit_demand)$sigma

knitr::kable(data.frame(
  state = state_names, alpha = alpha_hat, elasticity = -eta_hat
), digits = 3, col.names = c("需要の見通し", "切片の推定値", "価格弾力性の推定値"))
需要の見通し 切片の推定値 価格弾力性の推定値
暇な週 5.537 -3.493
普通の週 6.233 -2.518
忙しい週 6.628 -2.074

需要が多そうな週と少なそうな週では、需要の水準だけでなく、価格への反応も違うようだ。また、対数需要のショックの標準偏差は 0.193 と推定された。

実験データと推定した需要曲線を重ねると、次のようになる。ここで縦軸は数量そのものではなく、対数である。

図 2: 価格実験のデータと、状態別に推定した対数需要の条件付き平均

この講義では外部データを使わず、実験と営業記録も次のコードで作っている。実務の分析担当者には true_ で始まる値は見えない。上の推定も、この後のシミュレーションも、実験データと営業記録から得た推定値を使う。

# 教材用のデータ生成。true_で始まる値は、その後の推定・予測には渡さない。
state_levels <- c("low", "normal", "high")
state_names <- c("暇な週", "普通の週", "忙しい週")
price_menu <- seq(600, 1800, by = 50)

set.seed(20264)
true_alpha <- log(c(250, 500, 750))
true_eta <- c(3.5, 2.5, 2.0)
true_sigma <- 0.20
experiment_df <- data.frame(
  state = factor(rep(state_levels, each = 200), levels = state_levels),
  price = sample(price_menu, 600, replace = TRUE)
)
state_id <- as.integer(experiment_df$state)
experiment_df$quantity <- exp(
  true_alpha[state_id] - true_eta[state_id] * log(experiment_df$price / 1000) +
    rnorm(nrow(experiment_df), mean = 0, sd = true_sigma)
)

set.seed(20265)
true_state_prob <- c(0.25, 0.50, 0.25)
history_df <- data.frame(
  week = 1:208,
  state = factor(sample(state_levels, 208, replace = TRUE,
                        prob = true_state_prob), levels = state_levels)
)

# 費用・価格候補・現在の値付けは、業務上わかっている情報
cost_before <- 500
cost_after <- 650
current_prices <- c(700, 850, 1000)
history_df$price <- current_prices[as.integer(history_df$state)]
profit_target <- 2500000

生成時の \(\exp(\alpha_S)\) は、価格1,000円における数量の中央値であり、平均ではない。数量は連続量として近似している。生成時のパラメータと推定結果を比べると、次のようになる。

knitr::kable(data.frame(
  state = state_names,
  true_alpha = true_alpha, estimated_alpha = alpha_hat,
  true_elasticity = -true_eta, estimated_elasticity = -eta_hat
), digits = 3,
col.names = c("見通し", "切片の真値", "切片の推定値", "弾力性の真値", "弾力性の推定値"))
見通し 切片の真値 切片の推定値 弾力性の真値 弾力性の推定値
暇な週 5.521 5.537 -3.5 -3.493
普通の週 6.215 6.233 -2.5 -2.518
忙しい週 6.620 6.628 -2.0 -2.074

標本からの推定なので、真値と完全には一致しない。以下では、真値に戻して計算するのではなく、この推定結果を使って店長への提案を作る。

来期の需要を発生させるモデルを組み立てる

価格への反応が推定できても、それだけでは来期の業績は計算できない。そもそも、暇な週、普通の週、忙しい週が、それぞれどのくらい来るのだろうか。

各状態の確率を \(\pi_s=P(S_t=s)\) とし、通常営業の208週の記録から、

\[ \hat\pi_s=\frac{1}{208}\sum_{t=1}^{208}\mathbf{1}\{S_t=s\} \]

で推定する。\(\mathbf{1}\{S_t=s\}\) は、その週が状態 \(s\) なら1、それ以外なら0という記号である。

state_counts <- table(history_df$state)
state_prob_hat <- as.numeric(prop.table(state_counts))
knitr::kable(data.frame(
  state = state_names, weeks = as.integer(state_counts), probability = state_prob_hat
), digits = 3, col.names = c("需要の見通し", "過去208週の回数", "推定した確率"))
需要の見通し 過去208週の回数 推定した確率
暇な週 55 0.264
普通の週 105 0.505
忙しい週 48 0.231

ここでは、来期もこの確率が続き、週ごとの状態は独立に決まると仮定する。また、費用が変わっても、価格と見通しに対する需要の反応は変わらないとする。すると、来期の1週を作るモデルは次のように書ける。

\[ \begin{aligned} P(S_t=s)&=\hat\pi_s,\\ Z_t&\sim N(0,1),\\ q_t(p)&=\exp\{\hat\alpha_{S_t}-\hat\eta_{S_t}\log(p/1000)+\hat\sigma Z_t\}. \end{aligned} \]

\(Z_t\) は状態とも他の週のショックとも独立とする。店長は週初に \(S_t\) を見て価格を決めるが、\(Z_t\) が実現するのはその後である。需要の水準、価格への反応、ショックの大きさ、状態の確率のすべてに、データから得た推定値を入れている。

指定した価格・状態・ショックから数量を作る関数を用意しておこう。

quantity_hat <- function(price, state_id, z) {
  exp(alpha_hat[state_id] - eta_hat[state_id] * log(price / 1000) + sigma_hat * z)
}

推定した対数需要の平均を \(\hat\mu_s(p)=\hat\alpha_s-\hat\eta_s\log(p/1000)\) と書く。\(\exp\{\hat\mu_s(p)\}\) は、このモデルでは数量の中央値である。平均数量は

\[ \widehat E[q\mid p,S=s] =\exp\{\hat\mu_s(p)+\hat\sigma^2/2\} \]

になる。対数を取った量の平均と、元の量の平均を混同しないようにしよう。この後のコードは、\(\hat\sigma Z\) を加えてから exp() で数量を発生させ、それを平均する。そのため、ショックによって元の数量の平均が変わることも計算に入る。

候補価格ごとの粗利益をシミュレーションする

ここまでの結果を店長に見せると、「価格への反応はわかった。で、来期はいくらにするのがよいの?」と聞かれた。確かに、需要関数の係数を報告するだけでは依頼は終わっていない。

高く売れば1個あたりの利益は増えるが、売れる数量は減る。推定した需要関数を使って、この兼ね合いを計算しよう。 価格候補は600円から1,800円まで50円刻みとし、これは実験で無作為に割り当てた価格の候補と同じである。ここでは品切れや販売能力の制約はなく、売れた1個につき仕入費用 \(c\) がかかるものとする。

まず、需要の見通しを \(s\)、候補価格を \(p\) に固定する。標準正規乱数 \(Z^{(1)},\ldots,Z^{(M)}\) を発生させると、その価格での販売数量と粗利益が \(M\) 通りできる。これを平均して、週の期待粗利益を近似する。

\[ \widehat V_M(p,s;c) =\frac{1}{M}\sum_{m=1}^{M}(p-c) \exp\{\hat\alpha_s-\hat\eta_s\log(p/1000)+\hat\sigma Z^{(m)}\}. \]

ここで平均しているのは、同じ見通し・同じ価格の下で、売上ショックだけが異なる \(M\) 通りの「1週間の粗利益」である。暇・普通・忙しい週を混ぜた平均でも、13週分の合計でもない。

このように、多数の乱数から作った結果の平均や割合で期待値や確率を近似する計算を、モンテカルロ・シミュレーションという。ここでは \(M=20{,}000\) とする。

set.seed(20266)
planning_z <- rnorm(20000)

expected_profit_hat <- function(price, cost, state_id) {
  mean((price - cost) * quantity_hat(price, state_id, planning_z))
}

# 価格候補と需要の見通しの、すべての組み合わせを計算する
profit_grid <- expand.grid(price = price_menu, state_id = 1:3)
profit_grid$profit <- mapply(
  function(p, s) expected_profit_hat(p, cost_after, s),
  profit_grid$price, profit_grid$state_id
)

どの候補価格でも同じ planning_z を使っている。これにより、価格を比べるときに、たまたまよいショックが出たかどうかという違いを混ぜずに済む。

推定した需要に基づいて、値付けを提案する

店長の「粗利益をできるだけ確保したい」という目的に合わせて、推定モデルの下で週の期待粗利益が最も大きくなる価格を提案する。

\[ \hat g(s;c)=\arg\max_{p\in\{600,650,\ldots,1800\}}\widehat V_M(p,s;c). \]

\(\arg\max\) は「右側を最大にする \(p\) を選ぶ」という記号である。\(\hat g(s;c)\) は、見通し \(s\) と費用 \(c\) を与えると、提案する価格を返すルールだ。店長の行動を外から推測しているのではなく、あなたが需要推定の結果を使って提案を作っている。

recommended_prices <- sapply(1:3, function(s) {
  profits <- sapply(price_menu, function(p) expected_profit_hat(p, cost_after, s))
  price_menu[which.max(profits)]
})
knitr::kable(data.frame(
  state = state_names,
  current = current_prices,
  recommended = recommended_prices,
  increase = recommended_prices - current_prices
), col.names = c("需要の見通し", "現在の価格(円)", "提案価格(円)", "値上げ幅(円)"))
需要の見通し 現在の価格(円) 提案価格(円) 値上げ幅(円)
暇な週 700 900 200
普通の週 850 1100 250
忙しい週 1000 1250 250

仕入費用の上昇はどの週も150円だが、提案する値上げ幅は一律150円ではない。需要の価格への反応が見通しごとに違うため、利益を確保できる価格も違うのである。各週で今の価格を続けるか、提案価格に変えるかを、次の図で比べてみよう。

図 3: 費用650円での候補価格と期待粗利益。現在の価格と、推定モデルから提案する価格を示す

ここで最大にしているのは、売上ショックが実現する前の期待粗利益である。実際に売れた数量を見てから、一番儲かったはずの価格を選び直しているわけではない。また、毎週の価格変更に追加の費用はなく、今週の価格は翌週の需要に影響しないものとする。この設定だから、見通しごとに週の期待粗利益を比べればよい。

実は、このlog-log需要と正規ショックのモデルでは、先ほどの平均数量の式から、週の期待粗利益も直接計算できる。価格選択だけのために、乱数が不可欠というわけではない。

ここでは候補価格ごとの結果を発生させて比べる手順を見せたが、今回の依頼はそれで終わらない。需要の見通しも売上ショックも異なる13週間を通した業績の分布と、予算を下回る確率まで報告する必要がある。次のシミュレーションは、その部分に答えるためのものである。

その値付けを採用した来期を、5,000通り作る

店長に提案を採用してもらった場合、来期はどうなりそうか。週初の見通しが暇なら暇な週用の価格、普通なら普通の週用の価格、忙しいなら忙しい週用の価格を使う。来期の13週間を5,000通り発生させてみよう。

set.seed(20267)
n_future <- 5000
weeks_per_quarter <- 13

# 行が1つの仮想的な来期、列が第1週から第13週
future_state <- matrix(
  sample(1:3, n_future * weeks_per_quarter, replace = TRUE, prob = state_prob_hat),
  nrow = n_future
)
future_z <- matrix(rnorm(n_future * weeks_per_quarter), nrow = n_future)

ここでも、状態の確率には営業記録からの推定値を使っている。価格を比較するときの planning_z とは別の乱数を使い、提案した値付けの結果を評価する。

値付けルールを \(g\) とすると、仮想的な来期 \(b\) における粗利益の合計は、

\[ \begin{aligned} p_{bt}&=g(S_{bt}),\\ q_{bt}&=\exp\{\hat\alpha_{S_{bt}}-\hat\eta_{S_{bt}}\log(p_{bt}/1000)+\hat\sigma Z_{bt}\},\\ \Pi_b(c,g)&=\sum_{t=1}^{13}(p_{bt}-c)q_{bt}. \end{aligned} \]

となる。各週で見通しに合わせた価格を選び、その後に売上ショックが実現する。価格を決める式に、その週の \(Z_{bt}\) は入っていない。 そして13週分の粗利益を足せば、1つの来期の粗利益ができる。

simulate_quarters <- function(cost, price_rule) {
  price <- matrix(price_rule[future_state], nrow = n_future)
  alpha <- matrix(alpha_hat[future_state], nrow = n_future)
  eta <- matrix(eta_hat[future_state], nrow = n_future)
  quantity <- exp(alpha - eta * log(price / 1000) + sigma_hat * future_z)
  data.frame(
    mean_price = rowMeans(price),
    quantity = rowSums(quantity),
    revenue = rowSums(price * quantity),
    profit = rowSums((price - cost) * quantity)
  )
}

# 対応する来期では、同じ需要の見通しと同じ売上ショックを使う
baseline_quarters <- simulate_quarters(cost_before, current_prices)
unchanged_quarters <- simulate_quarters(cost_after, current_prices)
recommended_quarters <- simulate_quarters(cost_after, recommended_prices)

比較するのは、費用が500円のまま今の価格を続ける世界、費用が650円になっても今の価格を続ける世界、費用650円で提案価格を使う世界の3つである。同じ来期どうしには同じ状態とショックを使い、たまたま忙しい週が多かったという違いを、費用や価格の違いに混ぜないようにしている。

平均と下振れリスクを報告する

店長へのレポートを作ろう。来期の粗利益の期待値を近似するには、13週分を合計した粗利益を、5,000通りの来期について平均する。

\[ \widehat{E[\Pi(c,g)]}_{\mathrm{MC}} =\frac{1}{B}\sum_{b=1}^{B}\Pi_b(c,g), \qquad B=5000. \]

13で割っていないので、これは1週間の平均ではなく、四半期の粗利益の平均である。一方、250万円を下回る確率は、

\[ \widehat{P(\Pi(c,g)<2500000)}_{\mathrm{MC}} =\frac{1}{B}\sum_{b=1}^{B}\mathbf{1}\{\Pi_b(c,g)<2500000\} \]

で近似する。5,000通りのうち何通りが未達だったか、という割合である。

summarize_quarters <- function(x, label) {
  data.frame(
    scenario = label,
    mean_price = mean(x$mean_price),
    quantity = mean(x$quantity),
    revenue_man = mean(x$revenue) / 10000,
    profit_man = mean(x$profit) / 10000,
    below_target_pct = 100 * mean(x$profit < profit_target)
  )
}
pricing_report <- rbind(
  summarize_quarters(baseline_quarters, "費用500円・現在の価格"),
  summarize_quarters(unchanged_quarters, "費用650円・現在の価格"),
  summarize_quarters(recommended_quarters, "費用650円・提案価格")
)
計算した世界 平均価格(円) 数量(個) 売上(万円) 粗利益(万円)
費用500円・現在の価格 844 10525 882.5 356.3
費用650円・現在の価格 844 10525 882.5 198.4
費用650円・提案価格 1081 5413 591.3 239.4

数量・売上・粗利益は13週合計を来期間で平均したもの、価格は各週の価格を全5,000×13週で単純平均したものだ。

計算した世界 250万円未満の割合(%)
費用500円・現在の価格 0.02
費用650円・現在の価格 94.54
費用650円・提案価格 65.68
図 4: 推定した需要モデルで作った四半期の粗利益の分布。破線は250万円

図の棒が高いところほど、その範囲の粗利益になる来期が多かった。破線の左側が予算未達の来期である。

店長には、「費用上昇後も今の値付けを続ける場合と比べて、提案価格を使うと四半期の期待粗利益は約 41万円改善する見通しです。ただ、それでも250万円を下回る確率は約 65.7%あります」と報告できる。

需要曲線の推定で終わらず、その需要の下でどんな価格を提案し、採用した場合にどんな業績とリスクが見込まれるかまで、データを使って答えたのである。

今回の提案では、期待粗利益の最大化を判断基準にした。予算未達の確率は、その提案を採用した場合にも残るリスクとして報告している。

このレポートでは、需要係数、ショックの大きさ、状態の確率を推定値に固定して来期を発生させた。図が示しているのは、そのモデルの下での営業上の不確実さであり、パラメータの推定誤差も含めた予測区間ではない。提案価格も、推定した需要の下で最良の価格であって、真の需要の下で必ず最良とは限らない。

有限回のシミュレーションによる計算上の誤差もある。未達割合を \(\hat r\) とすると、モンテカルロ標準誤差はおおよそ \(\sqrt{\hat r(1-\hat r)/B}\) である。回数を増やせばこの誤差は小さくなるが、需要推定の誤差や来期の利益のばらつきは、それによって消えるわけではない。

実験と対象店舗に同じ需要モデルを使えること、来期も需要の反応や状態の分布が変わらないことも、結果を支える仮定である。実際の業務では推定の不確実さやこれらの仮定を検討し、提案を採用した後の実績とも照合していく必要がある。

重要推定した需要を、意思決定に使う

ここでの流れは、需要推定 → 反実仮想シミュレーション → 値付けの提案と業績の見通しである。需要のパラメータを推定するのは、係数の表を作るためだけではない。価格や費用を変えた世界で何が起きるかを計算し、どの選択をするか考えるためである。

ここは非常に重要なところである。どういう財をどういう価格で出した時に何個売れるのか、という需要関数を「所与」として、価格だけを動かした世界をシミュレーションした。なぜ需要関数は「所与」でいいのか?それは、需要関数を構成する、消費者の効用関数とそ効用関数に基づいた期待効用最大化という行動モデルは店側の価格を変えるという行動とは無関係だからである。つまり価格を変えた世界でも消費者の行動は変わらないので需要関数は変わらない。最初から1点の需要というポイントではなく、「こうなったらいくら買う」という関数として需要を求めておけば、それをいろんな世界で使いまわせるということである。

なので、需要関数は実証IOの根底にある概念であり、次回以降の数回はこの需要関数の推定という一点のみについて話す。今回は1商品の単純な需要関数を使った。次回以降は、消費者の選択から需要を組み立て、商品の代替関係も推定していく。そうした需要推定を土台に、複数商品の価格設定や企業間の競争、合併後の価格を計算する話へ進んでいく。

5. 反実仮想とは何か

ここまで見てきた「広告費を2倍にしたら」「仕入費用が上がり、提案した値付けを採用したら」という計算が、まさに反実仮想(counterfactual)である。反実仮想とは、「もしあの時、実際に起きたこととは違う選択をしていたら、結果はどうなっていたか」をモデルを使って計算することだと定義できる。

計量経済学Iで学んだ因果推論の道具(DiD、IV、RDDなど)も、広い意味では反実仮想を扱っている。「もしこの処置を受けていなかったら」という潜在アウトカムを、実際に観測されたデータの変動を利用して推定するのがそれらの手法だった。これらの設計が最も説得力を持つのは、通常、実際に観測された処置や共変量の支持範囲に近い問いである。支持範囲の外へ因果効果を外挿すること自体は不可能ではないが、効果の関数形や不変性について追加の仮定が必要になる。例えば、5%の値上げの変動から「50%値上げしたらどうなるか」「まったく新しい価格帯ならどうなるか」を答えるには、研究デザインだけでは足りない。

これに対して、需要関数や効用関数といった構造モデルを推定しておけば、データの中に実際に存在しない価格や商品構成についても、モデルの数式に従った結果を計算できる。これが構造推定(structural estimation)のアプローチであり、「構造推定とは、反実仮想シミュレーションをするためにモデルのパラメータを推定する作業である」とまとめることができる。ただし、計算可能であることと信頼できることは別である。遠い外挿ほど、効用の関数形、パラメータの政策不変性、企業行動や均衡の仮定に結果が強く依存するため、感度分析とモデル診断が欠かせない。

このコースで扱う反実仮想の具体例を、少し先取りして挙げておこう。

  • 合併審査(第4〜5回):2つの企業が合併したら、統合後の会社は価格をどう変えるインセンティブを持つか。需要の代替性(自社製品同士がどれだけ競合しているか)と供給側の価格設定モデルを組み合わせて、合併後の均衡価格をシミュレーションする。これは公正取引委員会などの独占禁止当局が実際に行っている分析そのものである。
  • 価格最適化(第15回):将来の需要変動や在庫状況を織り込んだ上で、いつ・いくらで値付けすれば利益(または売上)が最大になるかを、動的計画法を使ってシミュレーションする。

3つの概念の違いを、もう一度整理しておこう。

  • 予測(prediction):既存の相関構造を使って、観測されていない値(多くは将来の値)を当てにいくタスク。因果関係である必要はないが、学習時の相関構造が予測先でも安定していることが必要である。機械学習の多くの応用はここに属する。
  • 因果効果(causal effect):ある1つの処置・施策について、「その施策をした場合としなかった場合の差」を測るタスク。処置は通常、実際にデータの中で(一部の主体に対して)起きたものに限られる。
  • 反実仮想(counterfactual)/構造推定:モデル(需要関数、効用関数、企業の価格設定行動のモデルなど)を推定し、そのモデルを使って、データの中に実際には存在しない状況(新しい価格、新しい商品、新しい市場構造)の結果を計算するタスク。

3つは互いに排他的ではない。因果推論の道具(IV、DiDなど)は、構造モデルのパラメータを識別・推定するためにしばしば使われる(第3回のBerry反転+IV推定がその代表例)。つまりこのコースは、「予測」から「因果」を経て「反実仮想」へと視野を広げていく旅だと理解しておくとよい。

問いを受け取ったら、次の順で必要な材料を一段ずつ足すと混乱しにくい。

タスク 典型的な問い 最低限必要なもの
予測 今の運用が続くと来月の需要は? 予測精度と分布の安定性
支持範囲内の因果効果 実施された5%値上げの効果は? 比較可能な反実仮想を作る識別戦略
構造的反実仮想 未経験の価格・新商品・合併なら? 識別された行動パラメータと不変性・均衡の仮定
最適化 どの価格・配分を選ぶべきか? 反実仮想を計算するモデルに加え、目的関数と制約

6. 実証研究コーナー

ヒント実証研究コーナー:Chintagunta, Erdem, Rossi, and Wedel (2006)

消費者や企業の行動をモデルに書くと、何ができるようになるのか。“Structural Modeling in Marketing: Review and Assessment” は、消費者の選択・需要や企業間の競争を扱った研究を振り返り、マーケティングにおける構造モデルの役割を論じたレビューである。

著者たちが検討しているのは、行動についての理論をデータで確かめることと、そのモデルを実際の意思決定に使うことである。モデルを細かく作るほど、行動についての仮定や推定の計算負担も増える。その手間に見合うだけ、よい意思決定ができるのか。論文では、構造モデルの利点とともに、仮定の検証やモデルの妥当性をどう評価するかも取り上げている。

今回のシミュレーション2では、推定した需要関数を使って価格を選んだ。この例を踏まえると、「その提案は、需要について置いた仮定にどこまで依存しているのか」という問いを持って読める。これから構造モデルを学ぶにあたって、その使い道と、結果を信用するために確かめるべきことを考える入口になる。

ヒント実証研究コーナー:Athey and Luca (2019)

“Economists (and Economics) in Tech Companies” が紹介するのは、経済学がテック企業の中でどのような仕事になっているか、という話である。広告の効果を測ることから、広告枠を売るオークションや、利用者どうしが評価するレビューの仕組みまで、経済学者が関わる対象は幅広い。因果推論の技能に加えて、人のインセンティブや企業どうしの相互作用を考える力が、こうした仕事で使われている。

例えば、相手のレビューを読んでから自分のレビューを書く仕組みでは、悪い評価への報復を恐れて、正直な感想を書きにくくなるかもしれない。論文は、評価の公開方法を変えることでこうした問題に対処する研究を取り上げている。データを分析することと、人がどう反応するかを考えて仕組みを設計することが、つながっているのである。

今回、需要を推定してから値付けを提案したのも、こうした仕事の小さな例として読める。企業の依頼を分析できる問いに直し、その結果を実際の選択につなげるところまでが仕事になる。この講義で学ぶ道具がどこで使われるのか、具体的なイメージを持つのによい論文である。

ヒント実証研究コーナー:Einav and Levin (2014)

行政記録や企業の取引データが使えるようになると、経済学で調べられることはどう広がるのだろうか。“Economics in the Age of Big Data” は、そうした変化を具体的な研究とともに紹介している。

面白い例が、eBayで同じ売り手が同じ商品を繰り返し出品する記録である。商品や売り手をそろえながら、価格、送料、販売方法の違いを比較できる。ただし、売り手が需要の変化を見て価格を変えている可能性は残る。そこで同時に出品された商品に比較を絞るなど、細かな記録を使って比較の説得力を高めていく。大量のデータがあることの利点が、具体的に見えてくる例である。

機械学習と経済理論の組み合わせにも話が及ぶ。広告がクリックされる確率を予測することと、その広告枠をどのように売り、料金を決めるかは、組み合わせて考える必要がある。豊かなデータから何を学び、それをどんな意思決定に使うか。今回の講義を、データの変化によって広がる経済学の仕事の一部として捉えられる論文である。

ヒントおもしろ枠:Varian (2014)

“Big Data: New Tricks for Econometrics” は、回帰分析に馴染みのある経済学者に向けて、決定木、ランダムフォレスト、LASSOなどを紹介する論文である。タイタニック号の乗客の生存を予測する例などを使い、実際のデータに手法を当てはめながら説明している。学習に使ったデータへの当てはまりだけで満足せず、別のデータで予測性能を確かめることや、クロスバリデーションを使うことも勧めている。

今回の講義と特に近いのは、後半の予測と因果の議論だ。犯罪が多い地区ほど警官を多く配置しているなら、警官の人数と犯罪の相関は予測に役立っても、警官を増やす政策の効果にはならない。シミュレーション1の広告費と同じ問題である。一方で著者は、予測の道具を因果推論に組み込む可能性にも目を向け、広告を出さなかった場合のウェブサイト訪問数を予測して、実際の訪問数と比較する例を紹介している。

予測性能を高める工夫を学びながら、「その予測は、どの世界の結果を予測しているのか」と考えて読むとよい。今回分けて考えた予測と介入を、実際の分析でどう組み合わせるかに関心がある人に勧めたい。

7. ビジネスの現場で

ノートビジネスの現場で:依頼を「予測・効果検証・最適化」に仕分ける

データ分析チームに実際に来る依頼を、次の3つのタスクに仕分ける練習をしてみよう。

  • 予測タスク:「来月の在庫、どれくらい発注すればいいですか」「この顧客は来月解約しそうですか」。過去の相関パターンをそのまま将来に当てはめてよいタスク。
  • 効果検証タスク:「先月のクーポン施策、本当に売上を増やしたんですか」「新しいアプリのUI変更は、離脱率を下げたんですか」。ある1つの施策の因果効果を測るタスク。第10回では、ランダム化実験によって施策の増分利益を評価する。実験ができない場合も、計量Iで学んだ識別仮定や、第3回の価格内生性への対処が必要になる。
  • 最適化タスク:「どの顧客に、いくらのクーポンを配れば利益が最大になりますか」「この夏のセールで、どの商品をどれだけ値下げすべきですか」。反実仮想シミュレーションと組み合わせて、意思決定そのものを最適化するタスク。

同じ「価格を下げたら売上はどうなるか」という質問でも、「来月の売上予測に使いたいだけ」なのか、「本当にその値下げが効果があったのか検証したい」のか、「最適な値下げ幅を知りたい」のかによって、必要な分析はまったく違う。依頼の言葉をそのまま受け取らず、この3分類のどれに当たるかをまず見極めるのが実務の第一歩である。

ノートビジネスの現場で:「A/Bテストできない意思決定リスト」

実験(A/Bテスト)は因果効果を測るための最も強力な道具だが、すべての意思決定に使えるわけではない。以下は、実務でA/Bテストが難しい(あるいは事実上不可能な)意思決定の例である。

  • 全社的な値上げ:一部の店舗・顧客だけ価格を変えると、公平性の問題や顧客の不満(同じ商品なのに店舗によって値段が違う)を招きやすい。
  • テレビCM・マス広告:地域単位でしか出し分けができず、地域間で需要構造が違うため、綺麗な実験にはなりにくい。
  • 店舗の大規模改装:コストと時間がかかりすぎて、多数の店舗で同時に「改装する店」「しない店」をランダムに割り当てるのは非現実的。
  • 企業の合併:そもそも「合併する場合としない場合」を複数の世界で試すことはできない。

こうした意思決定に対しては、計量Iで学んだ観察データの因果推論や、需要・供給の構造モデルによる反実仮想シミュレーション(第3〜5回、第15回)が主要な武器になる。このコースの後半で学ぶ技術の多くは、まさに「実験ができない状況でどう意思決定を支えるか」という問題への答えである。

まとめ

重要まとめ
  • 計量経済学IIは、計量経済学Iで学んだ「識別・推定・推論」の3ステップと「モデル=条件付き分布の束」という考え方を土台に、意思決定のための反実仮想シミュレーションを組み立てることを目指す。
  • 実証ビジネス・エコノミクス、実証IO、quantitative marketingは、いずれも「データを使って企業・政策の意思決定を支える」という目的を共有する隣接分野であり、企業の意思決定は(a)需要と代替性、(b)施策の因果効果、(c)顧客の異質性、(d)最適な配分・価格付け、という4つの問いに整理できる。
  • 「予測」と「因果」はまったく別のタスクである。広告費と売上の相関を使ったモデルは、来月の売上予測にはよく効くが、「広告費を動かしたらどうなるか」という介入予測には大きく外れることがある。
  • データから需要関数を推定し、候補価格ごとの結果を計算することで、値付けを提案できる。その提案を採用した将来を繰り返し作れば、平均業績に加えて、予算未達の確率も計算できる。
  • 反実仮想とは「もしあの時○○していたら」をモデルで計算することであり、構造推定とはそのためのパラメータ推定作業である。合併審査や価格最適化など、このコース後半の多くのトピックがこの考え方の応用である。
  • 実験(A/Bテスト)ができない意思決定は数多く存在し、そこでは観察データの因果推論や構造モデルによる反実仮想シミュレーションが主要な武器になる。

宿題

  • ブラウザ実験室(playground1.html)で、今回のシミュレーションの数値を自分でいじって遊んでみよう。インストール不要、ブラウザだけでRが動く(初回ロードのみ30秒〜1分かかる)。
  • 計量経済学Iの自分のノートを見返し、「識別・推定・推論」の3ステップと「モデル=条件付き分布の束」という考え方について、自分の言葉で3行程度にまとめ直してみよう。
  • ChatGPT(または他の対話型AI)に「反実仮想とは何か、経済学の文脈で説明してください」と聞いてみて、自分がこのノートで学んだ内容とどう違う・同じかを比べてみよう。
  • 自分の仕事(または身近な企業)で「A/Bテストができない意思決定」を1つ挙げ、それがどうすれば分析できそうか(観察データの利用? 構造モデル?)を考えてみよう。
  • coding課題は assignment1.qmd を参照。価格と数量の店舗パネルデータを使い、操作変数法(2SLS)で真の価格弾力性を回収する練習をする。講義のシミュレーションとは別の設定で、需要を識別する側を練習する。

次回予告

次回(第2回)では、今回のシミュレーション2で推定した需要関数の中身に踏み込み、「消費者は複数の選択肢の中から1つを選ぶ」という状況を、確率的効用最大化モデル(random utility model, RUM)として定式化する。消費者が財の効用を比較して選択するというモデルから、有名な「logitモデル」の選択確率の式を導出し、計量Iでは扱わなかった最尤法(maximum likelihood estimation)を初めて学ぶ。さらに、価格弾力性・交差弾力性の計算方法も導入する。ここから数回にわたって、離散選択モデルという、実証IO・quantitative marketingの中心的な道具を身につけていくことになる。

参考文献

  • 上武康亮・遠山祐太・若森直樹・渡辺安虎 (2025)『実証ビジネス・エコノミクス』日本評論社、第1章。
  • Chintagunta, P., Erdem, T., Rossi, P. E., and Wedel, M. (2006) “Structural Modeling in Marketing: Review and Assessment,” Marketing Science, 25(6), 604-616.
  • Athey, S. and Luca, M. (2019) “Economists (and Economics) in Tech Companies,” Journal of Economic Perspectives, 33(1), 209-230.
  • Einav, L. and Levin, J. (2014) “Economics in the Age of Big Data,” Science, 346(6210), 1243089.
  • Varian, H. R. (2014) “Big Data: New Tricks for Econometrics,” Journal of Economic Perspectives, 28(2), 3-28.