穷人和富人就差1%的努力——python模拟社会财富分配游戏

社会资金流是持续而有目的性的,你是否曾想过,为何富人会出现,穷人又为何会出现?穷人和富人究竟如何形成,是否努力就一定能获得成功,赢得更多金钱?今天,让我们用python代码,来模拟一个小社会,看看财富的分配到底是怎样的。

游戏规则:

房间里有100个人,每人都有100元钱,他们在玩一个游戏。每轮游戏中,每个人都要拿出一元钱随机给另一个人,最后这100个人的财富分布是怎样的?

游戏一:没有借贷的社会

1.1 模型假设

  • 每个人初始基金100元
  • 从18岁到65岁,每天玩一次,简化运算按照一共玩17000轮
  • 每天拿出一元钱,并且随机分配给另一个人
  • 当某人的财富值降到0元时,他在该轮无需拿出1元钱给别人,但仍然有机会得到别人给出的钱

游戏一,我们假设分配到财富值为0时可不用出钱,可看做社会前期,没有借贷的日子。

1.2 搭建模型

1.2.1 导入所需函数库

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
import time

import warnings
warnings.filterwarnings('ignore') 
# 不发出警告

1.2.2 第一轮游戏

第一轮游戏,先不考虑某人财富值会出现0元或以下的情况,这里是100轮内。

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元

round_r1 = pd.DataFrame({'pre_round':fortune[0],'lost':1})
# 设定第一轮分配财富之前的情况
choice_r1 = pd.Series(np.random.choice(person_n,100))      
gain_r1 = pd.DataFrame({'gain':choice_r1.value_counts()})                  
# 这一轮中每个人随机指定给“谁”1元钱,并汇总这一轮每个人的盈利情况
round_r1 = round_r1.join(gain_r1)
round_r1.fillna(0,inplace = True)
fortune[1] = round_r1['pre_round'] - round_r1['lost'] + round_r1['gain']
# 合并数据,得到这一轮每个人“盈亏”多少钱 → 得到这一轮财富分配的结果
数据展示

1.2.3 第二轮游戏

第二轮游戏,需要考虑当某人财富值降到0元时,他在本轮无需拿出1元,同时可以有机会拿到1元。

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元

round_r1 = pd.DataFrame({'pre_round':fortune[0],'lost':0})
round_r1['lost'][round_r1['pre_round'] > 0] = 1
# 设定第一轮分配财富之前的情况 → 该轮财富值为0的不需要拿钱给别人
round_players = round_r1[round_r1['pre_round'] > 0]
# 筛选出参与游戏的玩家:财富值>0
choice_r1 = pd.Series(np.random.choice(person_n,len(round_players)))      
gain_r1 = pd.DataFrame({'gain':choice_r1.value_counts()})                  
# 这一轮中每个人随机指定给“谁”1元钱,并汇总这一轮每个人的盈利情况
round_r1 = round_r1.join(gain_r1)
round_r1.fillna(0,inplace = True)
fortune[1] = round_r1['pre_round'] - round_r1['lost'] + round_r1['gain']
# 合并数据,得到这一轮财富分配的结果

1.2.4 构建模型

把前两轮游戏汇总成一个函数模型

def game1(data, roundi):
    if len(data[data[roundi - 1] ==0]) > 0:   
    # 当数据包含财富值为0的玩家时
        round_i = pd.DataFrame({'pre_round':data[roundi-1],'lost':0})
        con = round_i['pre_round'] > 0
        round_i['lost'][con] = 1               # 设定每轮分配财富之前的情况 → 该轮财富值为0的不需要拿钱给别人
        round_players_i = round_i[con]         # 筛选出参与游戏的玩家:财富值>0
        choice_i = pd.Series(np.random.choice(person_n,len(round_players_i)))
        gain_i = pd.DataFrame({'gain':choice_i.value_counts()})     # 这一轮中每个人随机指定给“谁”1元钱,并汇总这一轮每个人的盈利情况
        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:
    # 当数据不包含财富值为0的玩家时
        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()})       # 这一轮中每个人随机指定给“谁”1元钱,并汇总这一轮每个人的盈利情况
        round_i = round_i.join(gain_i)
        round_i.fillna(0,inplace = True)
        return round_i['pre_round'] -  round_i['lost'] + round_i['gain']
        # 合并数据,得到这一轮财富分配的结果

1.2.5 运行模型

