谢林模型——R语言实现

谢林模型

参考文章谢林模型

数据准备

  • N×N的网格:::一共有pop个格子
    1.红格子,蓝格子 --代表家庭
    2.白格子 --代表搬家的目的地

用N×N的矩阵M表示
红格子:2
蓝格子:1
白格子:0

  • 给每个家庭编号:给矩阵M中的每个元素一个编号,方便后面使用

pop.coord, 记录矩阵中每个元素的编号

  • 计算每个家庭的周围状态,即左右上下的家庭都是红家庭还是蓝家庭

neighbor.all 记录矩阵中每个元素的周围,即左右上下分别是红格子、蓝格子、白格子

模型演化

  • 只针对红格子或者蓝格子进行处理

popLoc 代表了红蓝格子的编号

  • 每一轮演化,只针对一部分家庭进行处理,即针对一部分家庭来判断是否搬家

mp = 0.9 ,就是每轮要判断90%的家庭的周围状态,然后判断他们是否搬家
Chosen ,就是那些选出来要做判断的家庭编号,即矩阵元素的编号

  • 针对这个家庭的判断,计算他周围跟自己不同类的家庭个数,和同类的家庭个数,前者大,就搬家

M[i]==1 自己是蓝格子
& 并且
length(which(neighbor.all[[i]]==2)) 周围是红格子的数量

length(which(neighbor.all[[i]]==1)) 周围是蓝格子的数量

  • 针对这个家庭的判断,计算他周围跟自己同类的家庭个数,然后除以4, 即可得到同类比例,如果小于阈值75%,就搬家

rate <- length(which(neighbor.all[[i]]==M[i])) / 4

  • 搬家:自己原来的位置变为空,搬去的目的地变为自己的家庭状态

M[sample(which(M==0),1)]<- 1 随机选一个空格子变为 蓝格子
M[i]<-0 自己原有的位置变为白格子

完整代码

##下载并加载pacman包
if(!require(pacman))install.packages("pacman")
library(pacman)
p_load(plot.matrix,purrr)

#系统参数设置
#网格数
pop<-500
if(sqrt(pop) %% 1 != 0){
  repeat{      
    pop<-pop+1
    if(sqrt(pop) %% 1==0){
      break
    }
  }
}
print(pop)
N<-sqrt(pop)
empty<-0.1   #空格比例为10%
vacant<-as.integer(N*N*empty) ##空格的数量(整数)
vacant

##两类人群比例1:1(蓝色和红色)
B2R <- 1

#设定函数 找到蓝色红色的个数并赋值成1、2,确定空格数并随机排列组合
rand.init<-function(N,B2R,empty){
  blues<- as.integer(pop*(1-empty)/(1+1/B2R))  #强制转换成整数
  reds<- pop-blues
  M<-rep(1,N*N) #蓝色:1
  M[1:reds]<-2 #红色:2
  M[(N*N-vacant+1):(N*N)]<-0 #空格:0
  # set.seed(0)
  M<-sample(M)      #随机排列组合
  return(matrix(M,nrow=N,ncol=N))
}

#随机生成初始网格状态
M<-rand.init(N,B2R,empty)  #N、B2R、empty

init.M<-M

#画图
par(mfrow=c(1,1))                     #一行一列
plot(init.M,breaks=c(0,1,2,3),        #breaks是0、1、2、3四个数字
     col=c("white","blue","red"))     #颜色是蓝色、红色、白色

#确定网格中某个家庭的周围状态, mx是当前的网格
neighbor<-function(row,col,mx){
  if(row==1){U<-mx[sqrt(pop),col]} else{U<-mx[row-1,col]}  #sqrt(pop)=N,如果在第一行的话,上面就是第23行
  if(row==sqrt(pop)){D<-mx[1,col]} else{D<-mx[row+1,col]}
  if(col==1){L<-mx[row,sqrt(pop)]} else{L<-mx[row,col-1]}
  if(col==sqrt(pop)){R<-mx[row,1]} else{R<-mx[row,col+1]}
  c(L,R,U,D) # 左右上下
}

#网格家庭坐标编号
pop.coord<-cbind(rep(c(1:sqrt(pop)),sqrt(pop)),
                 as.vector(matrix(rep(1:sqrt(pop),sqrt(pop)),
                                  nrow=sqrt(pop),byrow=T)))
pop.coord

#确定网格上每个家庭的周围状态  是一个list,  其index:家庭编号, 元素是list, 代表了这个家庭的周围状态。 
neighbor.all<-map2(pop.coord[,1],pop.coord[,2],neighbor,mx=M)


mp<-0.9 #每期移动比例
for(r in 1:100){ #运行100次
  popLoc<-which(M==1 | M==2) #筛除空格(只留下代表家庭的格子)
  # set.seed(r)
  Chosen<-sample(popLoc,mp*length(popLoc))  #打乱家庭的位置,即随机选一定比例的家庭进行移动
  for(i in Chosen){        #每个家庭循环
    rate <- length(which(neighbor.all[[i]]==M[i])) / 4
    if(rate < 0.75){
        M[sample(which(M==0),1)]<- M[i]
        M[i]<-0
    }
    # if(M[i]==1 & length(which(neighbor.all[[i]]==2))>length(which(neighbor.all[[i]]==1))){ # 自己家是蓝色,且周围是红色的家庭大于蓝色的家庭,搬家
    #   M[sample(which(M==0),1)]<-1
    #   M[i]<-0
    # }
    # if(M[i]==2 & length(which(neighbor.all[[i]]==1))>length(which(neighbor.all[[i]]==2))){
    #   M[sample(which(M==0),1)]<-2
    #   M[i]<-0
    # }
   neighbor.all<-map2(pop.coord[,1],pop.coord[,2],neighbor,mx=M)
  }
}

#可视化
par(mfrow=c(1,2))    #一行2列
plot(init.M,breaks=c(0,1,2,3),col=c("white","blue","red"))
plot(M,breaks=c(0,1,2,3),col=c("white","blue","red"))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值