ブログが続かないわけ

この日記のはてなブックマーク数
Webエンジニアが思うこと by junichiro on Facebook

[Perl]クラスに同じ誕生日の子供が1組以上いる確率をImager でグラフにする

このエントリーを含むはてなブックマーク hateb
[Perl]クラスに同じ誕生日の子供が1組以上いる確率をImager でグラフにする

クラスの中に同じ誕生日の人がいる確率が、想像以上に高いというところはみんなどこかで聞いたことがあると思う。高校の確率の授業等では、計算をさせられたりすることもある。ただ、実際に手で計算してみると、電卓を使ってもかなり面倒な計算になる。これをPerl で書いてしまえばとても簡単に計算できる。

これを求めるために、簡単な計算の方針を示す。
1. クラスに同じ誕生日の子供が1組も存在しない確率を計算する
2. その逆を計算する(上記の確率を1から引く)

1. を求めるのはそんなに難しくない。
クラスの子供をひとりずつ選び出して、その子がそれまでに選んだ子供と同じ誕生日でない確率を掛け合わせていけばよい。
例えば、1人目の子は誕生日がいつでも良いので、365 / 365 となる。
2人目の子供は、1人目の子供と違う誕生日であればよいので、(365 - 1) / 365
3人目の子供は、1人目と2人目の子供と違う誕生日であればよいので、(365 - 2) / 365
以下同様に、n人目の子供の誕生日は( 365 - (n-1) ) /365 となる。

これらを掛け合わせたものが、クラスに同じ誕生日の子供が1組も存在しない確率となる。
これを1 から引けば、少なくとも1組以上の同じ誕生日の子供が存在することになる。
ここまでわかればこれをコードにすることは簡単だ

クラスの人数を$class_num とした。
sub get_propability {
my $class_num = shift;
my $p = 1;
for ( 1 .. $class_num ) {
$p = $p * ( 365 - ( $_ - 1 ) ) / 365;
}
return 1 - $p;
}
これだけでは面白くないので、クラスの人数の変化とそれに伴う確率の変化をグラフに表現してみる。グラフの描画にはImager を使う。もっとグラフをつくるためのモジュールもあるのだが、最適なものを探すのも面倒だったし、このくらいの簡単な物はImager でも直感的にかけてしまうので、今回はImager しか使わない。

■前半
#!/usr/bin/perl
use strict;
use warnings;
use Imager;

our %scale = ( x => 4, y => 3 );
our %size = (
x => 100 * $scale{x},
y => 100 * $scale{y},
);

my @dot =
map {
[
$_ * $scale{x},
$size{y} - get_propability($_) * 100 * $scale{y},
]
} ( 1 .. 100 );
write_graph(¥@dot);
まず、グラフのスケールとサイズを決める定数を定義する。これはいくつでもいいけど、適当な数値に設定してグラフが奇麗にみえるサイズにした。次に、さっきのget_propability を使ってグラフ上の点を計算して@dot という配列に格納する。Imager で作成する画像は左上が原点で、右方向にxが増加、下方向にyが増加となっているので、そのままグラフにすると都合が悪い。そのため、ちょっと計算して左下が原点、右方向にxが増加、上方向にyが増加するようにしている。得られた点の集合をwrite_graph という関数に渡して、グラフを描画している。

■write_graph
sub write_graph {
my $dot = shift;
my $img = Imager->new(
xsize => $size{x},
ysize => $size{y},
);
$img->box( filled => 1, color => 'skyblue' );
push( @$dot, [ $size{x}, $size{y} ] );
$img->polygon ( points => $dot, color => 'blue' );
$img = write_axis($img);
$img->write( file => 'tutorial.png' );
}
write_axis というのはグラフを見やすくするために、格子状の線を入れている部分だ。本題にはあまり関係ないが、参考までにソースを載せておく。

■write_axis
sub write_axis {
my $img = shift;
for ( 1 .. 9 ) {
$img->line(
color => 'black',
x1 => 10 * $scale{x} * $_,
x2 => 10 * $scale{x} * $_,
y1 => 0,
y2 => $size{y},
aa => 1,
endp => 1
);
$img->line(
color => 'black',
x1 => 0,
x2 => $size{x},
y1 => 10 * $scale{y} * $_,
y2 => 10 * $scale{y} * $_,
aa => 1,
endp => 1
);
}
return $img;
}


■結果


この図では左下が原点、右方向(x軸)がクラスの人数の増加、上方向が同じ誕生日の子がいる確率となっている。数字がふっていないのでわかりにくいが、座標の格子はx軸はクラスの人数が10人単位で引いていて、y軸は確率10%単位で引いている。クラスの人数が40人くらいのときはだいたい90% くらいになっていることがわかると思う。

僕たちが子供の頃は、中学も高校も人クラスの人数が45〜50人だったので、だいたい90%以上の確率で同じ誕生日の子がいたことになる。なるほど、数学の教科書に書いてあることは本当だ。しかし、少子化で1クラスの人数が少なくなってきている昨今では、なかなかそうとも言いがたい結果となっていることがわかる。例えば1クラスの人数が30人くらいだと70%くらいになるし、もし1クラスの人数が20人になってしまうと、40% くらいまで落ち込んでしまう。

まあ、それがどうした。といわれれば、どうもしないんだけど。
この記事のトラックバックURL
http://en.yummy.stripper.jp/trackback/1166556
トラックバック
コメント









関連情報