Chapter6 - 人工经济模型与turtle间的互动
本章将介绍一个人工经济模型,通过该模型进一步理解turtle之间的互动
6.1 货币转移模型
社会经济中有一个显著的现象:财富分布的不均衡性。
早在19世纪,意大利著名经济学家维弗雷多·帕累托(Vilfredo Pareto)就分析了大量实证数据,发现财富分布遵循一条幂律分布曲线。
这条幂律分布曲线满足帕累托法则(Pareto principle),也叫二八定律,即20%的财富被80%的穷人拥有(图中绿色的区域),而80%的财富被20%的富人占有(图中黄色的区域),二八定律充分反映了社会财富分布的不均衡性。
为了解释这种分布不均衡性,2000年,物理学家Victor M.Yakovenk提出了一个非常简单的人工经济模型:货币转移模型(money transfer model)。
在这个模型里,他把经济体比喻成分子,把货币量比喻成能量。对于一个气体系统来说,气体分子在碰撞过程中,能量只能从一个分子转移到另一个分子,而总能量保持守恒。经过大量碰撞,最终气体分子会达到一个非常不均等的能量分布状态。
货币在该模型中的分布也具有类似的特性。因此,货币转移模型符合如下基本规则:
- 经济系统中人和财富的总量保持不变;
- 开始的时候,每个人都有等量的货币;
- 每当两个主体相遇,他们就随机分配财富。
6.2 添加全局变量
首先打开NetLogo“界面”,添加两个按钮:“setup”和“go”,添加“go”按钮时勾选“持续执行”。然后添加一个全新的控件——“滑块”,使用滑块控件可以很方便地调整变量的数值。在“添加”下拉框中点选“滑块”,然后在空白处单击添加,这时会出现弹框,如图6-3所示。首先输入全局变量名称num_agents,代表主体个数,即货币转移模型中一共有多少人。“最小值”“增量”“最大值”用于设定数值变化范围,这里设定数值从1开始变到1000,增量是1,初始值设置成100,单击“确定”,这样全局变量就创建好了。拖动滑块,就可以看到变量的取值发生变化。
与此类似,我们可以再添加一个滑块来控制系统中的货币总量,变量名为total_money,取值范围选取1到1 000 000,增量为1,默认值设为10 000。这两个滑块所定义的总量值都可以在我们的代码中应用。
6.3 初始化模拟世界
1 | to setup |
6.4 主体之间如何交互
1 | to go |
- 在NetLogo里,let和set都是赋值语句,它们的用法一样,但二者有一个非常重要的区别:set只能应用于已经定义好的变量,而let适用于为第一次使用的变量赋值,它包含定义变量的意思。
比如变量agsets,前文并未定义,如果用set去赋值,系统会提示错误,所以这时必须使用let语句给agsets赋初始值。为什么以前没有遇到过let呢?比如初始化money时就没有定义过,其实turtles-own就给每一个turtle定义了money变量。另外像pcolor这样的变量,赋值前也没有先定义,但是pcolor是每一个patch都有的属性,它是NetLogo自带的变量,因此在初始化模拟世界时,patch的pcolor属性已经定义了。
other turtles-here
,顾名思义,就是其他所有turtles-here。第4章讲过,turtle和patch存在多个turtle对应一个patch的情况,比如当前turtle是我,我站在一个patch上,这个patch上也可能有其他turtle。turtles-here
返回值就是当前patch上包含了我的所有turtle的集合other turtles-here
返回值就是当前patch上除我以外其他turtle的集合,即我的潜在交易对象
one-of agsets
one-of agentset
,从集合agentset中随机选择一个元素;n-of n agentset
,从集合agentset中随机选择n个元素。- 当元素个数不满足时,比如集合为空,它返回的也为空;小于n时,就返回小于n的所有元素。
6.4.1 transaction模块
- 类比于函数,有自己的参数,通过方括号传入
let money1 ([money] of trader)
此处[money] of trader
相当于我们在写Java或者Python这种面向对象语言时用到的trader.money,在NetLogo中是用of来表示的,并且变量要用方括号括起来,如果要访问多个变量,可以用逗号隔开。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15to transaction [trader]
let deltam 0
let money1 ([money] of trader)
let epsilon (random-float 1)
set deltam (epsilon - 1) * money + epsilon * money1
if money + deltam >= 0 and money1 - deltam >= 0
[
set money money + deltam
ask trader[
set money money1 - deltam
]
]
end
6.4.2 变量作用域
在主体之间相互交互时,有一个关键点:变量的作用域。首先对所有turtle进行循环。因为每个turtle会随机选当前patch的另一个turtle做交易,所以transaction模块的所有变量,特别是money变量,隶属于当前turtle。也就是说,turtle在不停地进行循环。假如循环到的当前turtle是agent1,那么这时transaction模块的money就是agent1相应的属性
除去[money] of trader(方括号配合 of 的限定)
和set money money1 - deltam(作用域的限定)
中的money是trader的属性,其他money都是当前turtle也就是agent1的属性。在所有NetLogo程序里,一定要捋清楚变量到底隶属于谁,当出现多层嵌套的时候,一定要清楚其中任意一个变量到底是哪个主体的。
6.5 命令中心
在编程中,首先要保证语法通顺,但是在代码实现过程中,也可能有一些逻辑错误,这时系统并不会报错。针对这个例子,如何验证程序中的逻辑是否正确呢?根据货币转移模型规则,系统中的人和货币的总量不变,但是代码中并没有验证这两个量是否守恒,所以需要一个调试手段来验证程序的正确性。我们可以使用命令中心的功能,通过命令交互的方式来访问整个NetLogo的变量。比如对于货币总量,我们可以在“观察者”那里输入以下命令:sum [money] of turtles
它的作用就是把所有turtle的money组成一个集合,然后进行累加求和。
NetLogo是一个面向对象的层次性结构,它的最上层是observer,是由observer直接对整个系统进行操作的。因此我们刚才输入的命令实际是观察者(observer)输入的,它的返回结果也是由observer给出的。从返回值可以看到,它跟系统引入的货币量是一致的,小数是由于计算误差引起的,特别是过程中有随机小数把这些钱不停地进行分割,因此它在允许范围内会有一定误差。
6.6 绘制财富分布直方图
- 调整绘图笔为条形,这样它就会以柱状图的方式显示图形
- 绘图命令也要改,因为默认命令比较适合绘制时间序列曲线,例如横坐标轴是时间、纵坐标轴是种群数量的图形。但是当前需要绘制模型每一时刻的财富分布情况,因此要删掉绘图命令,并且修改X轴标记为Wealth,Y轴标记为Counts,在绘图更新命令中添加自定义函数——to-update-plot,这样在绘图时就会动态调用绘图更新命令。
histogram
直方图
- 定义一个变量lst,该变量的值是所有turtle的money属性组成的集合,lst是一个数值列表,其中每一个数值对应某个turtle的财富值。
- 设定了统计小区间的个数为100。
- if not empty? lst判断lst这个列表是否为空。这里empty? 是NetLogo自带的变量,该变量是一个布尔型变量,返回true或false。因此整个判断语句的意思是,如果lst不为空,则执行下面两行代码
set-plot-x-range 0 (max lst)
设定了X轴的取值范围是从0到财富值的最大值。在默认情况下,它的取值范围是0~10,但是这并不合理,因为当turtle发生交易后,财富值有可能非常大,所以这时我们要动态调整它的最大值。histogram lst
的作用是把lst变量以直方图的方式进行统计,并且把统计结果绘制到绘图界面。histogram是NetLogo自带的命令。- 保持模拟世界和绘图界面同步更新。在初始化代码中加入reset-ticks,然后在to go函数中添加tick进行计时,最后记得把“视图更新方式”选项改为“按时间步更新”
1
2
3
4
5
6
7
8to to-update-plot
let lst [money] of turtles
set-histogram-num-bars 100 ;; 设定了统计小区间的个数为100。
if not empty? lst [
set-plot-x-range 0 max lst
histogram lst
]
end
6.7 小结
1 | turtles-own [money] |