您的位置:首页 > 编程语言 > Python开发

Python 数据分析微专业课程--项目实战12 财富分配实验

2018-09-04 21:43 656 查看

1.项目说明

构建财富分配模型,模拟不允许借贷情况下的财富分配,允许借贷下的财富分配,努力型人生的财富分配

2.项目具体要求

1、财富分配模型
模型假设:
① 每个人初始基金100元
② 从18岁到65岁,每天玩一次,简化运算按照一共玩17000轮
③ 每天拿出一元钱,并且随机分配给另一个人
④ 当某人的财富值降到0元时,他在该轮无需拿出1元钱给别人,但仍然有机会得到别人给出的钱
要求:
① 构建模型模拟(这里需要跑17000轮)
② 绘制柱状图,查看该轮财富情况
③ 查看最后财富分配数据是什么分布?
④ 最富有的人相比于初始财富,翻了多少倍?
⑤ 10%的人掌握着多少的财富?30%的人掌握着多少的财富?又有百分之多少人财富缩水至100元以下了?

2、在允许借贷情况下,研究以下问题
和初始模型的区别:
允许借贷意味着可以找亲友、银行、投资人借贷 → 资产为负时,仍然参与游戏
要求:
① 构建模型模拟,再次模拟财富分配情况
② 绘制柱状图,查看该轮财富情况
③ 游戏次数与财富分布的标准差的情况,绘图来表示
④ 玩家从18岁开始,在经过17年后为35岁,这个期间共进行游戏6200次左右,则此刻查看财富情况,将财富值为负的标记成“破产”,通过图表研究
该类玩家在今后的游戏中能否成功“逆袭”(财富值从负到正为逆袭)

3、努力的人生会更好吗?
模型假设:
① 每个人初始基金仍为100元
② 一共玩17000轮
③ 每天拿出一元钱,并且随机分配给另一个人
④ 有10个人加倍努力,从而获得了1%的竞争优势
⑤ 允许借贷
要求:
① 构建模型模拟,再次模拟财富分配情况
② 努力的人,最后是否富有?
③ 绘制柱状图,查看该轮财富情况

3.实现思路:

1.首先构建模型的假设,这里有四个假设,根据这四个假设,使用随机数来模拟给钱和得到钱。首先模拟第一轮的财富分配,
然后扩展到多轮的分配,不考虑借贷的情况,使用for循环来进行多轮分配,并绘制柱状图,查看指定轮的财富情况

2.考虑借贷情况下构建模型,这里增加一个假设:当财富为0时可以向他人借贷继续游戏,即允许财富值为负数。通过多轮模拟情况研究一个问题,
即当玩家财富为负之后有多大可能变为正数。这里采用颜色标记的方法,在玩家为35岁时,将财富为负数的玩家标记为红色,然后查看红色标记的变迁情况。

3.这里在允许借贷的情况下再增加一个假设:如果有人的人生更加努力,竞争优势增加1%。在增加这个假设的情况下构建模型来模拟财富分配,
一次来研究努力型的人生是否可以获得更加多的财富

4.实现过程:

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

import warnings
warnings.filterwarnings('ignore')

start_time = time.time()

#模拟第一轮游戏分配,不考虑财富降到零的情况
person_n = [x for x in range(1,101)] #模拟100人Id
fortune = pd.DataFrame([100 for i in range(100)],index =person_n ) #初始财富状况
fortune.index.name = 'id'  #重命名index
round_r1 = pd.DataFrame({'pre_round':fortune[0],'lost':1}) #第一轮每个人拿出一块钱
choice_r1 = pd.Series(np.random.choice(person_n,100)) #100块对100人做随机分配
gain_r1 = pd.DataFrame({'gain':choice_r1.value_counts()}) #计算随机分配后的获利情况
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'] #第一轮分配后的财富情况
print(fortune)

