備忘録 blog

Docker/Machine Learning/Linux

ベイズ統計を用いた投票モデリングを目指して

はじめに

投票をある程度解釈可能なモデルによってモデリングすることによって、そのモデルのパラメータを変更した際に、選挙結果がどのぐらい変化するかというのを見積もることができる可能性がある。まず選挙に対するモデリング手法について、先行例として調査したものを紹介する。

また、実際はまだモデリングまで至っていないが、投票結果を解析するために、人間の解釈が可能なモデルを今後作っていきたい。その上で検討しているアイディアについても、あわせて記す。

先行例の調査

ベイズの考え方を用いると、投票行動は、ディリクレー多項分布モデルによって表現することができる。それぞれの分布について簡単に説明する。

類似した問題として、サイコロを複数回振った時に、どの出目が何回出たのか、というのをモデリングしたいと考える。この時、サイコロの出目は複数存在し、その中で1つを選ぶ、ということを表現する分布としてカテゴリカル分布というものがある。この試行を複数回繰り返すような場合では、多項分布を用いて表現することができる。

ただしサイコロの場合は等確率だが、候補者が選ばれる確率は等確率ではないこともある。この時、値の選ばれ方の性質(例えばサイコロであれば全ての出目が出る確率は同じ、投票であれば、1回の投票につき、候補者が選ばれる確率というのは候補者によって異なる)は、何らかの事前分布によって表現したい。そのためここでは、ディリクレ分布というものを用いることにする。

ディリクレ分布におけるパラメータ  {\alpha} によって、i 個の事象がそれぞれ  { \alpha_{i}-1} 回発生したときに、各事象の起こる確率が  {x_{i}}  である確率分布が与えられる。この分布は、あらゆる i に対して  { \alpha_{i}=1} の時は一様分布になり、 { \alpha_{i}} が大きくなればなるほど、確率分布の分散が小さくなっていく。

www.behind-the-enemy-lines.com

例えば3回、  { \alpha_{i}=1} のディリクレ分布から値を取る(サンプリングする)という試行を行うと、以下のようにランダムに3人の候補者に対する投票確率を得ることができる。(和は1になっている。)

f:id:sharply:20220204001549p:plain

ディリクレ分布は多項分布の共役事前分布になっている。このディリクレ-多項分布を用いて、投票をモデリングすることができる。

blog.byronjsmith.com

例えば、1988年のブッシュvsデュカキスのアメリカ大統領選挙モデリングする例がいくつか実装されている。1988年9月25日、大統領選挙の討論の前後で、ブッシュとデュカキスのどちらを支持するか?という世論調査を行ったとき、その結果がどのぐらい変化したか?というのをここではモデリングしている。

notebook.community

f:id:sharply:20220204000554p:plain

f:id:sharply:20220207180724p:plain

もっと複雑なものとして、パリにおけるEU・大統領・地域議員の選挙において、それぞれの選挙区における6つの主要政党(極左、左派、緑の党、中道、右派、極右)の得票数をモデルに組み込んだ Jupyter Notebook が公開されており、まだ全貌を読み解くことはできていないが、モデリング手法の検討に向けた大きな手がかりになると考えられる。

https://nbviewer.org/github/AlexAndorra/pollsposition_models/blob/master/district-level/munic_model_prod.ipynb

これについては、 YouTube に紹介のプレゼンテーションも上がっている。

www.youtube.com

これとは別の方法として、ベイズ回帰を用いたモデリングをするという方法もある。具体的には、個人の得票数に対して、グループによるバイアスがどの程度あるかを調べている。

gaiasky.hatenablog.com

モデリング

ここでは投票について、どのようなモデルが作れるかについて、いくつかの検討を記載する。

  • パターンA: ディリクレ分布によって表現される投票先のパターンについて、その重み付き和として表現される、各選挙区ごとの有権者の好みを多項分布によって表現する、ディリクレー多項分布モデルによって扱う。
    • 人間がとりうる投票パターンは限られている(選挙区ごとに完全にバラバラではなく、ある程度一致している)という仮定の元で、少ない投票パターンの重ね合わせで各選挙区の得票分布を説明することで、どんな投票パターンがあると、現実のそれぞれの選挙区での得票分布が説明できるかを探す。
    • Pros: 実装しやすい。
    • Cons: 人間がとりうる投票パターンは、政党の好みをディリクレ分布で表現するよりも、類似した政治的主張をする政党に投票する確率に相関がある、とみなすほうがより現実に近いのではないか?と考えることができる。
n_patterns = 4
n_candidates = 3
n_regions = 2

with pm.Model() as polling_model:
    
    # initializes the Dirichlet distribution with a uniform prior:
    shape = (n_patterns, n_candidates)
    a = np.ones(shape)
    shape2= (n_patterns, n_regions)
    b = np.ones(shape2)
    shape3 = (n_candidates, n_regions)
    np.dot(a.T,b)

    # This creates a separate Dirichlet distribution for each debate
    # where sum of probabilities across candidates = 100% for each debate
    theta = pm.Dirichlet("theta", a=a, shape=shape)

    coeff = pm.Dirichlet("coeff", a=b, shape=shape2)
    
    vote_dist = pm.math.dot(theta.T, coeff)
    
    responses = pm.Multinomial("responses", n=n, p=vote_dist, observed=y, shape=shape3)