执行代码,获得最终结果

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):
    fortune[round] = game1(fortune,round)   # 进行17000轮随机分配模拟
game1_result = fortune.T                    # 转置后得到结果数据 → 列为每一个人的id,行为每一轮的财富分配结果   
endtime = time.time()                       # 模型结束时间
print('模型总共用时%i秒' % (endtime - starttime))
# 计算时间

1.3 数据可视化

把模拟结果按财富值升序的顺序作出柱状图,同时输出图片,方便查看。
由于数据每轮变化波动较小,这里

  • 前100轮,每10轮绘制一个图
  • 100-1000轮,每100轮绘制一个图
  • 1000-17000轮,每400轮绘制一个图
os.chdir('C:\\Users\\Hjx\\Desktop\\财富分配游戏一')

def graph1(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,6))
        plt.bar(datai.index,datai.values,color='gray',alpha = 0.8,width = 0.9)
        plt.ylim((0,400))
        plt.xlim((-10,110))
        plt.title('Round %d' % n)
        plt.xlabel('PlayerID')
        plt.ylabel('Fortune')
        plt.grid(color='gray', linestyle='--', linewidth=0.5)
        plt.savefig('graph1_round_%d.png' % n, dpi=300)
# 创建绘图函数2

graph1(game1_result,0,100,10)
graph1(game1_result,100,1000,100)
graph1(game1_result,1000,17400,400)

print('finished!')
round0-round10600
round17000

从图可知,100人的财富值随游戏回合增加,贫富差距越来越明显。整体指数呈抛物线状,不过差距并不明显。

模拟实验开始前,我也曾以为无论进行多少轮,100人的财富值并无明显差异,毕竟每个人每一轮都必须拿出一元,而得到一元的概率是一样的。然而现实告诉你,富人和穷人就是这样出现的。

1.4 结果分析

对结果进行排序,增加累积和

round_17000_1 = pd.DataFrame({'money':game1_result.iloc[17000]}).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
部分数据展示

得出结论:

  • 经过17000轮,最富有的人财富值为404元相比于初始财富,为4.04倍
  • 6%的人掌握着群体约20%的财富,20%的人掌握着群体约50%的财富
  • 60%的人财富减少,低于100元
  • 9%的人财富不到原始财富的10%(即10元以下)

游戏二:允许借贷的社会

2.1 模型假设

  • 每个人初始基金100元
  • 从18岁到65岁,每天玩一次,简化运算按照一共玩17000轮
  • 每天拿出一元钱,并且随机分配给另一个人
  • 当某人的财富值降到0元时,允许财富值为负,即同样需要拿出1元钱给别人,有机会得到别人给出的钱

游戏二,我们允许借贷,当财富值为0时同样需要拿出钱,可以为负值,继续参与游戏。相当于现实世界的向亲友、银行、伙伴借钱,比较符合现今社会。

2.2 搭建模型

2.2.1 构建模型

不同于游戏一,这里可直接考虑为一种情况,不限制拿出收获金钱

def game2(data, roundi):
    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()})       # 这一轮中每个人随机指定给“谁”1元钱,并汇总这一轮每个人的盈利情况
    round_i = round_i.join(gain_i)
    round_i.fillna(0,inplace = True)
    return round_i['pre_round'] -  round_i['lost'] + round_i['gain']
    # 合并数据,得到这一轮财富分配的结果
print('finished!')

2.2.2 运行模型

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):
    fortune[round] = game2(fortune,round)   # 进行17000轮随机分配模拟
game2_result = fortune.T                    # 转置后得到结果数据 → 列为每一个人的id,行为每一轮的财富分配结果   
endtime = time.time()                       # 模型结束时间
print('模型总共用时%i秒' % (endtime - starttime))
# 计算时间

2.3 数据可视化

round_17000_2 = pd.DataFrame({'money':game2_result.iloc[17000]}).sort_values(by = 'money',ascending = False).reset_index()
round_17000_2['fortune_pre'] = round_17000_2['money'] / round_17000_2['money'].sum()
round_17000_2['fortune_cumsum'] = round_17000_2['fortune_pre'].cumsum()
round_17000_2.head(50)
部分数据展示

2.3.1 财富分布差异随时间的变化趋势

利用以上数据,来看看每个回合财富分布差异的大小

game2_st = game2_result.std(axis = 1)
game2_st.plot(figsize = (12,5),color = 'red',alpha = 0.6,grid = True)
plt.show()
财富标准差与回合数的关系