#模拟第一轮游戏分配,考虑财富降到零的情况
#过程与不考虑财富到零的情况大致相同
person_n = [x for x in range(1,101)]
fortune1 = pd.DataFrame([100 for i in range(100)],index =person_n )
fortune1.index.name = 'id'
round_r1 = pd.DataFrame({'pre_round':fortune1[0],'lost':1})
#判断前一轮分配后是否有人财富为0,若为0,则本次分配不需要支出1元,即支出为0
for i in range(1,101):
if round_r1.loc[i,'pre_round'] ==0:
round_r1.loc[i,'lost']=0
#计算本轮分配金额分配给100人
choice_r1 = pd.Series(np.random.choice(person_n,round_r1['lost'].sum()))
#计算随机分配后的获利情况
gain_r1 = pd.DataFrame({'gain':choice_r1.value_counts()})
round_r1 = round_r1.join(gain_r1)
round_r1.fillna(0,inplace = True)
#计算本轮分配后的财富情况
fortune1[1] = round_r1['pre_round']-round_r1['lost']+round_r1['gain']
print(fortune)

#① 构建模型模拟(这里需要跑17000轮)'
#创建财富分配模型 ---初始模型
def fortune_game1(r):
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'
for i in range(1,r+1):
round_r = pd.DataFrame({'pre_round':fortune[i-1],'lost':1})
for n in range(1,101):
if round_r.loc[n,'pre_round'] ==0:
round_r.loc[n,'lost']=0
choice_r = pd.Series(np.random.choice(person_n,round_r['lost'].sum()))
gain_r = pd.DataFrame({'gain':choice_r.value_counts()})
round_r = round_r.join(gain_r)
round_r.fillna(0,inplace = True)
fortune[i] = round_r['pre_round']-round_r['lost']+round_r['gain']
return fortune

#创建绘图函数,绘制运行指定次数之后的财富情况柱状图--不允许借贷,不排序
def plot1(data,start,end,length):
for i in range(start,end,length):
plt.figure(figsize = (12,6))
x = np.arange(100)
plt.bar(x,data[i],color = 'gray',width = 0.9,alpha = 0.8,edgecolor = 'black')
plt.title('第%i轮' % i)
plt.xlabel('PlayerID')
plt.ylabel('Fortune')
plt.ylim(0,400)
plt.xlim(-10,110)
plt.grid(linestyle = '--')
plt.savefig('第%i轮.png' % i)

#初始模型_不排序绘图
#保存图片路径
os.chdir(r'D:\IT\python数据分析师\项目13\初始模型_不排序绘制')

#用初始模型模拟财富分配,运行17000次
fortune1 = fortune_game1(17000)

#不排序绘制柱状图
#前100轮,每10轮绘制一次
plot1(fortune1,0,100,10)
#200至1000轮,每100次绘制一次
plot1(fortune1,100,1000,100)
#1000后每400次绘制一次
plot1(fortune1,1000,17400,400)




#创建绘图函数,绘制运行指定次数之后的财富情况柱状图--排序
def plot2(data,start,end,length):
for i in range(start,end,length):
plt.figure(figsize = (12,6))
x = np.arange(100)
plt.bar(x,data[i].sort_values(),color = 'gray',width = 0.9,alpha = 0.8,edgecolor = 'black')
plt.title('第%i轮' % i)
plt.xlabel('PlayerID')
plt.ylabel('Fortune')
plt.ylim(0,400)
plt.xlim(-10,110)
plt.grid(linestyle = '--')
plt.savefig('第%i轮.png' % i)

#初始模型_排序绘图
#保存图片路径
os.chdir(r'D:\IT\python数据分析师\项目13\初始模型_排序绘制')

#排序绘制柱状图
#前100轮,每10轮绘制一次
plot2(fortune1,0,100,10)
#200至1000轮,每100次绘制一次
plot2(fortune1,100,1000,100)
#1000后每400次绘制一次
plot2(fortune1,1000,17400,400)




#结论
from scipy import stats
u = fortune1[17000].mean()
std = fortune1[17000].std()
stats.kstest(fortune1[17000], 'norm', (u, std))
final_result =fortune1[[17000]].sort_values(by =17000,ascending = False).reset_index(drop=True)
final_result.columns = ['money']
final_result['propotion'] = final_result['money']/final_result['money'].sum()
final_result['cum_propotion'] = final_result['propotion'].cumsum()
print('根据KS正态性检验,财富分配整体呈正太分布')
print('最富有人财富为%i,最穷人财富为%i,最富有的人财富比初始财富增加%.2f倍!'
%(final_result['money'].max(),final_result['money'].min(),final_result['money'].max()/100))
print('财富榜前10名掌握%.2f的财富,前20名掌握%.2f的财富' % (final_result.iloc[9,2],final_result.iloc[19,2]))
print('有%.2f的人的财富缩水到100以下' % (len(final_result[final_result['money']<100])/100))

