読者です 読者をやめる 読者になる 読者になる

日記とか、工作記録とか

自分に書けることを何でも書いてゆきます。作った物、買ったもの、コンピュータ系の話題が多くなるかもしれません。

血液型の遺伝をVisualBasicでシミュレートしてみよう

VB.NET基礎学習Bible―270例題で学ぶプログラミングの散歩道

VB.NET基礎学習Bible―270例題で学ぶプログラミングの散歩道

「メンデルの法則」という遺伝に関係する言葉があって、例えば人間の血液型は、親から子へと伝わるわけです。

日本人にはA型が多いと言われますが、何世代にもわたって世代交代が行われてきたのに、特定の血液型がなくなってしまわないのは不思議なことだなぁと直感的に思いました。試しにこれをシミュレートしてみようと思います。

今回はプログラミング言語Visual Basicを使ってみます。具体的には、やりたいことは以下の通りです。

  • 最初にヒト(を模したデータ)をたくさん用意します。これを第一世代と呼ぶことにします。
  • ヒトは血液型のもとになるA, B, Oの遺伝型を持っています。
  • ひとりのヒトに遺伝型は2つあります。つまり、AA, AB, AO, BA, BB, BO, OA, OB, OOの9種類があるうることになります。それぞれ、血液型としては、A型, AB型, A型, AB型, B型, B型, A型, B型, O型です。ランダムに遺伝型を決めると、O型は9人にひとりの確率でしかならないことになります。
  • 第一世代のヒトがどの遺伝型を持つかは、ランダムで決めます。
  • ヒトを掛け合わせます。総人口が増減しないように、2人のヒトから2人のヒトが生まれることにします。第一世代を掛け合わせたヒトを第二世代と呼びます。第N世代の次はもちろん第N+1世代と呼びます。
  • 世代を次々に交代させて、それぞれの血液型をもつ人数がどのように変化するか観察します。
  • 便宜上、男性と女性の区別は作りません。

というわけでガリガリ書いてみたソースコードが以下の通り。
なるべく直感的に読みやすいように日本語をふんだんに使ってみました。

GUIにTextBoxを配置してあり、これの名前が「出力」です。TextBoxをマウスクリックすると計算が始まります。
世代数に設定した数だけ、実験を繰り返します。
一世代の人数は、人口という定数に設定します。

