最近在知乎上看到一个很有趣的问题:房间里有100个人,每人都有100元钱,他们在玩一个游戏。每轮游戏中,每个人都要拿出一元钱随机给另一个人,最后这100个人的财富分布是怎样的?下面有3个选项,你会选什么?
我觉得大部分的人都会选择均匀分布,因为100个人每次都会支出,每次都会收入,那么财富分页应该是接近均匀分布的.那么通过模拟真实的数据是怎么样的呢?让我们来看看.
我们把这个游戏视为社会财富分配的简化模型,来模拟社会的运行规律.
假设我们每个人一开始都有100的资金,每天花费1元就当做日常的开支.
获得财富的几率就随机这是为了……简化模型嘛..模拟一次就相当于过了一天..
模拟750次就相当于2年的数据是怎样的呢?
看上去有点参差不齐,每个人之间的差距还是有的.为了更直观的表达差距.我给数据排序.
差距已经慢慢出现了,最富有的财富大约是最贫穷的6倍.总体来说差距并不是特别的大.那么继续模拟下去呢?这是 模拟2200次,大约6年的数据:
相对2年的来说,财富分布更趋向于幂律分布(结论只是数据模拟.并不是经过数学精确计算的结果).但是我们可以发现初始财富100的分界线也在50人那里.这也是肯定的,富人的收入也就是穷人的支出…..
所以说在公平的规则下,世界还是体现了残酷的一面
那再模拟一种情况,如果我们比别人努力5%,也就是从贸易竞争中多5%的几率获得资金.财富分布图是怎么样的呢. (红柱代表拥有5%的竞争优势)
这仅仅是模拟750次也就相当于2年的数据.财富前十居然有8人.如果竞争优势更大的话财富分部差距也会更大.
所以说要多努力.
下面就开始上代码了:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="Access-Control-Allow-Origin" content="*">
<title>柱形图</title>
<link rel="stylesheet" href="/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/bootstrap-table/bootstrap-table.css"/>
<script src="/js/jquery-2.2.3.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/vue.min.js"></script>
<script src="/js/echarts.js"></script>
<script>
$(function () {
var vm = new Vue({
el: "#app",
data: {
simulationtimes: 0,//模拟次数
peoplecount: 100,//模拟人数
initialmoney: 100,//初始资金
size: 1, //每次消耗的资金
myChart: '',
Xzhi: [],//表示X轴上的文字解释集合
Yzhi: [],//表示图中Y的值集合
IntervalID: 0,//循环setinterval的ID
maxmoney: 0,//最富有的人
minmoney: 0,//最穷的人
top10money: '',//最富的10人的资金和所占百分比
down10money: ''//最穷的10个人资金和所占百分比
},
methods: {
//为图初始化数据
chushidata: function () {
for (var i = 0; i < vm.peoplecount; i++) {
//初始化100条数据
this.Xzhi.push(i);
this.Yzhi.push(vm.initialmoney);
}
;
this.myChart = echarts.init(document.getElementById('maintu'));
var zhutuoption = {
color: ['#3398DB'],
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'line' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: this.Xzhi,
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
type: 'bar',
barWidth: '60%',
data: this.Yzhi,
}
]
};
//设置参数,绘制图形
this.myChart.setOption(zhutuoption);
},
//模拟改变数据.
changeval: function () {
var v2;
$("#ppllpp").empty();
//循环100人次,每次给别人1元,这里是随机产生被接收的人.
for (var v1 = 0; v1 < vm.peoplecount; v1++) {
if (this.Yzhi[v1] > 0) {
do {
v2 = parseInt(Math.random() * vm.peoplecount);
} while (v1 == v2);
this.Yzhi[v1] -= this.size;
this.Yzhi[v2] += this.size;
}
}
;
this.simulationtimes += 1;//模拟次数+1
//重新设置参数,图表才会重新刷新一次.
this.myChart.setOption({
series: [{
name: '成交',
data: this.Yzhi
}]
});
},
//财富排序.
sortYzhi: function () {//对资金进行排序
this.Yzhi.sort();//调用自带的sort方法会以初始的100位分界线进行排序,数据前为100以上,后为100以下,
this.Yzhi.sort(function (a, b) {
return a - b;
});
//数组排序后是递增向上的,所以最富有的是最后一个,最贫穷的是第一个元素.
this.maxmoney = this.Yzhi[this.peoplecount - 1];
this.minmoney = this.Yzhi[0];
var topint = 0, downint = 0;
//计算最富有十个人的财富与所占比例
for (var v = this.peoplecount - 1; v > this.peoplecount - 11; v--) {
topint += parseInt(this.Yzhi[v]);
}
;
//显示财富值,计算所占比例保留两位小数加上%
this.top10money = topint + ' ' + (topint / (this.peoplecount * this.initialmoney) * 100).toFixed(2) + '%';
//计算最贫穷十个人的财富与所占比例
for (var v = 0; v < 10; v++) {
downint += parseInt(this.Yzhi[v]);
}
;
this.down10money = downint + ' ' + (downint / (this.peoplecount * this.initialmoney) * 100).toFixed(2) + '%';
//重新设置图的数据以刷新图表
this.myChart.setOption({
series: [{
name: '成交',
data: this.Yzhi
}]
});
},
stopInterval: function () {//停止自动循环
clearInterval(this.IntervalID);
},
setIntervalchange: function () {//启动自动循环
this.IntervalID = setInterval(this.changeval, 50);//这里调用方法是不能加括号,只能用哪个this.changeval
}
},
mounted: function () {
this.$nextTick(function () {
vm.chushidata();
})
}
});
})
</script>
</head>
<body>
<div class="container" id="app">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="col-md-2 column">
<h4>柱形图,100人游戏</h4>
</div>
<div class="col-md-2 column">
<button class="btn btn-sm" v-on:click="changeval()">柱形图,100人游戏</button>
</div>
<div class="col-md-2 column">
<button class="btn btn-sm" v-on:click="setIntervalchange()">开始定时模拟</button>
</div>
<div class="col-md-2 column">
<button class="btn btn-sm" v-on:click="stopInterval()">暂停/结束模拟</button>
</div>
<div class="col-md-1 column">
<button class="btn btn-sm" v-on:click="sortYzhi()">排序</button>
</div>
</div>
<div class="col-md-12 column">
<h3>模拟次数:{{simulationtimes}}</h3>
</div>
<div class="col-md-12 column">
<div class="col-md-10 column">
<div id="maintu" style="width: 850px;height:400px;"></div>
</div>
<div class="col-md-2 column">
<h4>最富有的:{{maxmoney}}</h4>
<h4>最贫穷的:{{minmoney}}</h4>
<h4>最富有的十个人:{{top10money}}</h4>
<h4>最贫穷的十个人:{{down10money}}</h4>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
下面的代码是拥有5%竞争优势的代码
因为有10个人拥有竞争优势,所以在设置模型的时候就要把人名和财富值一一对应,所以在给数组赋值的时候就是赋一个对象进去。
for (var i = 0; i < vm.peoplecount; i++) {
this.Xzhi.push(i);
this.Yzhi.push(vm.initialmoney);
this.XYzhi.push({name: i, val: vm.initialmoney});
}
然后因为要让有用竞争优势的人标识出来,所以给优势的人红色,其他人黄色.当玩家的name小于10(10个竞争优势)时使用红色.
series: [
{
type: 'bar',
barWidth: '60%',
data: this.Yzhi,
itemStyle: {
//通常情况下:
normal: {
//每个柱子的颜色即为colorList数组里的每一项,如果柱子数目多于colorList的长度,则柱子颜色循环使用该数组
color: function (params) {
var colorList = ['rgb(238,0,0)', 'rgb(255,250,3)'];
if (params.name < 10) {
return colorList[0];
} else {
return colorList[1]
}
}
},
}
}
]
因为拥有的竞争优势,所以获得财富的几率也大了.拥有5%的优势.也就是所占的权重要大5%,假设普通人所占权重是100,优势人就是105,那么拥有优势的人的几率就是105*10人/(105*10人+100*90人),也就是105/1005.那么生成几率的代码:
//v2代表获得财富人的ID.
v2 = parseInt(Math.random() * vm.peoplecount);
var gl = parseInt(Math.random() * 1005);
if (gl < 105) {
v2 = parseInt(Math.random() * 10);
} else {
v2 = parseInt(Math.random() * (vm.peoplecount - 10) + 10);
}
整体代码如下:
排序和右边的log是没有实现的,就当做没看到…
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="Access-Control-Allow-Origin" content="*">
<title>柱形图</title>
<link rel="stylesheet" href="/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/bootstrap-table/bootstrap-table.css"/>
<script src="/js/jquery-2.2.3.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/vue.min.js"></script>
<script src="/js/echarts.js"></script>
<script>
$(function () {
var vm = new Vue({
el: "#app",
data: {
simulationtimes: 0,//模拟次数
peoplecount: 100,//模拟人数
initialmoney: 100,//初始资金
size: 1, //每次消耗的资金
myChart: '',
Xzhi: [],
Yzhi: [],
XYzhi: [],
IntervalID: 0,
maxmoney: 0,//最富有的人
minmoney: 0,//最穷的人
top10money: '',//最富的10人的资金和所占百分比
down10money: ''//最穷的10个人资金和所占百分比
},
methods: {
chushidata: function () {
for (var i = 0; i < vm.peoplecount; i++) {
this.Xzhi.push(i);
this.Yzhi.push(vm.initialmoney);
this.XYzhi.push({name: i, val: vm.initialmoney});
}
;
this.myChart = echarts.init(document.getElementById('maintu'));
var zhutuoption = {
color: ['#3398DB'],
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'line' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: this.Xzhi,
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
type: 'bar',
barWidth: '60%',
data: this.Yzhi,
itemStyle: {
//通常情况下:
normal: {
//每个柱子的颜色即为colorList数组里的每一项,如果柱子数目多于colorList的长度,则柱子颜色循环使用该数组
color: function (params) {
var colorList = ['rgb(238,0,0)', 'rgb(255,250,3)'];
// return colorList[params.dataIndex];
if (params.name < 10) {
return colorList[0];
} else {
return colorList[1]
}
}
},
}
}
]
};
this.myChart.setOption(zhutuoption);
},
changeval: function () {
var v2;
$("#ppllpp").empty();
$.each(this.XYzhi, function (i, v) {
if (v.val > 0) {
do {
v2 = parseInt(Math.random() * vm.peoplecount);
var gl = parseInt(Math.random() * 1005);
if (gl < 105) {
v2 = parseInt(Math.random() * 10);
} else {
v2 = parseInt(Math.random() * (vm.peoplecount - 10) + 10);
}
} while (v.name == v2);
v.val -= vm.size;
vm.Yzhi[i] -= vm.size;
vm.Yzhi[v2] += vm.size;
$.each(vm.XYzhi, function (ii, vv) {
if (vv.name == v2) {
vv.val += vm.size;
}
})
}
});
this.simulationtimes += 1;
this.myChart.setOption({
series: [{
name: '成交',
data: this.Yzhi
}]
});
},
sortYzhi: function () {//对资金进行排序
this.XYzhi.sort();//调用自带的sort方法会以初始的100位分界线进行排序,数据前为100以上,后为100以下,
this.XYzhi.sort(function (a, b) {
return a.val - b.val;
});
//数组排序后是递增向上的,所以最富有的是最后一个,最贫穷的是第一个元素.
this.maxmoney = this.Yzhi[this.peoplecount - 1];
this.minmoney = this.Yzhi[0];
var topint = 0, downint = 0;
//计算最富有十个人的财富与所占比例
for (var v = this.peoplecount - 1; v > this.peoplecount - 11; v--) {
topint += parseInt(this.Yzhi[v]);
}
;
//显示财富值,计算所占比例保留两位小数加上%
this.top10money = topint + ' ' + (topint / (this.peoplecount * this.initialmoney) * 100).toFixed(2) + '%';
//计算最贫穷十个人的财富与所占比例
for (var v = 0; v < 10; v++) {
downint += parseInt(this.Yzhi[v]);
}
;
this.down10money = downint + ' ' + (downint / (this.peoplecount * this.initialmoney) * 100).toFixed(2) + '%';
this.Xzhi = [];
this.Yzhi = [];
$.each(this.XYzhi, function (i, v) {
vm.Xzhi.push(v.name);
vm.Yzhi.push(v.val);
});
//重新设置图的数据以刷新图表
this.myChart.setOption({
xAxis: [
{
data: this.Xzhi,
}
],
series: [{
name: '成交',
data: this.Yzhi
}]
});
},
stopInterval: function () {//停止自动循环
clearInterval(this.IntervalID);
},
setIntervalchange: function () {//启动自动循环
this.IntervalID = setInterval(this.changeval, 50);//这里调用方法是不能加括号,只能用哪个this.changeval
}
},
mounted: function () {
this.$nextTick(function () {
vm.chushidata();
})
}
});
})
</script>
</head>
<body>
<div class="container" id="app">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="col-md-2 column">
<h4>柱形图,100人游戏</h4>
</div>
<div class="col-md-2 column">
<button class="btn btn-sm" v-on:click="changeval()">柱形图,100人游戏</button>
</div>
<div class="col-md-2 column">
<button class="btn btn-sm" v-on:click="setIntervalchange()">开始定时模拟</button>
</div>
<div class="col-md-2 column">
<button class="btn btn-sm" v-on:click="stopInterval()">暂停/结束模拟</button>
</div>
<div class="col-md-1 column">
<button class="btn btn-sm" v-on:click="sortYzhi()">排序</button>
</div>
</div>
<div class="col-md-12 column">
<h3>模拟次数:{{simulationtimes}}</h3>
</div>
<div class="col-md-12 column">
<div class="col-md-10 column">
<div id="maintu" style="width: 850px;height:400px;"></div>
</div>
<div class="col-md-2 column">
<h4>最富有的:{{maxmoney}}</h4>
<h4>最贫穷的:{{minmoney}}</h4>
<h4>最富有的十个人:{{top10money}}</h4>
<h4>最贫穷的十个人:{{down10money}}</h4>
</div>
<div class="col-md-1 column">
<div v-for="va in XYzhi">
<h5>{{va.val+' '+va.name}}</h5>
</div>
</div>
<div class="col-md-1 column">
<div v-for="va in Yzhi">
<h5>{{va}}</h5>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
代码作者是可以运行的,如果有问题的话可以邮件:lijiazhen2017@gmail.com