Line 1: Error: Invalid Blog('by Esehara' )

または私は如何にして心配するのを止めてバグを愛するようになったか

>> Zanmemo

あと何かあれは 「esehara あっと じーめーる」 か @esehara まで

ギャンブラーの錯覚は本当に錯覚なのかどうかをRubyで検証する

今日の料理

f:id:nisemono_san:20160802154059j:plain

食べものに困ったときは、近くの肉屋でハムカツを買ってくればいい[要出典]。

お話

あるところに三人のギャンブラーがいた。この三人は仲が良く、今度カジノに繰りだそうということになった。そのカジノには、三つで一組のスロット台が存在していて、その三つのどれかが当たるような仕組みとなっていた。また、このカジノの売りは、それぞれのスロットを完全に操作せず、ランダムに当たりが出るようにしているということである。

ところで、ギャンブルにはオカルトというか、ある種の信念めいたものが、ギャンブラーにつきまとう。このギャンブラー三人は、それぞれ違った信念を持ちあわせていた。

まず一人目のギャンブラーは、「それぞれの台が完全にランダムに当たりが選ばれるとするならば、次にどの台を選択するかということを悩んでも仕方がない。なので、直感を信じて、台に座るのが正しい」

しかし、二人目のギャンブラーはこの意見に反対だった。「スロットが操作されていないとするならば、最終的にはそれぞれの台の当たりは同程度になる筈だ。とすると、例えば一台目が連続して20回当たるようなことがあれば、一台目が当たる確率は少なくなる筈だ。そう考えると、今までの台の中で一番当たってないものを選ぶのが正しい」

三人目はどちらのギャンブラーの意見にも疑問を抱いていた。「そもそも、二人の意見は余りにも頭でっかち過ぎる。それぞれの台が操作されていなかったとしても、ギャンブルには流れというものが存在している。君が出した、一台目が連続20回当たるのは、一台目に流れが来ているからだ。そのことを考慮に入れるならば、もっとも当っている台に賭けるのが正しい」

さて、この中で一番誰が勝利しただろうか。

議論

これはギャンブラーの錯覚という言葉で良く知られる(ギャンブラーの誤謬とも言う。英語だとGambler's fallacy)として有名である。乱暴に要約してしまえば、「なんらかの事象が起きたときに、その次に同じ事象が起きる確率は低くなる」とする信念のことである。

ギャンブラーの話に出てきたように、例えばコイントスで表が10回連続で起きると、「次は裏が出るのではないか」と不安になるだろう。ちなみに、コイントスで表が10回連続で起きる確率は 1/1024となり、11回目で 1/2048 となる。

とはいえ、そのような連続して何回、ということを考えずに素朴に考えるならば、歪なコインでは無い限り、1/2の確率となる筈である。

確率の世界には、「ある事象とある事象は独立である」という言いかたをする。これは、ある事象(仮にこの事象をAとしよう)が起きた上でのある事象の確率(仮にこの事象をBとする)が、B単体で起きる場合と同等であるときを指す。本来ならば、「ある台が当たった」という条件下では「次に他の台が当たる」確率に影響は及ぼさない筈である。今回の場合、これを疑ってみるというわけだ。

コード

コード自体は至って簡単である。まず最初に、クラス定義を行う。この話において必要なのは、スロットマシンとプレイヤーである。プレイヤーの勝利判定などは共通化できるので、クラスとしてまとめておき、推理ロジックの部分だけ継承してダックタイピングができるように整える。

実験方針としては以下の通り。まず、スロットマシンにどの台が当たったかの統計をまとめておく。次に、プレイヤーは、そのスロットの統計を基準に推理する。当然、一人目のプレイヤーはランダムに選ぶというのを決めているので、統計は無視する。そして、セット数を決め、各プレイヤーには、セットごとの順位でポイントが与えられるようにする。セットのはじめには、勝利数はリセットされるようにする。

class SlotMachine
  attr_accessor :win
  attr_accessor :win_static

  def initialize
    @win = {}
    @win_static = {0 => 0, 1 => 0, 2 => 0}
  end

  def set_win!
    @win = Random.rand(3)
    @win_static[@win] += 1
  end

  def sort_win
    win_static.sort {|(a1, a2), (b1, b2)| a2 <=> b2}
  end
end

class Player
  attr_accessor :win
  attr_accessor :point

  def initialize
    @win = 0
    @point = 0
  end

  def win? machine
    @guess == machine.win
  end

  def win_or_lose machine
    @win += 1 if win? machine
  end

  def result
    puts "Player Win: #{win}"
  end
end

class SimplePlayer < Player
  def guess machine
    @guess = Random.rand(3)
  end
end

class LeastGuessPlayer < Player
  def guess machine
    @guess = (machine.sort_win)[0][0]
  end
end

class MostGuessPlayer < Player
  def guess machine
    @guess = (machine.sort_win)[-1][0]
  end
end

で、実際に試行するコードは以下の通り。

simple_player = SimplePlayer.new
least_player = LeastGuessPlayer.new
most_player = MostGuessPlayer.new
players = [simple_player, least_player, most_player]

slot = SlotMachine.new
1.upto(1000) do
  players.each { |player| player.win = 0 }
  1.upto(1000) do
    slot.set_win!
    players.each do |player|
      player.guess slot
      player.win_or_lose slot
    end
  end
  players.sort! { |p1, p2| p1.win <=> p2.win }
  players[0].point += 2
  players[1].point += 1
  players[2].point += 0
end

puts "==========================="
puts "Result:"
players.each { |player| puts "#{player.class}: #{player.point}" }
puts "==========================="

結論

結論から言わせてもらうと、特に明確な誤差は出なかった。時々によって、誰が勝利するかというのはあるけれども、だいたいプラスマイナス50の範囲で収まっているし、試行によって、どのプレイヤーが勝利するかということに関しては、まちまちであったと言える(逆に言うならば、どのプレイヤーも同等に勝利している)。これは多くの読者が想像していた通りの結果だろう。

この実験によって、ギャンブラーの錯覚が錯覚であることがわかったわけだけども、しかし、ギャンブルというのは統計だけではなく、良くわからない「流れ」とか「ツキ」とかを信じるほうが人間味も増すし、楽しみも増すことは、恐らく間違いない。もし、どの信念を採用しようとも、それが勝利とさほど関係ないとするならば、自分の好きな信念を持ってしてギャンブルするというのは、一つのやりかたであるのかもしれない。

また、直感と確率論的に齟齬が生じるモンティ・ホール問題というものもある。過去にそのことについて言及した記事があるので、興味のある方は参考にして欲しい。

参考文献

確率論入門 (ちくま学芸文庫)

確率論入門 (ちくま学芸文庫)

また、実際のゲームで統計的なアプローチを取っているものとして、下のような本があるらしい(自分は未読である)。

科学する麻雀 (講談社現代新書)

科学する麻雀 (講談社現代新書)