房間裏面的財富分配遊戲

1. 問題描述

2. 問題假設

3. 問題解決及可視化分析

1.問題描述

房間內有 100 人,每人有 100 塊,每分鐘隨機 給另一個人 1 塊錢,最後這個房間內的財富分佈怎樣?

2.問題假設

我們可以用這個遊戲模擬現實社會上的財富運行及分配,有的人花錢,有的人掙錢,但是總資產不變。
假設:1.每個人在18歲帶着100元的初始資金開始玩遊戲;
2.每天玩一次,一直玩到80歲的人均壽命。
在現實社會中人的平均壽命爲80歲,那麼一生共需要玩大約20000次遊戲,也就是說有20000次機會選擇收錢或消費,只不過是隨即分配的。
在此基礎上,爲進一步模擬現實社會,分爲以下四種情況:
假設一 :不允許負債情況(財富值低於0即退出遊戲)
假設二 :負債情況(投機者:即使財富爲負依然消費)
假設三 :努力工作(奮鬥者:負債情況下獲得財富的機率多1%)
假設四 :存款利率(投資者:持有財富的年利率是3%)

3.問題解決

  • 初始化遊戲
#
#  初始化模擬世界
#
from random import choice, sample
import numpy as np

nLoops = 20000  # 分配的次數
nGamers = 100   # 參與分配的人數
deposit = 100   # 每個人初始財富數量
consume = 1        # 每次分配消費或者獲得的財富

gamers = {}     # 用字典的方式保存每個人的財富數量並初始化
for gamer in range(nGamers):
    gamers[gamer] = deposit

計算每次隨機分佈的個人財富

# 計算每一次隨機分配後的個人財富
def epoch(gamers, nGamers, consume, loan=False):
    """
    模擬每次分配的情況
       1 遍歷全體參與者,獲得參與者ID和擁有的財富
       2 隨機挑選除自己以外的一個參與者
       3 自己消費財富同時挑選的參與者獲得相應財富(注:考慮負債)
       
    參數:
        gamers - 分配遊戲的參與者和其攜帶的財富數量;數據類型:字典,其中key爲參與者ID,value爲對應的財富數量
        nGamers - 參與分配遊戲的總人數;數據類型:大於1的正整數
        consume - 參與每次分配消費或者獲得的財富;數據類型:正整數
        loan - 當參與者攜帶的財富小於零的時候,是否允許參與本次分配的消費活動
    """

    for nid, nvalue in gamers.items():
        others = list(range(0,nGamers))
        del(others[nid])
        to_gamer = choice(others)
        if gamers[nid] <= 0 and not loan:
            continue
        gamers[to_gamer] += consume
        gamers[nid] -= consume
    
    return gamers

可視化結果:

def vis_simulation(nGamers, gamers, lucky_gamers=None):
    """
    模擬世界的財富分配 - 可視化結果
    
    參數:
        nGamers - 參與分配遊戲的總人數;數據類型:大於1的正整數
        gamers - 分配遊戲的參與者和其攜帶的財富數量;數據類型:字典,其中key爲參與者ID,value爲對應的財富數量
    """
    from matplotlib import pyplot as plt
    %matplotlib inline
    plt.rcParams['font.sans-serif'] = ['SimHei'] #指定默認字體
    plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號

    if lucky_gamers:
        new_gamers = []
        for i in lucky_gamers:
            new_gamers.append(gamers[i])

        sort_gamers = sorted(gamers.values())
        new_index = []
        for i in new_gamers:
            index = sort_gamers.index(i)
            new_index.append(index)
    
    
    # 可視化結果
    plt.figure(figsize=(18,6))
    plt.subplot(131)
    plt.hist(gamers.values())
    #plt.xlim([0,400])
    #plt.ylim([0,30])
    plt.title("財富的總體分佈")

    plt.subplot(132)
    plt.bar(range(0,nGamers), gamers.values(), width=0.5, color='orange')
    if lucky_gamers:
        plt.bar(lucky_gamers, new_gamers, width=0.5, color='red')
    plt.plot([0,100],[100, 100],color='green',linestyle="-.",linewidth=1)
    plt.xlim([0,100])
    #plt.ylim([0,400])
    plt.title("個人持有財富的分佈")
    
    plt.subplot(133)
    plt.bar(range(0,nGamers), sorted(gamers.values()), width=0.5, color='orange')
    if lucky_gamers:
        plt.bar(new_index, new_gamers, width=0.5, color='red')
    plt.plot([0,100],[100, 100],color='green',linestyle="-.",linewidth=1)
    plt.xlim([0,100])
    #plt.ylim([0,400])
    plt.title("排序後的個人持有財富分佈")
    plt.show()
  • 假設一
    不允許負債情況(財富值低於0即退出遊戲):
