Skip to article frontmatterSkip to article content

06-02 ランダムウォーク,ライト-フィッシャー モデル

待ち時間,ランダムウォーク

02-01. サイコロの目の総和が100を超えるまでの待ち時間

# 02-01. サイコロの目の総和が100を超えるまでの待ち時間
import random
x = 0
for i in range(100):
    r = random.randrange(1, 7)
    x = x + r
    print(str(i + 1) + "回目:", x)
    if x >= 100:
        print(str(i + 1) + "回目で100を超えた.")
        break
1回目: 4
2回目: 10
3回目: 12
4回目: 18
5回目: 19
6回目: 23
7回目: 26
8回目: 28
9回目: 32
10回目: 35
11回目: 36
12回目: 39
13回目: 44
14回目: 48
15回目: 54
16回目: 57
17回目: 60
18回目: 65
19回目: 68
20回目: 70
21回目: 73
22回目: 76
23回目: 82
24回目: 88
25回目: 89
26回目: 90
27回目: 93
28回目: 95
29回目: 100
29回目で100を超えた.

02-02a. ランダムウォーク choice

# 02-02a. ランダムウォーク choice
x = 0
x_list = [x]
for i in range(100):
    r = random.choice([-1, 1])
    x = x + r
    x_list.append(x)
import matplotlib.pyplot as plt
plt.plot(x_list)
<Figure size 640x480 with 1 Axes>

02-02b ランダムウォーク randrange

# 02-02b ランダムウォーク randrange
x = 0
x_list = [x]
for i in range(100):
    r = random.randrange(-1, 2, 2)
    x = x + r
    x_list.append(x)
plt.plot(x_list)
<Figure size 640x480 with 1 Axes>

02-03. ランダムウォークの待ち時間

# 02-03. ランダムウォークの待ち時間
x = 0
x_list = [x]
for i in range(10000):
    r = random.choice([-1, 1])
    x = x + r
    x_list.append(x)
    if x >= 10:
        break
print("待ち時間:", len(x_list) - 1)
待ち時間: 48
plt.plot(x_list)
<Figure size 640x480 with 1 Axes>

ライトフィッシャー モデル

02-04. ライト-フィッシャー モデル

# 02-04. ライト-フィッシャー モデル
pop_size = 100
gen_end = 200

# aの初期値の設定
a = []
for i in range(pop_size):
    if i % 2 == 0:
        a.append(0)
    else:
        a.append(1)

a_list = [a.copy()]

for t in range(gen_end):
    # a_newの初期化
    a_new = []

    for i in range(pop_size):
        p1 = random.randrange(pop_size)
        p2 = random.randrange(pop_size)
        r = random.choice([a[p1], a[p2]])
        a_new.append(r)

    a = a_new.copy()
    a_list.append(a.copy())
# 結果の表示
for a in a_list:
    print(a)
Fetching long content....

02-05. matshowによる可視化

# 02-05. matshowによる可視化
plt.matshow(a_list, interpolation=None, vmin=0, vmax=1)
plt.ylabel("generation")
<Figure size 400x804 with 1 Axes>

02-06. 頻度の世代を経た変化

# 02-06. 頻度の世代を経た変化
p_list = []
q_list = []
for a in a_list:
    p = sum(a) / len(a)
    p_list.append(p)
    q_list.append(1 - p)
plt.plot(p_list, "-", q_list, "-")
<Figure size 640x480 with 1 Axes>

リストのコピー

問題にならないケース

# 問題にならないケース
a_list = []
for i in range(10):
    a = [i, i, i]
    a_list.append(a)

print(a_list)
[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4], [5, 5, 5], [6, 6, 6], [7, 7, 7], [8, 8, 8], [9, 9, 9]]

問題になるケース

# 問題になるケース
a_list = []
a = [0, 0, 0]
for i in range(10):
    for j in range(3):
        a[j] = i
    a_list.append(a)

print(a_list)
[[9, 9, 9], [9, 9, 9], [9, 9, 9], [9, 9, 9], [9, 9, 9], [9, 9, 9], [9, 9, 9], [9, 9, 9], [9, 9, 9], [9, 9, 9]]

修正

# 修正
a_list = []
a = [0, 0, 0]
for i in range(10):
    for j in range(3):
        a[j] = i
    a_list.append(a.copy())

print(a_list)
[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4], [5, 5, 5], [6, 6, 6], [7, 7, 7], [8, 8, 8], [9, 9, 9]]

突然変異固定までの待ち時間

02-07. 突然変異固定までの平均待ち時間を10回分について計算してみよう

Solution to Exercise 1

例は以下の通り.

# 待ち時間
num_trials = 10
pop_size = 100
init_num_target = int(pop_size / 2)

waiting_time = []
for n in range(1000):
    a = []
    for i in range(pop_size):
        if i < init_num_target:
            a.append(0)
        else:
            a.append(1)

    a_list = [a.copy()]
    for t in range(100000):
        a_new = []

        for i in range(pop_size):
            p1 = random.randrange(pop_size)
            p2 = random.randrange(pop_size)
            r = random.choice([a[p1], a[p2]])
            a_new.append(r)

        a = a_new.copy()
        a_list.append(a.copy())
        if (sum(a) == 0 or sum(a) == pop_size):
            break

    if sum(a_list[-1]) == 0 or sum(a_list[-1]) == pop_size:
        waiting_time.append(len(a_list))
    if len(waiting_time) >= num_trials:
        break
# 平均待ち時間
sum(waiting_time) / len(waiting_time)
148.2

関数を使うと,見通しが良くなる. 別の例は以下の通り.

def wright_fisher_Model(pop_size, gen_end, init_num_target, extinct_break=False):
    """Wright-Fisher model

    ハプロタイプを仮定したライト-フィッシャーモデルに基づく遺伝的浮動.

    Args:
        pop_size: 集団サイズ
        gen_end: 最終世代
        init_num_target: 注目している遺伝子型の初期数
        extinct_break: どちらかの遺伝子型が絶滅した場合に処理を中断するか

    Returns:
        a_list: 各世代の遺伝子型を記録したリスト

    """
    if pop_size < init_num_target:
        print(
            "注目する遺伝子型の初期値`init_num_target`は集団サイズ`pop_size`以下でなければならない."
        )
        return

    a = []

    for i in range(pop_size):
        if i < init_num_target:
            a.append(0)
        else:
            a.append(1)

    a_list = [a.copy()]
    for t in range(gen_end):
        a_new = []
        for i in range(pop_size):
            p1 = random.randrange(pop_size)
            p2 = random.randrange(pop_size)
            r = random.choice([a[p1], a[p2]])
            a_new.append(r)
        a = a_new.copy()
        a_list.append(a.copy())

        if ((sum(a) == pop_size) or (sum(a) == 0)) and extinct_break:
            break

    return a_list
# 待ち時間
num_trials = 10
pop_size = 100
init_num_target = int(pop_size / 2)

waiting_time = []
for n in range(1000):
    a_list = wright_fisher_Model(pop_size, 100000, init_num_target, extinct_break=True)
    if sum(a_list[-1]) == 0 or sum(a_list[-1]) == pop_size:
        waiting_time.append(len(a_list))
    if len(waiting_time) >= num_trials:
        break
# 平均待ち時間
sum(waiting_time) / len(waiting_time)
149.0