说明:
1.创建模型的最关键的一步是根据假设模拟出最基本的情景,然后再进行扩展,这里的最基本的情景是模拟出第一轮的财富分配,即用代码实现一百个人,初始值100元,每人抽取1元,随机分配给100个人,分配后所有人还剩下多少钱整个分配步骤。
2.模拟第一轮后再对模型进行扩展:当财富值降为零时,不允许借贷。再对模型进行简单调整,这里是加入一个for循环使用if语句对所有人的财富值进行判断,如果等于0,则将支出变为0。这样即可满足这个假设。
3.这样就可是创建一个函数:不允许借贷情况下的财富分配模型。对这个函数进行17000次循环,就是从18岁到65岁,每天玩一次,简化运算按照一共玩17000轮。
这里为了查看循环期间财富值的状况,因此创建两个绘图函数,绘制每个玩家的财富值柱状图,分为排序和不排序。
4.经过17000轮游戏后通过计算最后财富值可得到以下结论:
a.根据KS正态性检验,财富分配整体呈正太分布
b.最富有人财富为296,最穷人财富为1,最富有的人财富比初始财富增加2.96倍!
c.财富榜前10名掌握26%的财富,前20名掌握45%的财富
d.有56%的人的财富缩水到100以下

'''
2、在允许借贷情况下,研究以下问题
和初始模型的区别:
允许借贷意味着可以找亲友、银行、投资人借贷 → 资产为负时,仍然参与游戏
要求:
① 构建模型模拟,再次模拟财富分配情况
** 最富有的人相比于初始财富,翻了多少倍?
** 10%的人掌握着多少的财富?30%的人掌握着多少的财富?又有百分之多少人财富缩水至100元以下了?
② 绘制柱状图,查看该轮财富情况
** 横轴标签代表一个玩家的编号,柱子的高低变动反映该玩家财富值的变化
** 这里只需要每轮按照财富值排序绘制
** 前100轮,按照每10轮绘制一次柱状图,查看财富变化情况
** 100至1000轮,按照每100轮绘制一次柱状图,查看财富变化情况
** 1000至17000轮,按照每400轮绘制一次柱状图,查看财富变化情况
③ 游戏次数与财富分布的标准差的情况,绘图来表示
** 这里用允许借贷情况下模拟的结果
** 横坐标为游戏次数(总共17000次),纵坐标为财富分配标准差
** 绘制折线图
④ 玩家从18岁开始,在经过17年后为35岁,这个期间共进行游戏6200次左右,则此刻查看财富情况,将财富值为负的标记成“破产”,通过图表研究
该类玩家在今后的游戏中能否成功“逆袭”(财富值从负到正为逆袭)、
** 这里绘制柱状图 → 6200至17000轮,按照每500轮绘制一次柱状图
提示:
① 该模型只需要将初始模型中,“财富小于零时无需拿钱给别人”的条件删掉即可
② 最后绘制柱状图时,需要将负债的玩家标红,这里可以通过截取dataframe之后,给与color字段来设置颜色
'''

#允许借贷情况下的财富分配模型
def fortune_game2(r,color='gray'):
person_n = [x for x in range(1,101)]
#在初始数据汇总加入颜色字段,默认为'gray'
fortune = pd.DataFrame({'color':['gray' for i in range(100)],0:[100 for i in range(100)]},index =person_n )
fortune.index.name = 'id'
for i in range(1,r+1):
round_r = pd.DataFrame({'pre_round':fortune[i-1],'lost':1})
choice_r = pd.Series(np.random.choice(person_n,100))
gain_r = pd.DataFrame({'gain':choice_r.value_counts()})
round_r = round_r.join(gain_r)
round_r.fillna(0,inplace = True)
fortune[i] = round_r['pre_round']-round_r['lost']+round_r['gain']

#当运行6200次时,对小于0的行设置特别颜色,若没有该参数,则默认为'gray'
if i ==6200:
fortune.loc[fortune[i]<0,'color'] =color
return fortune

