模拟羊与兔种群模型 (Python)

huangapple go评论73阅读模式
英文:

Modelling a Sheep vs Rabbit population simulation (Python)

问题

我试图模拟羊和兔的种群,使用以下规则:

  1. 如果两种不同物种的动物在nside方格上的同一个方块上相遇,有可能它们都不死、都死亡,或者其中一个死亡。
  2. 如果同种物种的动物在一个方块上相遇,就有机会(概率类似于上面的情况)产生一个新的幼崽。

在下一个时间步中,存活的动物可以向左、向右、向上或向下移动。

我的问题是,在我的模型中,两种物种都在呈指数增长,我不确定如何解决这个问题。

我尝试过的方法是检查每一对动物。如果这对动物不包含死亡的动物,然后使用if-else条件来评估它们是否应该诞生新的动物或死亡。请注意,我的代码中的nsides代表网格的大小。我还将我的动物类命名为People2,因为它是从以前的代码中改编的。

# 测试不同的if/else函数

import numpy as np

class People2:  # 动物类
    def __init__(self, status, species, nsides=40):
        self.nsides = nsides
        self.location = np.random.randint(0, self.nsides, [2])
        self.status = status
        self.species = species

    def move(self):  # 移动动物,上下左右随机
        moves = np.random.randint(-1, 2, [2])
        self.location[0] = (self.location[0] + moves[0]) % self.nsides
        self.location[1] = (self.location[1] + moves[1]) % self.nsides

class World2:
    def __init__(self, time=0, maxtime=1000, nsides=40, npeople=2, nprob=0.9):
        self.npeople = npeople
        self.nprob = nprob
        self.nsides = nsides
        self.rabbits = []
        self.sheep = []
        self.time = 0
        self.maxtime = 1000
        
        for i in range(self.npeople):
            if i % 2 == 0:
                self.rabbits.append(People2(status=1, species='R', nsides=nsides))  # 生病的兔子
            else:
                self.sheep.append(People2(status=1, species='S', nsides=nsides))  # 健康的羊

        self.people = self.rabbits + self.sheep
        
    def movement(self):
        self.to_remove = []
        self.compare = []
        new = []

        # 伪代码
        self.a_list2 = list(enumerate(self.people))
        self.anim_combined = list(itertools.combinations(self.a_list2, 2))

        for r, s in self.anim_combined:
            if r[1].status != 0 and s[1].status != 0:
                if np.all(r[1].location == s[1].location):
                    if r[1].species != s[1].species:
                        r_prob, s_prob = np.random.choice([0, 1], p=[self.nprob, 1 - self.nprob], size=2)
                        if r_prob == 1:
                            pass
                        else:
                            r[1].status = 0
                        if s_prob == 1:
                            pass
                        else:
                            s[1].status = 0
                    else:
                        if r[1].species == s[1].species:
                            repro_prob = np.random.choice([1, 0], p=[self.nprob, 1 - self.nprob])
                            if repro_prob == 0:
                                pass
                            else:
                                if repro_prob == 1:
                                    new.append(People2(status=1, species=r[1].species, nsides=self.nsides))

        unique_elements = list(itertools.chain.from_iterable(self.anim_combined))
        not_killed = [index_and_animal[1] for index_and_animal in unique_elements if index_and_animal[1].status == 1]

        self.people.extend(new)
        self.people.extend(list(set(not_killed)))
        
        self.time += 1

        for animal in self.people:
            animal.move()

        return self.people

# 迭代4天
anim_world = World2()
rabbit_len = []
sheep_len = []

for _ in range(4):
    rabbit_count = 0
    sheep_count = 0

    for animal in anim_world.movement():
        if animal.species == "R":
            rabbit_count += 1
        elif animal.species == "S":
            sheep_count += 1

    rabbit_len.append(rabbit_count)
    sheep_len.append(sheep_count)

如果我能看到它们为什么呈指数增长以及为什么一些不同物种的动物没有被杀死,那将非常好。提前感谢您!

英文:

I am trying to model a sheep vs rabbit population with the following rules:

  1. If two animals of different species meet on the same square on an nside grid, there is a chance that either none, both or one of them die.
  2. If animals with the same species meet on a square, there is a chance (similar probability as ^^) that a new baby will be born.

In the next time step, the live animals can move either left, right, up or down.

My problem is that in my model, both species are exponentially growing and I'm not sure how to fix this.

What I have tried:
My approach to solving this problem was examine each of the pairs.
If the pair doesn't contain a dead animal, then evaluate its status if a new animal should be born or dead using if else conditions. Note that nsides in my code represents the size of the grid. I've also called my animal class People2 as it was adapted from a previous code.

