集団の進化をPython を用いてシミュレーションしてみる。 第2回。
先日からPythonの勉強を兼ねて、孤独なミュータント問題の進化の形質の伝播をシミュレートするということに取り組んでいる。
今回、違う形での可視化に挑戦している。
具体的には、散布図的な表現ではなく、ピクセルのような形で可視化をしている。
実際に書いたコードがこちら。
# 必要なライブラリのインポート
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import random
# 初期設定
# Parameters
population_size = 1000
generations = 30
survival_rate = 0.5
trait_propagation_probability = 0.5
max_trials = 50 # Number of trials to simulate
# 個体群の初期化(0: 形質を持たない個体, 1: 形質を持つ個体, -1: 死んだ個体)
population = np.zeros(population_size) # 全ての個体は最初形質を持たない
# 形質を持つ個体の初期設定
# ケース1: 1個体のみ形質を持つ
population[0] = 1
# ケース2: ランダムな2個体が形質を持つ
population[random.sample(range(population_size), 2)] = 1
# 2次元空間での個体群の初期配置
# 個体群の位置をランダムに生成(0から1の範囲内)
positions = np.random.rand(population_size, 2)
# 形質の伝播と可視化のための修正されたコードをここに実装します。
# 各世代の状態を保存するリストを再初期化
generation_states = [population.copy()]
def simulate_trait_spread_with_trials(population_size, generations, survival_rate, trait_propagation_probability, max_trials):
side_length = int(np.sqrt(population_size))
trial_results = []
for trial in range(1, max_trials + 1):
grid = np.zeros((side_length, side_length))
first_trait_x, first_trait_y = np.random.randint(0, side_length, size=2)
grid[first_trait_x, first_trait_y] = 1 # Initialize the first trait-bearing individual
generation_states = [grid.copy()]
for gen in range(1, generations + 1):
new_grid = np.zeros_like(grid)
trait_exist = False
for x in range(side_length):
for y in range(side_length):
if grid[x, y] == 1 and np.random.rand() < survival_rate:
trait_exist = True
new_grid[x, y] = 1 # The individual survives
# Propagate the trait to adjacent individuals
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
nx, ny = x + dx, y + dy
if 0 <= nx < side_length and 0 <= ny < side_length:
if np.random.rand() < trait_propagation_probability:
new_grid[nx, ny] = 1
if not trait_exist: # All trait-bearing individuals have perished
break
grid = new_grid
generation_states.append(grid.copy())
trial_results.append((generation_states, (first_trait_x, first_trait_y)))
return trial_results
import matplotlib.pyplot as plt
import os
def visualize_and_save_generation_process(trial_results, side_length, output_dir="simulation_results"):
if not os.path.exists(output_dir):
os.makedirs(output_dir)
for trial, (generation_states, first_trait_pos) in enumerate(trial_results, start=1):
for gen, state in enumerate(generation_states):
plt.figure(figsize=(8, 8))
display_grid = np.full((side_length, side_length, 3), [0.75, 0.75, 0.75]) # Default color
for x in range(side_length):
for y in range(side_length):
if state[x, y] == 1:
color = [1.0, 0.0, 0.0] if (x, y) == first_trait_pos and gen == 0 else [1.0, 1.0, 0.0]
display_grid[x, y] = color
plt.imshow(display_grid, interpolation='nearest')
plt.title(f"Trial {trial} - Generation {gen}")
plt.axis('off')
filename = f"trial_{trial}_gen_{gen}.png"
plt.savefig(os.path.join(output_dir, filename))
plt.close() # Close the figure to free up memory
import imageio
def create_gif_from_pngs(png_directory, output_gif_path, duration=0.5):
# ディレクトリ内の全PNGファイルを取得
png_files = sorted([f for f in os.listdir(png_directory) if f.endswith('.png')],
key=lambda x: (int(x.split('_')[1]), int(x.split('_')[3].split('.')[0])))
images = [imageio.imread(os.path.join(png_directory, f)) for f in png_files]
# 画像リストをGIFとして保存
imageio.mimsave(output_gif_path, images, duration=duration)
# Simulation and visualization
population_size = 1000
generations = 30
survival_rate = 0.5
trait_propagation_probability = 0.5
max_trials = 30 # Adjust based on your requirements
trial_results = simulate_trait_spread_with_trials(population_size, generations, survival_rate, trait_propagation_probability, max_trials)
visualize_and_save_generation_process(trial_results, int(np.sqrt(population_size)))
# GIFアニメーションの作成
create_gif_from_pngs("simulation_results", "simulation_animation.gif", duration=0.5)
想定した内容としてはまず1個体が形質を獲得するが、その個体の生存確率は50%としている。
つまり、形質を獲得してもそれが伝播する前に死んでしまうと仮定している。
実際に出来上がったものがこちら。