0
0

More than 1 year has passed since last update.

エージェントシミュレーション2(噂の広まり方)

Posted at

前回は・・・

コンビニなどの小売店内を想像したエージェントシミュレーションをしました。リンクを張っておきます。
<エージェントシミュレーション(コンビニ)>
https://qiita.com/chutake_exe/items/7906fa90f8272f326895

テーマ:噂の広まり方

大学が夏休みに入り、自由な時間が増えました。前回のコンビニのシミュレーションをもとに、今回は噂の広まり方をシミュレーションしてみようと思います。

今回は噂を伝える人、噂を受け取る人を用意します。ここではそれぞれAとBと名付けます。

・レイアウト

前回と同様に、pythonのTKinterを使います。30×30マスでフィールドを構築します。また観察を行うために必要なボタンもいくつか実装しました。

ここで赤い人物はA(噂を知っている人)、青い人物はB(噂を知らない人)としています。

・現実に近づけるために

今回のシミュレーションでは、噂の広まる方法は近くで聞こえてしまった場合に限ります。
また皆さんは、聞こえてしまった噂を鵜呑みにはしないですよね?(笑)
これらを踏まえてエージェントに2つの変数を用意し、その変数を調整することで観察をします。

変数1・・・Aが噂を発信する範囲(マス)
変数2・・・Bが噂を信じるまでの回数

少し前の噂や事実は忘れられていくように、情報には期限があります。よってあるステップ経過後、自動的にAはBに変化する(噂を広めなくなる)ようにしました。

・実験方法

変数を1つだけ変えて以下の試行をし、①~③で対照実験をする。

1, Bを10人単位でフィールドに追加していきます。
2, Aを1人追加する。(噂の発信源)
3, 全員に噂が広まる(全員Aになる)
4, 3になるまでのステップ数を計算する

① 人数を変えてみる。11人(A=1,B=10)と21人(A=1,B=20)
② 噂を広める範囲を変更してみる。
③ 噂を信じる回数を変更する。

「たまたま人が集まっていて、噂が広まるのが早すぎた」などが起こると、終了状態になるまでのステップ数が異常値になってしまいます。今回は各5回ずつ試行し、その平均値をとることで解決とします。(各5回では少ない気もしますが...)

結果

①~③の結果をグラフにしてみました。

① 人数を変える。左:11人(A=1,B=10)と右:21人(A=1,B=20)

全員がAになるまで、それぞれ平均 1503.6ステップ、__639.6ステップ__でした。まあ、人数が多ければ多いほど噂って広まりますよね。

② 噂の広まる範囲を変える。(左:2マス→右:4マス)

全員がAになるまで、それぞれ平均 1503.6ステップ476.6ステップ でした。

③ 噂を信じるまでの回数を変える。(左:5回→右:3回)

全員がAになるまで、それぞれ平均 1503.6ステップ936.6ステップ でした。

・まとめ

1番ステップ数が短いのが、②の噂を広める範囲を変えることでした。
結果をみて自分で「そりゃそうだろ、広い範囲に影響を与えるのが早く広まるじゃん」と思いました(笑)。よってこの観察の結果から、噂を早く広めたいとするならば
・有名人やインフルエンサーが発信源となることで、効率的に噂を広めることができる
ということが分かりました。

最後に

前回同様、現実世界になるべく近づけることが課題になります。フィールド上のA(噂を広める人)は一定期間ではありますが、その間は噂をし続けるという条件です。他にも噂を知る手段としてSNSなどがあります。このシミュレーションと同時並行で、エージェントがSNSを見ていて影響を受けるというのも面白そうですね。今回もプログラムを載せておきます。

プログラム(シミュレーション本体)
from tkinter import *
import random
import time
from dataclasses import dataclass
import matplotlib.pyplot as plt


CELLSIZE=20
FIELD_X,FIELD_Y=30,30
WIDTH,HEIGHT=FIELD_X*CELLSIZE,FIELD_Y*CELLSIZE
tk=Tk()
tk.title("噂の広まり方")
canvas=Canvas(tk,width=WIDTH,height=HEIGHT)
canvas.pack()

##変数##
layout=[]#Fieldの座標などが入る
agents=[]#エージェントたち
speed=2#観察の速さ
Allr=False #全員RedになったらTrueに
Allb=False #全員blueになったらTrueに
Start=False #フィールドにREDを追加したらカウント開始
RedAgent=[]#StartがTrueのとき、ステップ毎にREDの増減をadd
##/変数##

##dataclass##
@dataclass
class people:
   i:int
   x:int
   y:int
   status:str #購入前(yet)→購入後(done)
   life:int
   effectnum:int #影響受ける数

@dataclass
class Layout:
   x:int
   y:int
##/dataclass##

##関数##
def make_layout(layout):#レイアウトを作る
   for x in range(FIELD_X):
      for y in range(FIELD_Y):
         layout.append(Layout(x,y))


def create_layout(L):
   for x in range(FIELD_X):
      canvas.create_line(x*CELLSIZE,0,x*CELLSIZE,FIELD_Y*CELLSIZE)
   for y in range(FIELD_Y):
      canvas.create_line(0,y*CELLSIZE,FIELD_X*CELLSIZE,y*CELLSIZE,)

