NetLogo跨海龟属性赋值异常及贷款审批流程优化问题
问题背景
在如下NetLogo模型中,银行仅可为信用评分匹配自身acceptable_scores属性内分值的客户发放贷款,若客户信用评分不匹配银行acceptable_scores中的任意值则会被拒贷。
globals [ scores ] breed [ customers customer ] breed [ banks bank ] customers-own [ loan_amount credit_score status ] banks-own [ acceptable_scores list_of_customers ] to setup clear-all ask patches [ set pcolor 8 ] set scores n-values 10 [random 900 + 10] create-customers 100 [ set loan_amount random-exponential 20000 set credit_score one-of scores set status "applied" ] create-banks 10 [ set acceptable_scores n-of (random 3 + 1) scores set list_of_customers [] ] reset-ticks end to go ask one-of banks [ fund-loan reject-loan ] tick end to fund-loan let person one-of customers-here with [ (member? credit_score [acceptable_scores] of myself) ] if person != nobody [ ask person [ set status "funded" ] set list_of_customers lput person list_of_customers ] end to reject-loan let person one-of customers-here with [ (not member? credit_score [acceptable_scores] of myself) ] if person != nobody [ ask person [ set status "funded" ] set list_of_customers lput person list_of_customers output-print list_of_customers ] end
用户尝试在完成贷款发放后将每一位获贷客户添加到list_of_customers列表中,对应实现代码如下:
set list_of_customers lput person list_of_customers
但实际打印输出时该列表始终为空,提出以下三个问题:
- 将一个海龟的ID添加至另一海龟属性的正确实现方式是什么?
- 从多主体建模规范来看,当前的贷款发放、拒贷处理逻辑是否为最优实现?
- 贷款发放与拒贷两类处理逻辑是否可以合并为单个函数实现?
问题解答
1. 海龟代理存储的正确实现,以及列表为空的原因
你写的set list_of_customers lput person list_of_customers本身语法完全正确:NetLogo原生支持直接把海龟代理(agent)存入列表,不需要特意提取数字ID,这种写法比存ID更方便——后续要操作列表里的客户时,不需要再通过who号反查代理,效率更高也不容易出错。如果确实需要存数字形式的ID,写法为lput ([who] of person) list_of_customers即可。
列表始终为空的核心原因是逻辑bug,和存储写法无关:
- 第一,
customers-here的使用无对应逻辑支撑:模型setup阶段创建客户和银行后,没有设计任何空间位置匹配规则,所有代理默认堆在原点(0,0),但你没有限制银行/客户的移动,一旦代理位置偏移,当前银行所在patch没有客户,customers-here就会返回空代理集,person始终为nobody,根本不会触发后续添加列表、打印的逻辑。 - 第二,打印逻辑只写在
reject-loan的执行分支里:如果当前银行没有找到符合拒贷条件的客户,哪怕放款逻辑已经把客户加入列表,也不会触发打印,你看不到输出就会误以为列表是空的。 - 额外提一个笔误:
reject-loan过程中给拒贷客户设置的状态是"funded",和放款状态完全一致,属于明显的逻辑错误。
2. 当前逻辑不符合多主体建模的规范要求,存在多处可优化点
当前实现远不是最优,主要问题如下:
- 无效的空间过滤:如果模型不需要模拟银行和客户的空间交互(比如线下网点覆盖、地域经营限制),用
customers-here筛选客户完全没有必要,只会引入额外bug。如果需要空间规则,就要在setup阶段明确给银行、客户分配位置,设计对应的匹配逻辑。 - 缺失状态过滤:筛选客户时没有加
status = "applied"的条件,会重复选中已经完成审批(放款/拒贷)的客户,不符合业务逻辑,也会导致重复统计。 - 逻辑冲突风险:同一个银行先后执行放款、拒贷逻辑,两个过程独立筛选客户,有可能选中同一个客户,出现先放款再拒贷的矛盾。
- 数据存储混乱:不管是放款还是拒贷的客户都往同一个
list_of_customers里存,没有区分审批结果,后续做统计分析时无法区分两类客户。
3. 两类逻辑完全可以合并为单个函数,且更推荐这种实现
合并后可以消除重复代码,避免逻辑冲突,参考实现如下:
to process-loan-applications ; 只筛选状态为待申请的客户,不需要空间规则就把customers-here改成customers let eligible-pool customers-here with [ status = "applied" ] ifelse any? eligible-pool [ let target one-of eligible-pool ifelse member? ([credit_score] of target) acceptable_scores [ ; 符合评分要求,放款 ask target [ set status "funded" ] ; 存储时同时标记客户审批结果,方便后续统计 set list_of_customers lput (list target "funded") list_of_customers ][ ; 不符合评分要求,拒贷 ask target [ set status "rejected" ] set list_of_customers lput (list target "rejected") list_of_customers ] output-print list_of_customers ][ output-print "No pending applications for current bank" ] end
对应把go过程里的逻辑改成调用单个函数即可:
to go ask one-of banks [ process-loan-applications ] tick end
内容的提问来源于stack exchange,提问作者capiono
相关产品推荐
相关产品推荐

