28人中にB型が3名以下になる確率
Rに苦戦中にて候 - ときどきの雑記帖 i戦士篇 を読んで R の練習にちょうど良さそうだな…とチャレンジしてみようと思ったのですが、その前にとりあえず Squeak Smalltalk を使ってオーソドックスに。
| 血液型群 B型が三名以下 試行回数 bag | 血液型群 := RunArray runs: #(4 3 2 1) values: #(A O B AB). B型が三名以下 := 0. 試行回数 := 100000. bag := (1 to: 28) asBag. 試行回数 timesRepeat: [ ((bag collect: [:each | 血液型群 atRandom]) occurrencesOf: #B) <= 3 ifTrue: [B型が三名以下 := B型が三名以下 + 1]]. B型が三名以下 / 試行回数 * 100.0 "=> 16.062 % "
あくまで候補のB型の割合がおかしなことになっていないという前提ですが。^^;
直接求める方法はないものかと、Wikipedia を眺めていたらこんなのを見つけました。
全住民の5%がある感染症に罹患しており、その中から無作為に500人を抽出する。このとき、抽出された集団の中に罹患者が30人以上いる確率はどれくらいか。
二項分布 - Wikipedia
これを適当に置き換えて、
28人を無作為に抽出したとき、B型の人が3名以下になる確率を求めよ。
同じく Squeak Smalltalk でこの確率を計算してみると約16%と似たような値が出たのであっているっぽいですね。
(3 to: 0 by: -1) inject: 0 into: [:sum :each | sum + ((28 take: each) * (0.2 raisedTo: each) * (1 - 0.2 raisedTo: 28 - each) asFloat)] "=> 0.1601826710989386 "
では、R でもシミュレーションを…と思ったのですが時間切れなので後ほど。
追記:
…ということで R で書いてみました。新しく runif、table、factor を覚えました。
xs <- array(runif(28)) p2b <- function(x) if (x>=0.6) "A" else if (x>=0.3) "O" else if (x>=0.1) "B" else "AB" bs <- function(x) table(factor(mapply(p2b,runif(28)),levels=c("A","O","B","AB")))["B"] n <- 10000 table(mapply(bs, 1:n) <= 3)["TRUE"] / n #=> 0.1642
ついでに Smalltalk のを Ruby に書き換えた版も。
btypes = [4,3,2,1].zip(["A","O","B","AB"]).collect{ |n,t| [t]*n }.flatten count = 0 n = 10000 n.times{ count += 1 if ((1..28).collect{ |e| btypes.sample }).count("B") <= 3 } count.to_f / n #=> 0.1577