- 基本理論
- 每個個體看作一個點(暫時用二維的點)【多維情況下,每一個維度都可以是對個人某一屬性的描述】
- 點的走向作爲個人的發展情況
- 社會初期隨機發展,一定時間後個人發展受朋友影響
- 前一次的點與後一次的點構成一個線段
- 在某一時間內,
人A 對應的線段 與人B 對應的線段相交,則認定兩人相識(成爲朋友) - 兩點之間的距離作爲兩個人親密度的度量,前提是成爲朋友
- 在達到一定年齡之後 , 人們會選擇與自己親密度最佳(距離最小)的異性朋友作爲伴侶(成爲戀人),一定時間後產生新的人類
- 未完待續
- 算法實現
Code: humans
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 24 10:48:48 2015
# Human
@author: Zhang_Jun
"""
import random
import math
class human(object):
def __init__(self,ID):
self.ID = ID # 編號
self.sex = random.randint(1,2) # 隨機產生性別
self.x_before = 0 ; self.y_before = 0 # 個人狀態描述(前)
self.x_after = 0 ; self.y_after = 0 # 個人狀態描述(後)
self.vector = [self.x_after - self.x_before , self.y_after - self.y_before] # 個人生活方向
self.ability = 1 # 發展潛力,決定了個人發展方向的模長
self.age = 0 # 個人的年齡
self.friend = [(ID,self)] # 個人的所有好友列表 (編號,包含好友所有信息的對象)
self.friend_distance_sex = [(ID,0,0)] # 好友的親密度與性別屬性 (編號、親密度、性別同性與否[0:同性,1:異性])
self.mate = [ID,self,100000] # 個人的配偶 ,配偶編號 以及 親密度
self.stage = 1 # 個人的生存狀況 1 爲 生 0 爲 死
self.time = 0 # 記錄時間流逝,可以構造一個與年齡轉換的函數 (自定義)
def initiate_grow(self,step): # 社會剛形成期間,每個人隨機發展,不受他人影響
for i in range(step): # step 爲控制發展次數的參數()
self.time = self.time + 1 # 每step一次,增加一個時間單位
self.x_before = self.x_after
angle = random.randint(0,360)/180.0 * math.pi
self.x_after = self.x_after + self.ability * math.cos(angle)
self.y_before = self.y_after
self.y_after = self.y_after + self.ability * math.sin(angle)
self.vector = [self.x_after - self.x_before , self.y_after - self.y_before]
def grow(self,step,coef_friend,coef_random):
self.time = self.time = self.time + 1
self.x_before = self.x_after
self.y_before = self.y_after
friend_effect = [i * coef_friend for i in norm(sum_direction(self.friend))]
angle = random.randint(0,360)/180.0 * math.pi
random_effect = [i*coef_random for i in norm([math.cos(angle) , math.sin(angle)])]
direction =[i * self.ability for i in norm(sum_list(friend_effect,random_effect))]
[self.x_after,self.y_after] = sum_list([self.x_before,self.y_before] , direction)
self.vector = [self.x_after - self.x_before , self.y_after - self.y_before]
self.ability = sigmoid(inverse_sigmoid(self.ability) + coef_random * random.randint(-5,5)+ coef_friend * inverse_sigmoid(friend_ability(self.friend,self.ability)))
def sigmoid(x): # 控制個人能力增長的幅度
return 2.0/(math.exp(-0.1*x)+1)
def inverse_sigmoid(y):
return 10*math.log(y / (2.0-y) )
def sum_list(a,b):
return [x+y for x,y in zip(a,b)]
def sum_direction(friend_List):
direction =[0,0]
for friend in friend_List:
direction = sum_list(direction,friend[1].vector)
return direction
def norm(L):
ss = 0 # 平方和
for i in L:
ss = ss + i*i
sss = math.sqrt(ss)
return [x/sss for x in L]
def friend_ability(friend_List,self_ability):
fri_ability = [fri[1].ability for fri in friend_List]
return (1.0*sum(fri_ability)/len(fri_ability) - self_ability)*0.5 + 1
#-------------相遇判斷函數-------------------------
# 線段的交點 -> 是否有交點/交點是否在線段上
# -kx+y=b
def meet(human1,human2) :
delta =1e-10
P1 = [human1.x_before,human1.y_before]
P2 = [human1.x_after,human1.y_after]
P3 = [human2.x_before,human2.y_before]
P4 = [human2.x_after,human2.y_after]
if (P2[0]-P1[0])==0: # in case of denominator equals 0 (避免分母爲0的情況)
if (P3[0]-P4[0])==0:
return 0
else:
k2 = 1.0*(P4[1]-P3[1])/(P4[0]-P3[0])
b2 = -k2*P3[0]+P3[1]
P = [P1[0],k2*P1[0]+b2]
if (P[0]-P1[0])*(P[0]-P2[0])<=0 and (P[0]-P3[0])*(P[0]-P4[0])<=0 \
and (P[1]-P1[1])*(P[1]-P2[1])<=0 and (P[1]-P3[1])*(P[1]-P4[1])<=0 :
return 1
else:
return 0
elif (P4[0]-P3[0])==0: # in case of denominator equals 0 (避免分母爲0的情況)
if (P2[0]-P1[0])==0:
return 0
else:
k1 = 1.0*(P2[1]-P1[1])/(P2[0]-P1[0])
b1 = -k1*P1[0]+P1[1]
P = [P3[0],k1*P3[0]+b1]
if (P[0]-P1[0])*(P[0]-P2[0])<=0 and (P[0]-P3[0])*(P[0]-P4[0])<=0 \
and (P[1]-P1[1])*(P[1]-P2[1])<=0 and (P[1]-P3[1])*(P[1]-P4[1])<=0 :
return 1
else:
return 0
else:
k1 = 1.0 * (P2[1] - P1[1]) / (P2[0] - P1[0])
k2 = 1.0 * (P4[1] - P3[1]) / (P4[0] - P3[0])
b1 = -k1 * P1[0] + P1[1]
b2 = -k2 * P3[0] + P3[1]
if abs(k1 - k2) < delta: # if use k1=k2 will cause singular matrix 精確度問題
return 0
else: # 求解兩直線交點
P=[0,0]
P[0] = (b1 - b2) / (k2 - k1)
P[1] = (k2 * b1 - k1 * b2) / (k2-k1)
# 判斷交點是否在線段上
if (P[0]-P1[0])*(P[0]-P2[0])<=0 and (P[0]-P3[0])*(P[0]-P4[0])<=0 \
and (P[1]-P1[1])*(P[1]-P2[1])<=0 and (P[1]-P3[1])*(P[1]-P4[1])<=0 :
return 1
else:
return 0
Code: simulate (待註釋)
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 24 11:14:11 2015
@author: Zhang_Jun
"""
import human
import math
import pylab as plt
import numpy as np
import pandas as pd
import seaborn
seaborn.set()
# -------------------------generate humans-----------------
humans = []
human_number = 1000 # number of initiate humans
for i in range(human_number):
humans.append(human.human(i))
#----------------------------------------------------------
#-------------------- the initiate grows of humans---------
Time = 2
for people in humans:
people.initiate_grow(Time)
#-----------------show the vector of humans--------------------
V = [people.vector for people in humans ]
human_V = np.array(V)
#plt.plot(human_V[:,0],human_V[:,1],'.')
#plt.figure()
#---------------------------------------------
def draw_grow(number):
Position =[[people.x_before,people.x_after,people.y_before,people.y_after] for people in humans]
X_Position = np.array(Position)[:,:2]
Y_Position = np.array(Position)[:,2:]
for i in range(number):
plt.plot(X_Position[i],Y_Position[i])
#---------------------------------------------------------
for i in range(10):
for people in humans:
people.initiate_grow(1)
draw_grow(human_number)
# after initiate grow , the growth of people should folow some rule
marrage_age_bottom = 20
marrage_age_top = 40
#--------------------------------------meet -------------
Meet=np.zeros(human_number*human_number).reshape(human_number,human_number)
Meet_people=[]
for t in range(10):
for people in humans:
people.grow(1,0.8,0.2)
#draw_grow(human_number)
for i in range(human_number):
for j in range(human_number):
if Meet[i,j]==0 and i != j:
Meet[i,j] = human.meet(humans[i],humans[j])
if Meet[i,j] == 1 and (i,j) not in Meet_people:
Meet_people.append((i,j))
#print Meet_people
#print Meet
for fri in Meet_people: # friend in Meet_people
if (fri[1],humans[fri[1]]) not in humans[fri[0]].friend:
humans[fri[0]].friend.append((fri[1],humans[fri[1]]))
distance = math.sqrt( math.pow(humans[fri[1]].x_after \
- humans[fri[0]].x_after , 2) + math.pow(humans[fri[1]].y_after \
- humans[fri[0]].y_after , 2))
sex_compare = 0 if humans[fri[0]].sex == humans[fri[1]].sex else 1
humans[fri[0]].friend_distance_sex.append((fri[1],distance,sex_compare))
# --------------------------------------------------------
#draw_grow(human_number)
have_friend = set([p[0] for p in Meet_people])
for i in have_friend:
table1 = humans[i].friend # 所有的朋友 (編號和對象)
table2 = humans[i].friend_distance_sex # 朋友的屬性(編號、親密度、性別同性與否)
ID_OBJ = pd.DataFrame(table1,columns=('ID','OBJ')) # 轉化爲pandas 格式
ID_DIS_Sex = pd.DataFrame(table2,columns=('ID','DIS','SEX')) # 轉化爲pandas 格式
S_ID_DIS_SEX = ID_DIS_Sex.sort(columns='DIS') # 按照親密度排列
S_ID_DIS_HSEX = S_ID_DIS_SEX[S_ID_DIS_SEX.SEX == 1] # 獲取異性列表
if len(S_ID_DIS_HSEX)>0:
mate_DIS = S_ID_DIS_HSEX.DIS.values[0] # 記錄與配偶的親密度
mate_ID = S_ID_DIS_HSEX.ID.values[0] # 記錄配偶ID
if mate_DIS < humans[mate_ID].mate[2]: # A的理想配偶已經有配偶的情況判定及處理
humans[humans[mate_ID].mate[0]].mate=[humans[mate_ID].mate[0],humans[mate_ID].mate[1],100000]
humans[i].mate = [mate_ID,ID_OBJ[ID_OBJ.ID==mate_ID]['OBJ'].values[0],mate_DIS]
humans[mate_ID].mate =[i,humans[i],mate_DIS]
have_mate = [i for i in have_friend if humans[i].mate[0]!=i]
print len(have_mate) # 擁有配偶的人數
#-----------------show the vector of humans--------------------
plt.figure()
V = [people.vector for people in humans ]
human_V = np.array(V)
plt.plot(human_V[:,0],human_V[:,1],'.')
plt.figure()
# draw friends
for me in have_friend:
for number in range(len(humans[me].friend)):
Position =[humans[me].x_after,humans[me].friend[number][1].x_after,humans[me].y_after,humans[me].friend[number][1].y_after]
plt.plot(Position[:2],Position[2:],'g-',linewidth=0.3)
運行以上代碼
500人發展一段時間後的情況圖(某一時刻)
運行後查看變量(人)的情況
In [274]: have_mate
Out[274]:
[1,
2,
3,
6,
8,
9,
10,
11,
13,
16,
17,
18,
19,
...}
In [277]: have_friend
Out[277]:
{0,
1,
2,
3,
4,
5,
6,
8,
9,
10,
...}
In [281]: humans[11].mate
Out[281]: [216, <human.human at 0x3c5a79e8>, 0.12324587994054474]
In [282]: humans[216].mate
Out[282]: [11, <human.human at 0x5fa5ee48>, 0.12324587994054474
朋友圖(多階段發展)
一定時期後形成一定的格局
人們的發展方向分佈