脳ざらし紀行


2005-09-13

_ Ruby で政治学

衆院選は自民党の圧勝で終わりました。民主党はどうしてここまで惨敗してしまったのでしょうか。小選挙区制に原因があるとも言われています。小選挙区での得票数と議席は以下のようになります。従来から小選挙区制度では2大政党制になるだとか、なんだとか色々なことがいわれているようですがそれって本当なんでしょうか。

その他にも、一票の格差が結果に影響を与えているかもしれません。民主党は都市部で強くて、一票の格差のために不利であるという説もあります。

Ruby を使って簡単に実験してみましょう。

小選挙区での得票数と議席
得票数 議席
自民32518389 219
民主24804786 52
公明981105 8
共産4937375 0
社民996007 1
国民432679 2
日本137172 0
無所属3240521 18

300の選挙区の人口はすべて同じだとします。上の得票をランダムに300の小選挙区に割り振っていき、選挙区毎にトップになった政党がその選挙区の議席を獲得するとします。プログラムを速くて簡単なものにするために、各選挙区の人口を実際の1/100として、政党に投票する確率は独立同分布にしています。

voter = {}
voter[:jimin]  = 32518389
voter[:minshu] = 24804786
voter[:kome]   =   981105
voter[:kyosan] =  4937375
voter[:shamin] =   996007
voter[:kokumin]=   432679
voter[:nippon] =   137172
voter[:mushozk]=  3240521

seats = {}
voter.each_key{|k| seats[k] = 0}

sum = 0
voter.each_value{|v| sum += v}
voter_per_zone = sum / (300 * 100)

300.times{
  zone = {}
  voter.each_key{|k| zone[k] = 0}
  
  voter_per_zone.times{
    vote =  rand(sum) + 1
    voter.each{|k, v|
      if vote <= v
        zone[k] += 1
        break
      else
        vote -= v
      end
    }
  }
  seats[zone.sort{|a, b| a[1] <=> b[1]}[-1][0]] += 1  
}
seats.each{|k, v|
  puts "%7s" % k + ": %4d" % v
}

さて結果は、実際の選挙結果と似たようなものになるでしょうか。それとも、民主党に有利なものになるでしょうか。少し考えてみて下さい。

 

 

 

結果は以下のようになります。

$ ruby vote.rb
  jimin:  300
 nippon:    0
 minshu:    0
mushozk:    0
   kome:    0
 kyosan:    0
 shamin:    0
kokumin:    0

驚くべきことに、自民党がすべての小選挙区で議席を獲得してしまうのです。つまり私たちの単純なモデルは現実をうまく説明できないということです。また、最初の問の立て方も間違っていたことが分かります。私たちは「どうして民主党が惨敗したのか」ではなく、「どうして民主党はこんなにも小選挙区で議席を獲得できたか」を考えないといけません。

しかし、有権者が実際にどのように投票しているかを考えるトイモデルとしてはなかなか悪くないでしょう。得票率を色々変えて遊んでみると良いかもしれません。例えば、小選挙区にランダムに各党の支持者が住んでいるこの単純なモデルでは、得票数がかなり拮抗しないと2大政党制にはならないことが分かります。2大政党制はそんなに簡単には実現しないようです。

このようなことを考えていくのが政治学であると僕は理解しています。

_ [Ruby] Array#each と Hash#each

Hash#each は遅いのか。

$ cat h_vs_a.rb
require 'benchmark'

h = {}
n = 1000000
n.times{|i| h[i] = nil }
a = Array.new(n)

Benchmark.bm{|b|
  b.report do
    h.each{|k, v| }
  end

  b.report do
    a.each{|e| }
  end
}
$ ruby -v h_vs_a.rb
ruby 1.9.0 (2005-09-09) [i686-linux]
      user     system      total        real
  9.250000   0.030000   9.280000 ( 10.004543)
  0.330000   0.000000   0.330000 (  0.337381)

Hash を Array で書き直し。

voter = [
  [:jimin, 32518389],
  [:minshu, 24804786],
  [:kome, 981105],
  [:kyosan, 4937375],
  [:shamin, 996007],
  [:kokumin, 432679],
  [:nippon, 137172],
  [:mushozk, 3240521],
]

seats = {}
voter.each{|k| seats[k[0]] = 0}

sum = 0
voter.each{|v| sum += v[1]}
voter_per_zone = sum / (300*100)

300.times{
  zone = {}
  voter.each{|k| zone[k[0]] = 0}
 
  voter_per_zone.times{
    vote =  rand(sum) + 1
    voter.each{|k|
      if vote <= k[1]
        zone[k[0]] += 1
        break
      else
        vote -= k[1]
      end
    }
  }
  seats[zone.sort{|a, b| a[1] <=> b[1]}[-1][0]] += 1  
}
seats.each{|k, v|
  puts "%7s" % k + ": %4d" % v
}
$ time ruby -v vote.rb > /dev/null
3.33s user 0.01s system 98% cpu 3.401 total
 
$ time ruby -v vote.rb.old > /dev/null
7.78s user 0.01s system 99% cpu 7.827 total

$  time ./miniruby -v ../../vote.rb
ruby 1.9.0 (2005-08-19) [i686-linux]
YARVCore 0.3.1 (rev: 254) [opts: [direct threaded code] [optimize basic operation] [stack caching]
[operands unification] [instructions unification] [inline method cache] ]
1.18s user 0.00s system 81% cpu 1.450 total

$ time ./miniruby -v ../../vote.rb.bak
ruby 1.9.0 (2005-08-19) [i686-linux]
YARVCore 0.3.1 (rev: 254) [opts: [direct threaded code] [optimize basic operation] [stack caching]
[operands unification] [instructions unification] [inline method cache] ]
7.34s user 0.00s system 96% cpu 7.577 total

yarv だと違いが顕著だ。

独立同分布じゃないバージョン。

voter = [
  [:jimin,  32518389],
  [:minshu, 24804786],
  [:kome,     981105],
  [:kyosan,  4937375],
  [:shamin,   996007],
  [:kokumin,  432679],
  [:nippon,   137172],
  [:mushozk, 3240521],
]

voter.each{|e| e[1] /= 100 }

seats = {}
voter.each{|e| seats[e[0]] = 0}

sum = 0
voter.each{|e| sum += e[1]}
voter_per_zone = sum / 300

300.times{
  zone = {}
  voter.each{|e| zone[e[0]] = 0}
  
  voter_per_zone.times{
    vote =  rand(sum) + 1
    voter.each{|e|
      if vote <= e[1]
        zone[e[0]] += 1
        e[1] -= 1
        break
      else
        vote -= e[1]
      end
    }
    sum -= 1
  }
  seats[zone.sort{|a, b| a[1] <=> b[1]}[-1][0]] += 1  
}
seats.each{|k, v|
  puts "%7s" % k + ": %4d" % v
}
お名前:
E-mail:
コメント:
本日のリンク元

最近のコメント

2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|04|05|
2011|04|
2012|03|07|
2013|01|02|07|
トップ «前の日記(2005-09-12) 最新 次の日記(2005-09-16)» 編集