本文通过简化了社会财富分配的过程,使用Python进行模拟计算,得出了几个有趣的结论。
本文的灵感来源于城市数据团发布的一篇文章:该如何面对这个残酷的世界?
在这篇文章中,把社会财富分配问题简化成一个零和游戏,游戏基础规则如下:
房间里有100个人,每人都有100元钱,他们在玩一个游戏。每轮游戏中,每个人都要拿出一元钱随机给另一个人,最后这100个人的财富分布是怎样的?
结果更符合均匀分布、正态分布还是幂律(power law)分布?
接下来我们通过参考蒙特卡罗模拟算法的思想,使用Python对这个游戏的过程进行模拟,得出结论。
如果还不了解蒙特卡罗模拟算法的,可以参考我的上一篇文章:如何通过Python实现蒙特卡罗模拟算法
1.财富分配模型
模型假设
- 每个人初始基金100元;
- 从18岁到65岁,每天玩一次,简化运算按照一共玩17000轮;
- 每天拿出一元钱,并且随机分配给另一个人;
- 当某人的财富值降到0元时,他在该轮无需拿出1元钱给别人,但仍然有机会得到别人给出的钱。
Python模拟
有了以上的模型假设,我们就可以开始使用Python进行模拟游戏。
首先需要构造初始数据集,给100个玩家,每个人分配初始资金100元:
# 构造初始数据集:100个玩家,每个人都有100元初始资金
players_num = 100
players = range(1, players_num+1) # 玩家编号
df = pd.DataFrame({
'player': players,
'money': [100] * players_num
})
接着,模拟整个游戏过程,把每一轮的财富分配结果都保存下来:
result = [] # 存储每次分配结果
total_round = 17000 # 总共轮次
# 保存还未开始游戏时每个玩家的的财富
result.append([0] + df['money'].to_list())
for round in range(1, total_round+1):
# 幸运鹅数量
lucky_guys_num = len(df[df['money'] > 0])
# 每个人的财富都减1(除非没钱了)
df['money'] = df['money'].apply(lambda x: x-1 if x > 0 else 0)
# 计算每个人增加的金额
lucky_guys = np.random.choice(players, size=lucky_guys_num) # 有多少个人-1,就抽取多少次
lucky_guys_bonus = Counter(lucky_guys) # 幸运鹅对应的奖励金额
df['money'] = df.apply(lambda row: lucky_guys_bonus.get(row['player'], 0) + row['money'], axis=1)
result.append([round] + df['money'].to_list()) # 轮次以及每个玩家的财富
print(f'Round {round}')
# 所有财富分配的结果
result_df = pd.DataFrame(result, columns=