Public Class コンソール

    Private Sub TextBox1_Click(sender As Object, e As EventArgs) Handles 出力.Click
        Const 世代数 As Integer = 3000
        Const 人口 As Integer = 10000

        Dim 旧世代 As 世代
        Dim 新世代 As 世代

        旧世代 = New 世代(人口)
        旧世代.人々を初期化()
        出力.AppendText(旧世代.統計を発表する & vbCrLf)
        旧世代.人々をシャッフル(人口 * 10)

        For index = 1 To 世代数 - 1
            新世代 = New 世代(旧世代)
            出力.AppendText(String.Format("{0,4}代:", index) & 新世代.統計を発表する & vbCrLf)
            新世代.人々をシャッフル(人口 * 10)
            旧世代 = 新世代
        Next
    End Sub

    Class 世代
        Public 人々 As ヒト()

        Dim A型 As Integer = 0
        Dim B型 As Integer = 0
        Dim O型 As Integer = 0
        Dim AB型 As Integer = 0

        Sub New(人数 As Integer)
            '人数は偶数が扱いやすいので調整
            If 人数 Mod 2 = 1 Then
                ReDim 人々(人数)
            Else
                ReDim 人々(人数 - 1)
            End If
        End Sub

        Sub New(旧世代 As 世代)
            '世代間で人口は変わらないことにする
            ReDim 人々(旧世代.人々.Length - 1)

            For index = 0 To 人々.Length - 2 Step 2
                For index2 = 0 To 1
                    人々(index + index2) = New ヒト
                    '両親からひとつずつ遺伝型をもらう
                    人々(index + index2).slot0 = 旧世代.人々(index).遺伝型を選ぶ
                    人々(index + index2).slot1 = 旧世代.人々(index + 1).遺伝型を選ぶ
                    Select Case 人々(index + index2).血液型を教える
                        Case 血液型.A
                            A型 += 1
                        Case 血液型.B
                            B型 += 1
                        Case 血液型.O
                            O型 += 1
                        Case 血液型.AB
                            AB型 += 1
                    End Select
                Next
            Next
        End Sub

        Sub 人々を初期化()
            Dim r As New System.Random()
            For index = 0 To 人々.Length - 1
                人々(index) = New ヒト()
                人々(index).slot0 = r.Next(3)
                人々(index).slot1 = r.Next(3)
                Select Case 人々(index).血液型を教える
                    Case 血液型.A
                        A型 += 1
                    Case 血液型.B
                        B型 += 1
                    Case 血液型.O
                        O型 += 1
                    Case 血液型.AB
                        AB型 += 1
                End Select
            Next
        End Sub

        Sub 人々をシャッフル(回数 As Integer)
            Dim r As New System.Random()
            DimAs ヒト
            For index = 0 To 回数
                Dim a As Integer = r.Next(人々.Length)
                Dim b As Integer = r.Next(人々.Length)= 人々(a)
                人々(a) = 人々(b)
                人々(b) =Next
        End Sub

        Function 統計を発表する() As String
            Return String.Format("全部で{0,5}人⇒A型:{1,4} B型:{2,4}, O型{3,4}, AB型{4,4}", 人々.Length, A型, B型, O型, AB型)
        End Function
    End Class

    Class ヒト
        Dim r As New System.Random()
        Property slot0 As 遺伝型
        Property slot1 As 遺伝型

        Function 遺伝型を選ぶ() As 遺伝型
            If r.Next(2) = 0 Then
                Return slot0
            Else
                Return slot1
            End If
        End Function

        Function 血液型を教える() As 血液型
            Select Case slot0
                Case 遺伝型.A
                    Select Case slot1
                        Case 遺伝型.A
                            Return 血液型.A
                        Case 遺伝型.B
                            Return 血液型.AB
                        Case 遺伝型.O
                            Return 血液型.A
                    End Select
                Case 遺伝型.B
                    Select Case slot1
                        Case 遺伝型.A
                            Return 血液型.AB
                        Case 遺伝型.B
                            Return 血液型.B
                        Case 遺伝型.O
                            Return 血液型.B
                    End Select
                Case 遺伝型.O
                    Select Case slot1
                        Case 遺伝型.A
                            Return 血液型.A
                        Case 遺伝型.B
                            Return 血液型.B
                        Case 遺伝型.O
                            Return 血液型.O
                    End Select
            End Select
            Return Nothing
        End Function
    End Class

    Enum 遺伝型
        A = 0
        B = 1
        O = 2
    End Enum

    Enum 血液型
        A = 0
        B = 1
        O = 2
        AB = 3
    End Enum
End Class

このプログラム(一世代一万人、3000世代)を10回実行して、結果を見てみました。

2999代:全部で10000人⇒A型:1646 B型:5056, O型 294, AB型3004
2999代:全部で10000人⇒A型:5810 B型: 802, O型 42, AB型3346
2999代:全部で10000人⇒A型:3188 B型:3438, O型1174, AB型2200
2999代:全部で10000人⇒A型:3895 B型:2632, O型1902, AB型1571
2999代:全部で10000人⇒A型:4739 B型:2137, O型1398, AB型1726
2999代:全部で10000人⇒A型:5823 B型:1316, O型1619, AB型1242
2999代:全部で10000人⇒A型:4102 B型:2429, O型1861, AB型1608
2999代:全部で10000人⇒A型:2927 B型:2378, O型3995, AB型 700
2999代:全部で10000人⇒A型:3204 B型:3466, O型1460, AB型1870
2999代:全部で10000人⇒A型:1474 B型:5583, O型 590, AB型2353
2999代:全部で10000人⇒A型:5608 B型:1256, O型 232, AB型2904

もちろん試行ごとにばらつきはあるわけなんですが、この範囲では0になってしまう場合はありませんでした。O型の発現率が低いとは言っても、遺伝型としてはなくなるわけではないので、A型やB型のヒトのなかにOの遺伝型を持っている人は一定の割合で存在するわけです。参考になるでしょうか。