从图中可以发现,约6000回合前,财富标准差变化极快。而6000回合后,变化趋于稳定,在一定斜率上波动。
就于我们的游戏规则,可以得出财富值在每个人35岁左右已形成明显差异。35岁可以大致判定一个人是否事业有成。

2.3.2 “35岁”暂时失利,能否实现逆袭

游戏群体从18岁开始,为方便计算35岁的失利人群能否逆袭,18-35岁大致为6200个回合。
这里我们定义暂时失利的人群为6200回合后,财富值为负的人,看看此后他们能否逆袭(由负变正)

game2_round6200 = pd.DataFrame({'money':game2_result.iloc[6200].sort_values().reset_index()[6200],
                                'id':game2_result.iloc[6200].sort_values().reset_index()['id'],
                                'color':'gray'})
game2_round6200['color'][game2_round6200['money'] < 0] = 'red'
id_pc = game2_round6200['id'][game2_round6200['money'] < 0].tolist()
print('财富值为负的玩家id为:\n',id_pc)
# 筛选数据
# 设置颜色参数

plt.figure(figsize = (10,6))
plt.bar(game2_round6200.index,game2_round6200['money'],color = game2_round6200['color'],alpha = 0.8,width = 0.9)
plt.grid(color='gray', linestyle='--', linewidth=0.5)
plt.ylim((-200,400))
plt.xlim((-10,110))
plt.title('Round 6200')
plt.xlabel('PlayerID')
plt.ylabel('Fortune')
plt.show()
失利人群

接下来,我们查看他们6200-17000回合后的财富值变化情况

os.chdir('C:\\Users\\QJ\\Desktop\\项目13\\game2')

def graph2(data,start,end,length):
    for n in list(range(start,end,length)):
        datai = pd.DataFrame({'money':data.iloc[n],'color':'gray'})
        datai['color'].loc[id_pc] = 'red'
        datai = datai.sort_values(by = 'money').reset_index()
        plt.figure(figsize = (10,6))
        plt.bar(datai.index,datai['money'],color=datai['color'],alpha = 0.8,width = 0.9)
        plt.grid(color='gray', linestyle='--', linewidth=0.5)
        plt.ylim((-200,400))
        plt.xlim((-10,110))
        plt.title('Round %d' % n)
        plt.xlabel('PlayerID')
        plt.ylabel('Fortune')
        plt.savefig('graph2_round_%d.png' % n, dpi=200)

graph2(game2_result,6200,17000,500)

print('finished!')
35岁

42岁

49岁

64岁

最终,10人只有3人能逆袭成功。当中我们可以发现在在42岁,有4人逆袭且财富值能位列40名前后。然而在社会资金流运转下,最终只有3人逆袭,且财富值均属于超低水平。

2.4 结果分析

返回到游戏二整体数据,得出结论:

  • 经过17000轮,最富有的人财富值为498元相比于初始财富,为4.98倍
  • 5%的人掌握着群体约20%的财富,15%的人掌握着群体约50%的财富
  • 53%的人财富减少,低于100元
  • 25%的人破产,财富值为负数

对比游戏一和游戏二,我们可以发现,在允许借贷的条件下

  • 最富有的人财富值容易更高
  • 社会总资金更集中于少数人手里
  • 贫富差距增大,破产人群数量大

回归现实

破产人群并没有模拟实验的数字那么吓人,这是由于收入支出的不对等和社会福利的影响。
发现没有,模拟实验把每个人的收入支出几率对等化,然而现实并不会出现每个个体一样的工作待遇和消费支出,所以现实模型来得更为复杂多变。
为了继续游戏,对应现实,我们假设有10个人勤奋努力,获得1%的竞争优势,看看财富分配又会出现怎样的变化。

游戏三:努力就一定有回报?

3.1 模型假设

  • 每个人初始基金100元
  • 从18岁到65岁,每天玩一次,简化运算按照一共玩17000轮
  • 每天拿出一元钱,并且随机分配给另一个人
  • 当某人的财富值降到0元时,允许财富值为负,即同样需要拿出1元钱给别人,有机会得到别人给出的钱
  • 其中,有10人勤奋努力,获得1%的竞争优势(即每轮有0.0101的概率拿到1元,其他人则为0.899/90)

3.2 搭建模型

3.2.1 构建模型

这里,设置努力的10个人id 分别为:[1,11,21,31,41,51,61,71,81,91],方便后续跟踪观察。