# 模擬分配 - 不負債的情況
for i in range(nLoops):
    gamers = epoch(gamers, nGamers, consume)
print(gamers)

輸出:
在這裏插入圖片描述
可視化結果:

vis_simulation(nGamers, gamers)

在這裏插入圖片描述

  • 假設二
    負債情況(投機者:即使財富爲負依然消費)
gamers = {}     # 用字典的方式保存每個人的財富數量並初始化
for gamer in range(nGamers):
    gamers[gamer] = deposit

# 模擬分配 - 允許負債的情況
for i in range(nLoops):
    gamers = epoch(gamers, nGamers, consume, loan=True)
vis_simulation(nGamers, gamers)

在這裏插入圖片描述

  • 假設三
    努力工作(奮鬥者:負債情況下獲得財富的機率多1%)
# 假如有某些比較努力的人們,計算每一次隨機分配後的個人財富
def epoch_better_person(gamers, nGamers, consume, lucky_gamers, loan=False):
    """對於給定人數的遊戲參與者, 每個人都隨機的給其他人指定數量的貨幣(give)
       其中loan參數顯示是否允許參與分配的人其財富爲負值(即負債)
    """
    
    pass

gamers = {}     # 用字典的方式保存每個人的財富數量並初始化
for gamer in range(nGamers):
    gamers[gamer] = deposit

# 模擬分配 - 允許負債的情況 & 存在10個積極努力的參與者(奮鬥者)
lucky_gamers = sample(range(0, nGamers), 10)
for i in range(nLoops):
    gamers = epoch_better_person(gamers, nGamers, consume, lucky_gamers, loan=True)
    
vis_simulation(nGamers, gamers, lucky_gamers=lucky_gamers)

在這裏插入圖片描述
說明一下下:以上代碼來自老師,我做了一下總結與修改,並增添了一個自己的…(嘿嘿)

  • 假設四
import matplotlib.pyplot as plt#繪圖庫
import numpy as np#數據分析
import pandas as pd#數據分析
import random #隨機函數
import time#計算時間
import copy#dataframe使用


plt.rcParams['font.sans-serif']=['SimHei']   # 用黑體顯示中文
plt.rcParams['axes.unicode_minus']=False     # 正常顯示負號

###定義方法:玩遊戲#####
# 假設3(play_game3):存款利率(投資者:持有財富的年利率是3%)
def play_game3(round_number):   #round_number表示遊戲的輪數
    id_list = range(100)  #定義每個人的編號
    id_money_dict = {k: 100 for k in id_list}  #定義初始每個人各#100元
    round_id_money_dict={}  #用於放每一輪遊戲後每一個人的財富值,每一輪的數據都會保存
    for round_id in range(1,round_number+1):  #進行多輪遊戲
        if round_id/365==0:
            for i in [0,11,22,33,44,55,66,77,88,99]:
                id_money_dict["i"]*=1.03 #每一年計算一次利率
        for id in id_money_dict.keys():   #每一輪中的每一個人都進行拿#錢和收錢的遊戲
            id_money_dict[id] += -1     #其中一個人拿出一元錢
            id_get = random.randint(0, 99)   #隨機選出另外一個
                                                    #收錢的人
            while id_get == id:
                id_get = random.randint(0, 99)  #如果出錢者
                                                    #錢者是同一個人,則重新選一個收錢者
                                                  
            id_money_dict[id_get] += 1   #另外一個人收下一元錢
        round_id_money_dict[round_id]=copy.copy(id_money_dict) #每一輪遊戲過後,將數據存儲在字典round_id_money_dict中                                              
    data_result=pd.DataFrame(round_id_money_dict)  #將每一輪遊戲結束後的數據轉化爲DataFrame格式,便於取用和比較                         
                                   
    return(data_result) 
