首先,介绍下什么是蒙特卡洛模拟(let's go)
蒙特卡罗(Monte Carlo)方法,又称随机抽样或统计试验方法,当所要求解的问题是某种事件出现的概率,或者是某个随机变量的期望值时,它们可以通过某种“试验”的方法,得到这种事件出现的频率,或者这个随机变数的平均值,并用它们作为问题的解。这就是蒙特卡罗方法的基本思想。蒙特卡罗方法通过抓住事物运动的几何数量和几何特征,利用数学方法来加以模拟,即进行一种数字模拟实验。它是以一个概率模型为基础,按照这个模型所描绘的过程,通过模拟实验的结果,作为问题的近似解。可以把蒙特卡罗解题归结为三个主要步骤:构造或描述概率过程;实现从已知概率分布抽样;建立各种估计量。
简单来说,就是通过随机数,对策略进行模拟和评估
那么,如何通过蒙特卡洛模拟对社会财富分配进行预估呢,此处有个不成熟的小案例,即:假设有100个人,每人的初始财富是100元,当财富值大于0时,需要随机向其他一人支付1元,当财富值为0时,无需支付,但仍有可能获得其他人支付的金额,基于以上假设进行需进行如下四步操作:
1、构建函数模型
#注意:当某人财富值为0时,该轮无需拿钱出来,但仍有机会获得别人的财富
def game1(data,roundi):
if len(data[data[roundi-1]==0])>0:
round_i=pd.DataFrame({'pre_round':data[roundi-1],'lost':0})
con=round_i['pre_round']>0
round_i['lost'][con]=1
round_players_i=round_i[con]
choice_i=pd.Series(np.random.choice(person_n,len(round_players_i)))
gain_i=pd.DataFrame({'gain':choice_i.value_counts()})
round_i = round_i.join(gain_i)
round_i.fillna(0,inplace=True)
return round_i['pre_round']-round_i['lost']+round_i['gain']
else:
round_i=pd.DataFrame({'pre_round':data[roundi-1],'lost':1})
choice_i=pd.Series(np.random.choice(person_n,100))
gain_i=pd.DataFrame({'gain':choice_i.value_counts()})
round_i=round_i.join(gain_i)
round_i.fillna(0,inplace=True)
return round_i['pre_round']-round_i['lost']+round_i['gain']
运行模型,模拟财富分配
import time
person_n=[x for x in range(1,101)]
fortune=pd.DataFrame([100 for i in range(100)],index=person_n)
fortune.index.name='id'
#设定初始参数,游戏玩家100人,初始资金100元
starttime=time.time()
for round in range(1,17001)[:3000]:
print('正在进行第%i次模拟'% round)
fortune[round] = game1(fortune,round)
#fortune[round] = game1(fortune,round)
game1_result=fortune.T
endtime=time.time()
print('模型总共用时%i秒' % (endtime - starttime))
game1_result
绘制柱状图
前100轮,按每10轮绘制一次,第100-1000轮,按照每100轮绘制1次,第1000-17000轮,按每400轮绘制一次
查看财富变化状况
def graph2(data,start,end,length):
for n in list(range(start,end,length)):
datai=data.iloc[n].sort_values().reset_index()[n]
plt.figure(figsize=(10,3))
plt.title('第%i轮'%n)
plt.bar(datai.index,datai.values,color='gray',alpha=0.8,width=0.5)
plt.xlabel('PlayerID')
plt.ylabel('Fortune')
plt.xlim(-10,110)
plt.ylim(0,400)
plt.grid(alpha=0.5,linestyle='--')
graph2(game1_result,0,100,10)
graph2(game1_result,100,1000,100)
graph2(game1_result,1000,17000,400)
得出结论
最后一轮中,最富有的人财富值为365元,相比于初始财富,翻了3.65倍
10%的人掌握着28%的财富,20%的人掌握着51%的财富?
60%的人财富缩水至100元以下了
round_17000_1 = pd.DataFrame({'money':game1_result.iloc[-1]}).
sort_values(by = 'money',ascending = False).reset_index()
# 最后一轮数据汇总,并排序
round_17000_1['fortune_pre'] = round_17000_1['money'] / round_17000_1['money'].sum()
# 计算每个人的财富占比
round_17000_1['fortune_cumsum'] = round_17000_1['fortune_pre'].cumsum()
# 计算积累财富占比
round_17000_1.head()
fortune_sum = round_17000_1['money'].sum()
top10 = round_17000_1[round_17000_1['fortune_cumsum']<0.1]
top20 = round_17000_1[round_17000_1['fortune_cumsum']<0.2]
# 汇总出掌握前10%/20%财富的人群
lessthan100_num = len(round_17000_1[round_17000_1['money']<100])/100
print('最后一轮中,最富有的人财富值为%.1f元,相比于初始财富,翻了%.2f倍'
% (round_17000_1.iloc[0]['money'],round_17000_1.iloc[0]['money']/100))
print('10%%的人掌握着%.2f%%的财富,20%%的人掌握着%.2f%%的财富'
% (top10['money'].sum()/10000*100,top20['money'].sum()/10000*100))
print('%.2f%%的人财富缩水至100元以下了' % (lessthan100_num*100))
注意:用蒙特卡洛模拟需要满足样本可用随机数试验的原则,样本分布必须是随机的,不能有偏好!
以上便是此次模拟过程~