如何在Python的Mesa囚徒困境模型中获取邻居上一步行动?
问题分析与修复方案
核心问题
- 空列表触发
max()报错:当所有邻居(含自身)上一步行动都是D时,best_neighbors为空,直接调用max()会抛出max() arg is an empty sequence错误。 - Memory记录不完整:仅在时间步0时记录行动,后续时间步未更新
memory,导致后续时间步无法正确获取邻居上一步的行动(甚至触发索引越界)。 - 邻居范围可选调整:原代码获取邻居时包含自身(
include_center=True),若你希望仅参考其他智能体,需修改该参数。
修复后的完整代码
class PDAgent(Agent): def __init__(self, pos, model, starting_move=None): """ Create a new Prisoner's Dilemma agent. pos: (x, y) tuple of the agent's position. model: model move: C(cooperating) or D(defecting) score: score of the agent """ super().__init__(pos, model) self.pos = pos self.score = 0 if starting_move: self.move = starting_move else: self.move = self.random.choice(["C", "D"]) self.memory = [] # 初始化时记录初始行动(对应时间步0) self.memory.append(self.move) def step(self): """Get the best neighbor's move, and change own move accordingly if better than own score.""" # 获取邻居:若不需要包含自己,将include_center改为False neighbors = self.model.grid.get_neighbors(self.pos, True, include_center=True) best_neighbors = [] current_time = self.model.schedule.time # 时间步0:仅计算初始得分,不调整行动 if current_time == 0: self.score += self.increment_score() return # 时间步>=1:收集上一步行动为C的邻居 if current_time >= 1: # 先检查邻居的memory是否有对应时间步的记录,防止索引越界 for neighbor in neighbors: if len(neighbor.memory) > current_time - 1: if neighbor.memory[current_time - 1] == "C": best_neighbors.append(neighbor) # 没有符合条件的邻居,直接保持当前行动 if not best_neighbors: return # 找到得分最高的合作型邻居 best_neighbor = max(best_neighbors, key=lambda a: a.score) # 仅当邻居得分更高时,切换行动 if best_neighbor.score > self.score: self.move = best_neighbor.move def increment_score(self): neighbors = self.model.grid.get_neighbors(self.pos, True) # 基于上一轮的行动计算得分(符合囚徒困境常规规则,可按需调整) moves = [neighbor.memory[-1] for neighbor in neighbors] return sum(self.model.payoff[(self.memory[-1], move)] for move in moves) def advance(self): """每个时间步结束后,记录当前行动到memory,供下一轮参考""" self.memory.append(self.move)
关键修改说明
- 完善Memory记录:初始化时就把初始行动存入
memory,新增advance()方法(Mesa框架中,step()算决策,advance()更新状态),确保每个时间步后都记录当前行动,后续能正确获取上一步的行动数据。 - 提前处理空列表:在调用
max()前先判断best_neighbors是否为空,为空则直接返回,避免报错。 - 索引安全检查:增加
len(neighbor.memory) > current_time -1的判断,防止因个别智能体的memory未更新导致索引越界。 - 得分逻辑修正:把原代码中基于当前
move计算得分,改为基于上一轮行动(memory[-1]),符合囚徒困境的常规规则。 - 简化冗余逻辑:删除无意义的
self.move = self.move语句,直接用return保持行动即可。
内容的提问来源于stack exchange,提问作者Emmina
相关产品推荐
相关产品推荐