###定義方法:繪製柱狀圖#####
def draw1(data,n):   #data表示n輪後的數據,n表示遊戲輪數   
    data=pd.DataFrame(data)
    data=data.T
    datai = pd.DataFrame({'money':data.iloc[0],'color':'gray'})
    datai['color'].loc[0,11,22,33,44,55,66,77,88,99] = 'red'
    datai = datai.sort_values(by = 'money').reset_index()
    plt.figure(figsize=(14,12))
    plt.bar(datai.index,datai['money'],color = datai['color'])
    plt.xticks(np.arange(100), datai["index"],fontsize=8,rotation=90)#設置座標值
    plt.ylim([-300,500])
    plt.xlim([-10,110])
    plt.xlabel('玩家編號') #定義橫座標的名稱
    plt.ylabel('財富值/元') #定義縱座標的名稱
    plt.title(str(n)+'輪遊戲後的財富分佈')
    
    plt.show()

'''
規定年利率爲3%,那麼一年後的財富爲(1.03)*本金
規定id號爲0,11,22,33,44,55,66,77,88,99的人爲投資者
'''
 
#開始遊戲
data_result=play_game3(20000)

##繪製十年,二十年,三十年,四十年,五十年後財富分佈結果
for i in [3600,7200,10800,14400,18000]:
    start=time.time()
    draw1(data_result[i],i) 
    
    ##數據分析
    print("%d次遊戲後數據分析:"%i)
    
    #分析id號爲0,11,22,33,44,55,66,76,88,99的人的財富情況
    print("投資者的財富值情況:")
    for j in [0,11,22,33,44,55,66,76,88,99]:
        print(data_result[i][j],end=" ") 
    
    ##投資者所擁有的財富佔總財富的比例
    invest_money=0
    for x in [0,11,22,33,44,55,66,76,88,99]:
        invest_money+=data_result[i][x]
    print("投資者所擁有的財富佔總財富的比例%s%%"%(invest_money/100))
    
    ## 分析第n次遊戲,財富值排名前30的Id號
    rank_money = np.argsort(data_result[i])[90:100] # 返回排序後各數據的原始下標即從小到大排列財富值後,返回id號
    count=0#統計排名前三中那十個人的比例
    for m in rank_money:
        for n in [0,11,22,33,44,55,66,76,88,99]:
            if m==n:
                count+=1
    print("財富排行榜排名前十的人中,投資者共有%d個,所佔比例爲%s%%"%(count,count/3*10))
    
    end=time.time()#結束時間
    print("所用時間爲:"+str(end-start)+"s")
    

在這裏插入圖片描述

  • 總結
    1.結合圖表及數據可知,投資者的財富處於不確定的狀態,在18-48歲時投資者的財富一直處於上升階段,並且所有人的財富所佔總體財富的比例也在上升,而48歲即10800次遊戲後投資者所擁有的財富佔總財富的比例開始下降,並且一旦負債之後就難以迴歸原來的初始值,而財富排行榜中,投資者所佔比例也不是很多,告訴我們"投資有風險,需謹慎"

    2.儘管最成功的玩家不一定是最努力的那個,
    但是努力的人大都(80%)混的還不錯。感謝這個殘酷世界還給我們留下一條生路。
    那麼,該如何面對這個殘酷的世界?

那就是

努力 – 奮鬥 並堅持下去
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章