f:id:sharply:20220207235219p:plain

このモデルに対して、有権者の政党に対する好みにおける仮定を反映させたいと考える。この仮定は、政治傾向が類似した候補者にはある程度の確率で投票するが、政治傾向が遠い候補者に投票する確率が低いという想定である*1

この想定の中で、候補者(あるいは政党)を、その政治的な立ち位置によって一次元の軸上に表現できるのではないかという、いささか大胆な仮定を置いている。つまり、どの候補者を選択するかというのを単純なカテゴリとして分類するのであれば、ディリクレ分布のようなモデルを使うのは妥当かもしれないが、どの候補者を選ぶかというところに何らかの指向性があるとすると、別の分布を利用できることが考えられる。

ここでは、順序予測 (ordinary prediction) と同じような考え方を用いてモデリングすることを想定している。順序予測というのは、例えば「あなたは今幸福かどうかを1(幸福ではない)~10(幸福である)の値で表現した時に、 どのぐらいの値ですか(整数)?」というアンケートにおける分類の値であったり、「競馬による着順は何位か?」というように、カテゴリではあるが、隣り合ったカテゴリは便宜上隔てられているだけであって、その間には何らかの連続性があるものに対する予測のことを指している。

これはどのように実現できるかというと、積分布関数上の閾値 x_1, x_2, ... の差 x_2-x_1, x_3-x_2, ... を確率とするようにモデルを作ることで、その閾値の分布を、不確かさを含めてモデリングできるようになる。このようなアイディアに基づいて、パターンBとパターンCを考えている。

  • パターンB: 政党の好みを一次元のそれぞれの選挙区において、有権者が平均μ、分散σの正規分布に従うとする。正規分布か何かでえられるような閾値x_1, x_2, ... によって、その有権者分布を候補c_1, c_2,... に分割し、累積分布関数の差によって得られた確率p_1, p_2, ... によって表現される各選挙区ごとの有権者の好みを、多項分布によって表現する。
    • パターンBでは、政党の好みが、集団ごと異なる正規分布で表現されるという仮定を置いている。
    • Pros:
      • 選挙区毎の有権者の政治傾向分布を表現することができる。
      • 候補の政治傾向を一次元で表現できる。
    • Cons:
      • 政党をポジションによって一軸にソートできない場合、政党のポジションは何によって定義すべきか?
      • 全ての選挙区で同じ切り口で切ってしまうと、単に選挙区毎の有権者の思想分布が違うという結論になってしまって、政党ごとの特徴を見いだすのが難しくなってしまう可能性はある。
@as_op(itypes=[tt.dmatrix, tt.dscalar, tt.dscalar], otypes=[tt.dmatrix]) 
def outcome_probabilities_mat(theta, mu, sigma):
    out = np.empty((theta.shape[0]+1, theta.shape[1]), dtype=np.float64)
    n = norm(loc=mu, scale=sigma)       
    cdf = np.vectorize(lambda x: n.cdf(x))
    theta_cdf = cdf(theta).T

    out[0, :] = theta_cdf[0, :]      
    out[1, :] = np.max([np.repeat(0, theta.shape[1]), theta_cdf[1, :] - theta_cdf[0, :]], axis=0)
    out[2, :] = 1 - theta_cdf[1, :]

    return out

thresh_tmp = np.repeat([(0.35, 0.65)], n_regions, axis=0)

with pm.Model() as polling_model_complex:
    
    shape = (n_patterns, n_candidates)
    shape3 = (n_regions, n_candidates)
    ps = pm.Normal('theta', mu=thresh_tmp, #tau=np.repeat(1/2**2, len(thresh4)),
                      shape=(n_candidates - 1, n_regions))#, observed=thresh_obs4)
    p1 = pm.Uniform('p', -1, 1)
    sds = pm.Uniform("sds", 0.1, 10)

    vote_dist = outcome_probabilities_mat(ps, p1, sds)

    responses = pm.Multinomial("responses", n=n, p=vote_dist.T, observed=y, shape=shape3)

f:id:sharply:20220204000612p:plain

  • パターンC: 日本全体で正規分布に従う1つの指向モデル(いわゆる選挙の風)を持っていて、その上でそれぞれの選挙区において、正規分布か何かでえられるような閾値 x_1, x_2, , ... によって、その有権者分布を候補 c_1, c_2,... に分割し、累積分布関数の差によって得られた確率 p_1, p_2, ... によって表現される各選挙区ごとの有権者の好みを、多項分布によって表現する。
    • Pros:
      • 政党間の連合が存在している場合と存在していない場合との間で、どのぐらい支持を得ている層が違うかが分かる可能性がある。
    • Cons:
      • 政党をポジションによって一軸にソートできない場合、政党のポジションは何によって定義すべきか?
      • 単純に政党別の得票率の帯グラフとは何が違うのだろうか?

これらについて実際のモデルの適用については、具体的に議論しておらず、今後の課題となっている。

*1:具体的には右派の有権者は極右〜中道の候補者に投票しがち、左派の有権者極左〜中道の候補者に投票しがち、という傾向。