一見平等なトレードから必然的に不平等が生まれる(pythonシミュレーション)
池谷裕二さんの「脳はなにげに不公平」を読んでいて、初っ端から面白そうで試すのが簡単そうなお話があったので、pythonでシミュレーションしてみた。
シミュレーション内容
「100人のプレイヤー全員に1万円を渡す。100人の中からランダムに2人選び、1人目から2人目へと千円渡す。これを繰り返す」
たったこれだけだ。ただし、話を簡単にするため残金0の場合に借金はできないものとする。
全員が平等に初期資金をもらい、全員が同じようにもらう側になり、全員が同じように渡す側にもなり得る。ルールは明らかに平等だ。誰も贔屓などされていないし、誰も差別されていない。「不公平だ」なんていう文句は、この時点ではつけようがない。
シミュレーション
では実際にpythonでシミュレーションをしてみよう。プレイヤーおよびその所持金はnumpyの配列で表現する。
import numpy as np num = 100#プレイヤーの数 players = 10000*np.ones(num,np.int32)#プレイヤーを用意して10000円ずつ渡す
この時点での配列の中身を一応確認しておこう。
print("初期状態:\n",players) print("トレード前平均所持金:",np.mean(players)) print("\n") #実行結果 初期状態: [10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000] トレード前平均所持金: 10000.0
まあ当然、全員が1万円を持っている。平均が1万円なのも当たり前だろう。
次に、トレードを行う関数を作る。
#プレイやーiからプレイヤーjに1000円渡す def trade(players): i,j=np.random.randint(0,num,2)#ランダムに2人を選ぶ if (players[i] > 0):#残金があるかどうか確認 players[i]-=1000 players[j]+=1000 else: pass#プレイヤーiの残金がゼロの場合はトレード不成立
あとはトレードを繰り返せば良い。
#トレードを繰り返す times = 10000#トレードの回数 for _ in range(times): trade(players)
…わざわざ関数化する必要もなかったかも。では結果を見てみよう
print("{}回トレード後:\n".format(times),players) print("トレード後平均所持金:",np.mean(players)) print("\n") #実行結果 10000回トレード後: [ 9000 2000 19000 11000 0 7000 8000 7000 11000 5000 10000 5000 4000 20000 22000 1000 4000 3000 22000 1000 1000 19000 10000 20000 8000 3000 16000 4000 21000 1000 28000 8000 7000 0 2000 0 25000 34000 0 24000 12000 10000 34000 15000 9000 22000 19000 14000 1000 20000 2000 10000 2000 0 13000 7000 9000 22000 0 2000 24000 1000 0 2000 5000 11000 4000 0 5000 15000 3000 18000 28000 9000 21000 8000 22000 35000 11000 12000 3000 0 6000 3000 6000 8000 4000 5000 40000 1000 2000 7000 19000 0 4000 6000 7000 12000 4000 4000] トレード後平均所持金: 10000.0
数字の羅列を見てもよくわからないので、ヒストグラムにした方がよいだろう。
#ヒストグラムを表示 import matplotlib.pyplot as plt plt.hist(players)
以下のようなグラフが得られた。
なんと、たったこれだけのトレードでも「大多数の貧乏人とごく一部の大富豪」という、現実世界と同じ格差が生まれてしまったのだ!しかも恐ろしいことに、これだけの格差があったとしても「平均所持金」だけを見ると、常に10000円なのだ(当たり前だが)!平均ボーナスだとか平均貯蓄額などの数字を見るたびに現実と乖離している印象を受けるのは正規分布から大きく外れたこの格差が原因なわけだ。
まとめ
非常に平等な条件でのトレードから格差が生まれることをシミュレーションによって確認した。ちなみにこの不平等な分布はボルツマン分布と呼ばれ、数学的には自明らしい。らしいというのは、恥ずかしながら私は統計学や数理解析には詳しくなく、このような時にどう定式化すれば解析解が導けるのかという「理論屋の方法論・思考法」みたいなものがよく分からないのだ。このくらいの問題は理論計算出来る人間になりたいものだ。というわけで、この問題からボルツマン分布を解析的に導く方法をご存知の方がいたら是非教えて欲しい。
最後に、今回使用したプログラムを整理して掲載しておく。
import numpy as np import matplotlib.pyplot as plt num = 100#プレイヤーの数 times = 10000#トレードの回数 players = 10000*np.ones(num,np.int32)#プレイヤーを用意して10000円ずつ渡す print("初期状態:\n",players) print("トレード前平均所持金:",np.mean(players)) print("\n") #プレイやーiからプレイヤーjに1000円渡す def trade(players): i,j=np.random.randint(0,num,2)#ランダムに2人を選ぶ if (players[i] > 0):#残金があるかどうか確認 players[i]-=1000 players[j]+=1000 else: pass#プレイヤーiの残金がゼロの場合はトレード不成立 #トレードを繰り返す for _ in range(times): trade(players) print("{}回トレード後:\n".format(times),players) print("トレード後平均所持金:",np.mean(players)) print("\n") #ヒストグラムを表示 plt.hist(players)