#创建绘图函数,绘制运行指定次数之后的财富情况柱状图--允许借贷情况下
def plot3(data,start,end,length):
for i in range(start,end,length):
plt.figure(figsize = (12,6))
data1  = data.sort_values(i)
x = np.arange(100)
#绘制柱状图,使用数据颜色字段设置柱子颜色
plt.bar(x,data1[i],color = data1['color'],width = 0.9,alpha = 0.8,edgecolor = 'black')
plt.title('第%i轮' % i)
plt.xlabel('PlayerID')
plt.ylabel('Fortune')
plt.ylim(-300,500)
plt.xlim(-10,110)
plt.grid(linestyle = '--')
plt.savefig('第%i轮.png' % i)

'''
② 绘制柱状图,查看该轮财富情况
** 横轴标签代表一个玩家的编号,柱子的高低变动反映该玩家财富值的变化
** 这里只需要每轮按照财富值排序绘制
** 前100轮,按照每10轮绘制一次柱状图,查看财富变化情况
** 100至1000轮,按照每100轮绘制一次柱状图,查看财富变化情况
** 1000至17000轮,按照每400轮绘制一次柱状图,查看财富变化情况
'''
os.chdir(r'D:\IT\python数据分析师\项目13\允许借贷')

#使用允许借贷模型模拟财富分配,运行17000次,颜色默认'gray'
fortune2 = fortune_game2(17000)

#允许借贷情况下绘制柱状图
#前100轮,每10轮绘制一次
plot3(fortune2,0,100,10)
#200至1000轮,每100次绘制一次
plot3(fortune2,100,1000,100)
#1000后每400次绘制一次
plot3(fortune2,1000,17400,400)





'''
③ 游戏次数与财富分布的标准差的情况,绘图来表示
** 这里用允许借贷情况下模拟的结果
** 横坐标为游戏次数(总共17000次),纵坐标为财富分配标准差
** 绘制折线图
'''
std_lst=[]
#循环获取标准差,添加至list
for i in range(0,17001):
std_lst.append(fortune2[i].std())
#生成Series
std_s = pd.Series(std_lst)
#绘制折线图
std_s.plot(figsize = (12,6),color = 'blue',alpha = 0.6,xlim = [0,17000],ylim=[0,140],grid = True)
plt.savefig('财富标准差.png')

'''
④ 玩家从18岁开始,在经过17年后为35岁,这个期间共进行游戏6200次左右,则此刻查看财富情况,将财富值为负的标记成“破产”,通过图表研究
该类玩家在今后的游戏中能否成功“逆袭”(财富值从负到正为逆袭)、
** 这里绘制柱状图 → 6200至17000轮,按照每500轮绘制一次柱状图
'''
#允许借贷情况下,负债玩家逆袭情况
os.chdir(r'D:\IT\python数据分析师\项目13\允许借贷_负债玩家逆袭')

#使用允许借贷模型模拟财富分配,运行17000次,6200轮时破产的人设置颜色为'red',来观察之后是否有逆袭
fortune3 = fortune_game2(17000,'red')

#绘制状图观察6200轮之后的财富分配情况
plot3(fortune3,6200,17000,500)

#结论--允许借贷情况下
final_result1 =fortune2[[17000]].sort_values(by =17000,ascending = False).reset_index(drop=True)
final_result1.columns = ['money']
final_result1['propotion'] = final_result1['money']/final_result1['money'].sum()
final_result1['cum_propotion'] = final_result1['propotion'].cumsum()
print('允许借贷情况下:')
print('最富有人财富为%i,最穷人财富为%i,最富有的人财富比初始财富增加%.2f倍!'
%(final_result1['money'].max(),final_result1['money'].min(),final_result1['money'].max()/100))
print('财富榜前10名掌握%.2f%%的财富,前20名掌握%.2f%%的财富' % (final_result1.iloc[9,2]*100,final_result1.iloc[19,2]*100))
print('有%.2f%%的人的财富缩水到100以下' % ((len(final_result[final_result1['money']<100])/100)*100))
print('2000轮之前的标准差变化较大,之后逐渐平缓')
print('允许借贷情况下,贫富差距会变得更加大!')




说明:
1.通过调整基本模型来实现允许借贷的情况下的财富分配模拟,同时为了实现对6200轮之后时财富值为零的人的观测,在模型中加入颜色标签字段,在6200轮时将财富值为零的人的颜色标签设置为红色。
2.创建新的绘图函数,使用颜色标签的字段设置柱子的颜色,这样可以看到6200之后红色柱子的财富变化情况。
3.计算每一轮分配之后财富的标准差,根据标准差绘制折线图,看看贫富差距的变化情况。
4.根据以上模拟和分析可得以下结论:
a.最富有人财富为383,最穷人财富为-288,最富有的人财富比初始财富增加3.83倍!
b.财富榜前10名掌握32.54%的财富,前20名掌握56.61%的财富
c.有51.00%的人的财富缩水到100以下
d.2000轮之前的标准差变化较大,之后逐渐平缓
e.允许借贷情况下,贫富差距会变得更加大!

