Quantcast
Channel: 円周率近似値の日に生まれて理系じゃないわけないだろ! - knifeのblog
Viewing all articles
Browse latest Browse all 5376

日本人の血液型の割合

$
0
0

午後のひとときに、日本人の血液型の割合について、ちょっと計算をしてみました。

日本人の血液型の割合は、A型が40%、O型が30%、B型が20%、AB型が10%と言っても、
概ね許容範囲とされている。

現実には、数パーセントの前後の揺れはあるかとは思うが、概算で使うならば十分だし、覚えやすいという点もある。

そこで、ちょっとした疑問が湧いてきたのですが、これは血液型の表現型であって、遺伝子型ではどうなっているのだろうか?

簡単に言えば、AA型とAO型、BB型とBO型と、それぞれ分けたら、それぞれの比はどのくらいなのだろうか?

ということが気になりました。

仮に、遺伝子型での血液型の割合が解っていたとして、均等に交配がなされたとしたら、どういう計算式になるのか?ということは立式できそうです。

現実では、子どもが生まれるまでに約1年が掛かるし、均等に交配するというようなことはありませんし、子どもを産む年齢もまちまちなのですが、それぞれを世代ということで分けて考えます。

左辺が次世代、右辺が現世代の割合として、
AA=(AA+AO/2+AB/2)2
BB=(BB+BO/2+AB/2)2
OO=(OO+AO/2+BO/2)2
AO=2(AA+AO/2+AB/2)(OO+AO/2+BO/2)
BO=2(BB+BO/2+AB/2)(OO+AO/2+BO/2)
AB=2(AA+AO/2+AB/2)(BB+BO/2+AB/2)
AA+AO+BB+BO+OO+AB=1
のように立式することが出来ます。

遺伝子型の2つの文字を見て、それを含む割合を加算して、それぞれを掛けるということで、それほど難しいことはしていません。

また、それぞれの割合の合計を1としておくのも忘れずに。


さて、この計算式を使って、現世代、次世代、次次世代、…と血液型の割合の変化が見られるかとは思うのですが、次世代以降はまったく変化が無くなるということが解ります。

これを、ハーディー・ワインベルクの法則というそうです。

 


同じ計算を何回も反復するならば、プログラムするのが手っ取り早いですね。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[])
{
    double aa,ao,bb,bo,oo,ab;
    double aa2,ao2,bb2,bo2,oo2,ab2;
    double total;
    int i;

    if ( argc == 7 ) {
        aa = atof(argv[1]);
        ao = atof(argv[2]);
        bb = atof(argv[3]);
        bo = atof(argv[4]);
        oo = atof(argv[5]);
        ab = atof(argv[6]);
        total = aa+ao+bb+bo+oo+ab;
        aa /= total;
        ao /= total;
        bb /= total;
        bo /= total;
        oo /= total;
        ab /= total;
    } else {
        aa = 0.09;
        ao = 0.31;
        bb = 0.02;
        bo = 0.18;
        oo = 0.30;
        ab = 0.10;
    }
    printf("AA:%.10f AO:%.10f BB:%.10f BO:%.10f OO:%.10f AB:%.10f\n",aa,ao,bb,bo,oo,ab);

    for (i=0; i<10; i++) {
        aa2 = (aa+ao/2.0+ab/2.0)*(aa+ao/2.0+ab/2.0);
        bb2 = (bb+bo/2.0+ab/2.0)*(bb+bo/2.0+ab/2.0);
        oo2 = (oo+ao/2.0+bo/2.0)*(oo+ao/2.0+bo/2.0);
        ao2 = 2.0*(aa+ao/2.0+ab/2.0)*(oo+ao/2.0+bo/2.0);
        bo2 = 2.0*(bb+bo/2.0+ab/2.0)*(oo+ao/2.0+bo/2.0);
        ab2 = 2.0*(aa+ao/2.0+ab/2.0)*(bb+bo/2.0+ab/2.0);
        aa = aa2;
        ao = ao2;
        bb = bb2;
        bo = bo2;
        oo = oo2;
        ab = ab2;
        total = aa+ao+bb+bo+oo+ab;
        aa /= total;
        ao /= total;
        bb /= total;
        bo /= total;
        oo /= total;
        ab /= total;
        printf("AA:%.10f AO:%.10f BB:%.10f BO:%.10f OO:%.10f AB:%.10f\n",aa,ao,bb,bo,oo,ab);
    }

    return EXIT_SUCCESS;
}

> aboab
AA:0.0900000000 AO:0.3100000000 BB:0.0200000000 BO:0.1800000000 OO:0.3000000000 AB:0.1000000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000
AA:0.0870250000 AO:0.3215500000 BB:0.0256000000 BO:0.1744000000 OO:0.2970250000 AB:0.0944000000

パラメーター無しで、日本人の血液型の割合に近いざっとした値をデフォルト値にして計算しています。

1行目と2行目は値がことなりますが、2行目以降も同じ計算をしているのですが、まったく同じ値になっていますね。

パラメーターに、AA AO BB BO OO ABの順番に割合を自然数または正の小数で与えるだけで、割合の合計がどんな値であろうとも、与えられた比の通りで合計が1になるように調整しています。

AA:0.087025
AO:0.321550
BB:0.025600
BO:0.174400
OO:0.297025
AB:0.094400
を表現型にするため、それぞれを足し算すると、
A:0.408575≒40%
B:0.200000=20%
O:0.297025≒30%
AB:0.094400≒10%
と言っても遜色のない値となっていますね。

このプログラムを使えば、パラメーターを適当に与えることで、次世代以降の比率が解るということですね。


さて、この計算式は次世代以降を計算できるのですが、過去に遡るにはどうすればいいのでしょうか?

簡単にいうと、n世代の値を入れたら、n-1世代の値が返ってくるということですね。

どうすれば良いのかは想像できます。

それは、行列式で逆行列を求めて、逆行列にn世代の値を入れて、n-1世代をの値を返せばよい。

とりあえず、行列式は別の記事としましょうか。


ではでは

 

 


Viewing all articles
Browse latest Browse all 5376

Trending Articles