#testing the different if/else functions 
import numpy as np
class People2: #class animals 
def __init__(self, status, species,  nsides=40): #change here
self.nsides = nsides
self.location = np.random.randint(0, self.nsides, [2])
self.status = status
self.species=species
def move(self): #moving animals up or down 
moves = np.random.randint(-1, 2, [2])
self.location[0] =  (self.location[0]+ moves[0]) % self.nsides
self.location[1] =  (self.location[1] + moves[1]) % self.nsides
class World2:
def __init__(self,time=0, maxtime=1000, nsides=40, npeople=2, nprob=0.9):
self.npeople = npeople
self.nprob=nprob
self.nsides=nsides
self.rabbits=[]
self.sheep=[]
#self.people = []
#who_is_sick = np.random.randint(0, self.npeople)
self.time=0 
self.maxtime=1000
for i in range(self.npeople):
if i%2 == 0:
self.rabbits.append(People2(status=1, species='R', nsides=nsides))  # sick person 
else:
self.sheep.append(People2(status=1, species='S' , nsides=nsides))  # healthy person
self.people=self.rabbits+self.sheep
def movement(self):
self.to_remove=[]
self.compare=[]
new=[]
#pseudocode 
self.a_list2=list(enumerate(self.people))
self.anim_combined=list(itertools.combinations(self.a_list2, 2))
#traverse through list, if I am not my self:
for r, s in self.anim_combined: #note that r,s don't refer to rabits vs sheep, could be anyanimal
if r[1].status!=0 and s[1].status!=0:
if np.all(r[1].location==s[1].location): 
if (r[1].species!=s[1].species) : #diff species 
r_prob, s_prob = np.random.choice([0, 1],p=[self.nprob,1-self.nprob], size=2)
if r_prob==1:
pass
else:
r[1].status==0
if s_prob==1:
pass 
else:
s[1].status==0
else: #same species 
if (r[1].species==s[1].species):
repro_prob=np.random.choice([1, 0], p=[self.nprob,1-self.nprob] )
if repro_prob==0:
pass
else: #if the prob is 1, then append a "baby"
if repro_prob==1:
new.append(People2(status=1, species=r[1].species, nsides=self.nsides)) 
#remove those who are dead (i.e. status=0) 
unique_elements = list(itertools.chain.from_iterable(self.anim_combined))
not_killed = [index_and_animal[1] for index_and_animal in unique_elements if index_and_animal[1].status == 1]
# putting all the alive animals back into the original equation
self.people.extend(new) #adding the new babies 
self.people.extend(list(set(not_killed))) #adding whatever wasn't killed into this list 
self.time += 1
for animal in self.people:
animal.move()
return self.people
#iterating over 4 days
anim_world = World2()
rabbit_len = []
sheep_len = []
for _ in range(4): #iterating for 10 days
rabbit_count = 0
sheep_count = 0
for animal in anim_world.movement():
if animal.species == "R":
rabbit_count += 1
elif animal.species == "S":
sheep_count += 1
rabbit_len.append(rabbit_count)
sheep_len.append(sheep_count)

If I could see why they are exponentially growing and why some animals arent being killed if they are of different species,that would be great. Thanks in advance!

答案1

得分: 0

你正在复制所有存活的动物,使用self.people.extend(list(set(not_killed)))。尝试将self.people.extend(new)替换为self.people = new。这将使它成为所有新的动物,而不是扩展仍然存活的那些。你也可以将self.people设置为空数组,例如:

self.people = []
self.people.extend(new)
self.people.extend(list(set(not_killed)))

或者你可以将self.people设置为list(set(not_killed)),例如:

self.people = list(set(not_killed))
self.people.extend(new)

但无论如何,在扩展之前,你确实需要设置self.people,否则在设置时会删除已扩展的部分。

希望这有所帮助!

P.S. slothrop 是对的,你可能想将r[1].status==0替换为r[1].status=0

英文:

You are duplicating all the living animals with self.people.extend(list(set(not_killed))). try replacing self.people.extend(new) with self.people = new. That will set it to be all the new ones than you extend all the ones that are still alive. You could alternatively set self.people to a empty array e.g.

self.people = []
self.people.extend(new)
self.people.extend(list(set(not_killed)))

or you can set self.people to list(set(not_killed))

e.g.

self.people=list(set(not_killed))
self.people.extend(new)

You do need to set self.people before you extend it though. otherwise you would remove the extended ones when it is set.

Hope this helps!

P.S. slothrop is right you probably want to replace r[1].status==0 with r[1].status=0.

huangapple
  • 本文由 发表于 2023年5月24日 23:37:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76325241.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定