'''
3、努力的人生会更好吗?
模型假设:
① 每个人初始基金仍为100元
② 一共玩17000轮
③ 每天拿出一元钱,并且随机分配给另一个人
④ 有10个人加倍努力,从而获得了1%的竞争优势
⑤ 允许借贷
允许借贷意味着可以找亲友、银行、投资人借贷 → 资产为负时,仍然参与游戏
要求:
① 构建模型模拟,再次模拟财富分配情况
② 努力的人,最后是否富有?
③ 绘制柱状图,查看该轮财富情况
** 横轴标签代表一个玩家的编号,柱子的高低变动反映该玩家财富值的变化
** 这里只需要每轮按照财富值排序绘制
** 前100轮,按照每10轮绘制一次柱状图,查看财富变化情况
** 100至1000轮,按照每100轮绘制一次柱状图,查看财富变化情况
** 1000至17000轮,按照每400轮绘制一次柱状图,查看财富变化情况
提示:
① 这里设置的10个人id分别为:[1,11,21,31,41,51,61,71,81,91]
② np.random.choice(person_n, p =[...]) → 这里通过设置p来修改概率:努力的10人概率为0.0101,其他人概率为(0.899/90)
'''
#允许借贷情况下努力人生财富分配模型
def fortune_game3(r):
person_n = [x for x in range(1,101)]
fortune = pd.DataFrame({'color':['gray' for i in range(100)],0:[100 for i in range(100)]},index =person_n )
fortune.index.name = 'id'
#设置分配概率
p=[0.899/90 for i in range(100)]
#调高10个努力的人 10%的分配概率,颜色设置为'red'
for i in  range(1,92,10):
fortune.loc[i,'color'] = 'red'
p[i-1] = 0.0101

for i in range(1,r+1):
round_r = pd.DataFrame({'pre_round':fortune[i-1],'lost':1})
choice_r = pd.Series(np.random.choice(person_n,100,p = p))
gain_r = pd.DataFrame({'gain':choice_r.value_counts()})
round_r = round_r.join(gain_r)
round_r.fillna(0,inplace = True)
fortune[i] = round_r['pre_round']-round_r['lost']+round_r['gain']
return fortune

#努力对财富分配有什么影响
os.chdir(r'D:\IT\python数据分析师\项目13\努力人生')

#使用努力人生财富分配模型模拟财富分配,运行17000次
fortune4 = fortune_game3(17000)

#前100轮,每10次绘制一次
plot3(fortune4,0,100,10)
#200至1000轮,每100次绘制一次
plot3(fortune4,100,1000,100)
#1000后每400次绘制一次
plot3(fortune4,1000,17400,400)

print('10为努力玩家中多位都进入了财富排行前10,努力型人生有更大的概率成功!')

time_end = time.time()
print('time cost:',time_end-time_start)
print('Finish!')




说明:
1.努力型人生财富分配模型是在允许借贷模型基础上做一些调整得到的,在模型中加入一个概率列表,将10位玩家的概率提升1%,同时在颜色标签字段中,将这10为玩家的颜色设置为红色,这样可以通过柱状图看到这10为玩家的财富变化情况。
2.通过17000次分配模拟可看到10为努力玩家中多位都进入了财富排行前10,努力型人生有更大的概率成功!

5.总结

  • 这个财富分配模拟实际上就是模特卡罗模拟,使用随机数来模拟符合概率统计特征的事物,例如说这里的财富分配。虽然现实中财富分配有很多人为因素,
  • 但是如果样本量足够大,在这样范围中在分配财富就具有随机性了,所以,后财富分配符合正太分布这样一个特征。
  • 使用模特卡罗模拟可以模拟很多复杂的情景,因此如果需要分析一项很复杂又无法获得大量的数据事情时,可以使用蒙特卡罗模拟来创建模型,这样可以
    可以获得该事情的基本特征,并以此来对未知的情况进行预测。
阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