集団の進化をPython を用いてシミュレーションしてみる。
先日、孤独なミュータントの問題の投稿の中で下記のように記した。
進化と言うものを改めて考えてみたい。 進化とは集団内のある1個体が突然変異を起こし、 それが適応的であった場合にその形質が集団内で、少しずつ広がっていくと言う過程をたどる。
この広がり具合をシミュレーションしてみたいと思い、ChatGPTを使いながらPython でコードを書いてみた。
すると、形質の広がり方がわかりやすいアニメーションがかけたので、ここに備忘として残しておきたい。(もちろんこのアニメーションは簡易的なもので、いくらでも深掘りはできるが、一旦試しとしては十分かと考えたので残しておく。)
興味がある人は、Google Colabolatory等で簡単に実施ができるので、ぜひ試していただきたい。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
# パラメータ設定
num_points = 1000 # 空間内の点の総数
influence_radius = 0.1 # 突然変異が影響を及ぼす半径
steps = 30 # アニメーションの総ステップ数(世代数)
# 点の初期配置(2次元空間内)
# 点をランダムに配置することで、初期集団を生成します。
points = np.random.rand(num_points, 2)
# 突然変異を持つ点の選択(最初の点)
# 最初に突然変異を持つ点をランダムに1つ選択します。
mutation_index = np.random.choice(num_points)
mutations = np.zeros(num_points, dtype=bool) # 突然変異の有無を追跡するための配列
mutations[mutation_index] = True # 選択された点に突然変異を割り当てる
# 図と軸の設定
fig, ax = plt.subplots()
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
scat = ax.scatter(points[:, 0], points[:, 1], c='gray', alpha=0.6) # 初期の点をプロット
def update(frame):
"""アニメーションの各フレームを更新する関数"""
global mutations
new_mutations = mutations.copy() # 現在の突然変異状態をコピー
for i in range(num_points):
if mutations[i]: # 既に突然変異を持つ点はスキップ
continue
# 現在の点から既存の突然変異点までの距離を計算
distance = np.sqrt((points[i, 0] - points[mutations, 0])**2 + (points[i, 1] - points[mutations, 1])**2)
# 距離が影響半径以内にあれば、新たに突然変異を獲得
if np.any(distance < influence_radius):
new_mutations[i] = True
mutations[:] = new_mutations # 突然変異状態を更新
# 突然変異を持つ点は青色で、そうでない点は灰色で表示する
colors = ['blue' if m else 'gray' for m in mutations]
scat.set_color(colors)
return scat,
# アニメーションの生成
ani = FuncAnimation(fig, update, frames=np.arange(steps), blit=True, repeat=False)
# GIFとして保存
writer = PillowWriter(fps=2) # アニメーションのフレームレートを指定
ani.save("mutation_spread_simulation.gif", writer=writer)
出力結果はこちらだ。
灰色の点はまだ新しい形質を獲得していない個体、青色の点は新しい形質を獲得した個体である。 アニメーションは新しい形質を獲得した個体が増えていく様子を示している。