person_p = [0.899/90 for i in range(100)]
for i in [1,11,21,31,41,51,61,71,81,91]:
    person_p[i-1] = 0.0101
# 设置概率

def game3(data, roundi):
    round_i = pd.DataFrame({'pre_round':data[roundi-1],'lost':1}) # 设定每轮分配财富之前的情况
    choice_i = pd.Series(np.random.choice(person_n,100, p = person_p))
    gain_i = pd.DataFrame({'gain':choice_i.value_counts()})       # 这一轮中每个人随机指定给“谁”1元钱,并汇总这一轮每个人的盈利情况
    round_i = round_i.join(gain_i)
    round_i.fillna(0,inplace = True)
    return round_i['pre_round'] -  round_i['lost'] + round_i['gain']
    # 合并数据,得到这一轮财富分配的结果
print('finished!')

运行模型

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):
    fortune[round] = game3(fortune,round)   # 进行17000轮随机分配模拟
game3_result = fortune.T                    # 转置后得到结果数据 → 列为每一个人的id,行为每一轮的财富分配结果   
endtime = time.time()                       # 模型结束时间
print('模型总共用时%i秒' % (endtime - starttime))
# 计算时间
数据展示

3.3 数据可视化

os.chdir('C:\\Users\\QJ\\Desktop\\项目13\\game3')

plt.figure(figsize = (10,6))
data0 = pd.DataFrame({'money':game3_result.iloc[0],'color':'gray'})
data0['color'].loc[[1,11,21,31,41,51,61,71,81,91]] = 'red'
plt.bar(data0.index,data0['money'],color=data0['color'],alpha = 0.8,width = 0.9)
plt.grid(color='gray', linestyle='--', linewidth=0.5)
plt.ylim((-200,400))
plt.xlim((-10,110))
plt.title('Round %d' % 0)
plt.xlabel('PlayerID')
plt.ylabel('Fortune')
plt.savefig('graph3_round_%d.png' % 0, dpi=200)
# 绘制起始图片

def graph3(data,start,end,length):
    for n in list(range(start,end,length)):
        datai = pd.DataFrame({'money':data.iloc[n],'color':'gray'})
        datai['color'].loc[[1,11,21,31,41,51,61,71,81,91]] = 'red'
        datai = datai.sort_values(by = 'money').reset_index()
        plt.figure(figsize = (10,6))
        plt.bar(datai.index,datai['money'],color=datai['color'],alpha = 0.8,width = 0.9)
        plt.grid(color='gray', linestyle='--', linewidth=0.5)
        plt.ylim((-200,400))
        plt.xlim((-10,110))
        plt.title('Round %d' % n)
        plt.xlabel('PlayerID')
        plt.ylabel('Fortune')
        plt.savefig('graph3_round_%d.png' % n, dpi=200)
# 创建绘图函数2

graph3(game3_result,10,100,10)
graph3(game3_result,100,1000,100)
graph3(game3_result,1000,17400,400)

print('finished!')
财富值变化

round17000

一分耕耘一分收获,努力的10人都冲到群体前列,财富值均有所提升,更包揽财富榜前三。所以说,努力是有回报的。

3.4 结果分析

富人和穷人的区别

模拟游戏考虑的角度较为简单,但清晰可见的是富人和穷人的关键区别无非两个字——努力。穷人总在抱怨壮志难酬,却很少发现富人之所以为富,在于他肯多下的1%努力,这将在多年后形成明显的差异。

然而现实更残酷,富人往往付出穷人500%的努力,甚至更多。马云上千亿身家,花费多少倍常人的努力,无法估量。

今天你努力了吗?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 在一片鞭炮声中几辆绿色军用大巴驶进我们这个小小营区,2009年度第一批新兵来到了向往已久的绿色军营。在热烈的掌声中...
    书写初心阅读 320评论 0 0
  • 看节目还要流泪。 过小年,我们各自自由收获。
    马上做阅读 123评论 0 0
  • 姓名:陈海帆 日期:2018年6月26日 名称:宁波万尚 六项精进403期努力三组学员 【日精进打卡第12天】 【...
    努力三组帆姐阅读 121评论 0 0
  • 沉沉夜色罩乾坤,独倚高楼饮薄酒 静听落雨击寒石,细闻冷风抚枯叶 谁识君心思故里,惟有深秋寒雨夜
    榆之木阅读 235评论 0 0