def rectangle_buyer(agents):
   for agent in agents:
      x=agent.x*CELLSIZE
      y=agent.y*CELLSIZE
      if(agent.status=="done"):
         canvas.create_rectangle(x,y,x+CELLSIZE,y+CELLSIZE,fill="red")
      elif(agent.status=="yet"):
         canvas.create_rectangle(x,y,x+CELLSIZE,y+CELLSIZE,fill="blue")

def add():#BLUE追加
   for x in range(10):#客をふやす
      i=len(agents)+1
      x=random.randint(0,29)
      y=random.randint(0,29)
      status="yet"
      life=0
      effe=0
      agents.append(people(i,x,y,status,life,effe))

def add_rumor():#RED追加
   global Start
   i=len(agents)+1
   x=random.randint(0,29)
   y=random.randint(0,29)
   status="done"
   life=200#うわさの寿命
   effe=0
   agents.append(people(i,x,y,status,life,effe))
   Start=True

def move(agents):#エージェントの移動
   for agent in agents:
      while(True):
         rand=random.randint(0,50)#1~5で方向を決める
         if(rand<10):#右
            p=FIELD_X*(agent.x+1)+agent.y
            if(not p>FIELD_X*FIELD_Y):
               agent.x+=1
               break

         elif(rand<20):#下
            p=agent.y+1
            if(not p>FIELD_Y-1):
               agent.y+=1
               break

         elif(rand<30):#左
            p=FIELD_X*(agent.x-1)+agent.y
            if(not p<0):
               agent.x-=1
               break

         elif(rand<40):#上
            p=agent.y-1
            if(not p<0):
               agent.y-=1
               break

         else:#止まる
            break
         ##行動おわり

def check(distance,effectNum):#distance=噂が広まる距離、effectNum=噂が広まるための回数
   for checkagent in agents:
      if(checkagent.status=="done"):
         for agent in agents:
            if(abs(agent.x-checkagent.x)<=distance and abs(agent.y-checkagent.y)<=distance and agent.status=="yet"):#近くにいるとき
               agent.effectnum+=1
               if(agent.effectnum>=effectNum):
                  agent.status="done"
                  agent.effectnum=0
                  agent.life=200
         checkagent.life-=1
         if(checkagent.life<0):
            checkagent.status="yet"
            checkagent.life=0

def checkAllr():##全員redか判定
   if(len(agents)==0):
      return False
   for agent in agents:
      if(agent.status=="yet"):
         return False
   return True

def checkAllb():#全員blueか判定
   if(len(agents)==0):
      return False
   for agent in agents:
      if(agent.status=="done"):
         return False
   return True

def print_all():#エージェント総出力
   for agent in agents:
      print(agent)

def change_speed():#観察のスピード変更
   global speed
   speed=txt.get()

def RedAgentCount():#REDを数える
   count=0
   for agent in agents:
      if(agent.status=="done"):
         count+=1
   return count

def Redprint():#REDの増減をリストで出力
   print(RedAgent)

##/関数##

#レイアウト構成
make_layout(layout)

##UI##
btn1=Button(tk,text="人追加",command=add)
btn1.pack()
btn2=Button(tk,text="出力",command=print_all)
btn2.pack()
btn3=Button(tk,text="重要人物",command=add_rumor)
btn3.pack()
txt=Entry(width=20)
txt.insert(0,"2")
txt.pack()
btn4=Button(tk,text="速さ変更",command=change_speed)
btn4.pack()
btn5=Button(tk,text="REDのデータ",command=Redprint)
btn5.pack()
##/UI##

##main##
def main_loop():
   global Allr,Allb
   canvas.delete("all")#全部消す
   create_layout(layout)#レイアウト描画
   move(agents)#エージェントの移動 (エージェントのリスト)
   check(2,5)#噂が広まるかチェック (広まる距離、近づいた回数)
   rectangle_buyer(agents)#エージェントの描画

   #全員がREDかBLUEになるまでリストに追加する
   if(checkAllr()):
      Allr=True
      print(f"{RedAgentCount()} : 全員REDになりました。")
   if(checkAllb() and Start):
      Allb=True
      print(f"{RedAgentCount()} : 全員BLUEになりました。")
   if((not Allr) and (not Allb)):
      if(Start):
         RedAgent.append(RedAgentCount())
      tk.after(speed,main_loop)
##/main##

##main呼び出し
main_loop()

プログラム(グラフ書く用)
import matplotlib.pyplot as plt

#取得した値を入れる
data1=[]
data2=[]
data3=[]
data4=[]
data5=[]
#何ステップで終了したか出力
print(f"data1:{len(data1)}")
print(f"data2:{len(data2)}")
print(f"data3:{len(data3)}")
print(f"data4:{len(data4)}")
print(f"data5:{len(data5)}")

#グラフの描画
plt.title("噂を広める範囲=2,信じるまでの回数=5",fontname="MS Gothic")
plt.xlabel("移動回数(時刻)",fontname="MS Gothic")
plt.ylabel("噂が広まった人数(人)",fontname="MS Gothic")

plt.plot(data1,color="red")
plt.plot(data2,color="blue")
plt.plot(data3,color="black")
plt.plot(data4,color="orange")
plt.plot(data5,color="green")
plt.show()

##5回の平均
print((len(data1)+len(data2)+len(data3)+len(data4)+len(data5))/5)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0