我在 NetLogo 中有一个包含值的列表以及每个值的概率列表。现在我想根据概率抽取一个随机值(加权随机抽取)。我想过使用 Rnd 扩展,但我不太清楚如何获得正确的权重,请帮忙
set values [1 2 3]
set probabilities [0.2 0.3 0.5]
set state ( rnd:weighted-one-of agentset reporter-task )
如果您想使用 any 概率,而不仅仅是那些加起来为 1 的概率,您可以在不使用 rnd 扩展的情况下执行此操作。例如,如果您想根据得票数选择候选人 1、2 或 3:
to-report weighted-rand
let values [1 2 3]
;let probabilities [0.2 0.3 0.5]
let votes [5 7 9]
; calculate the cumulative probability list
let cum reduce [
lput (?2 + (ifelse-value (empty? ?1) [0] [last ?1])) ?1
] (fput [] votes)
; Roll a uniform random number weighted by the cumulative probability vector
let x random-float sum votes
let j -1
let found false
while [(not found) and (j < (length cum))]
[
set j (j + 1)
if (x <= item j cum) [set found true]
]
report item j values
end
这有点复杂(尤其是减少的棘手使用),但它基本上所做的是创建概率(投票)的累积和,然后找到该列表中均匀随机值下降的位置。然后它从与找到的位置相对应的值列表中返回该项目。
如果您想要/需要为您的值和概率使用两个单独的列表,则方法是让扩展程序选择一个 index 并使用该索引来访问传递给
rnd:weighted-one-of
的报告器中的概率和,一旦选择,即为列表中的值。这就是下面代码中的example1
。
但是,如果您可以将值和概率放在同一个列表中,则扩展会更容易使用。这是通过构建“对”列表(即每个子列表中包含两个项目的列表列表)来完成的。有了它后,您可以在报告器中使用该对中的第二个项目 (
item 1
),并使用该对中的第一个项目 (item 0
) 设置您的状态。 example2
展示了如何执行此操作。
extensions [ rnd ]
to example1
let values [1 2 3]
let probabilities [0.2 0.3 0.5]
let indices n-values length values [ ? ]
let index rnd:weighted-one-of indices [ item ? probabilities ]
let state item index values
end
to example2
let pairs [[1 0.2] [2 0.3] [3 0.5]]
let state item 0 rnd:weighted-one-of pairs [ item 1 ? ]
end
编辑:
正如 Seth 在评论中提到的,您可以使用
(map list values probabilities)
从两个单独的列表构建配对列表。他还提到,代码可能“使用 first
和 last
而不是 item 0
和 item 1
更清晰。”
example3
整合了这两个建议:
to example3
let values [1 2 3]
let probabilities [0.2 0.3 0.5]
let pairs (map list values probabilities)
let state first rnd:weighted-one-of pairs [ last ? ]
end
基于 theoden 的答案,这里有一个适应较新的 NetLogo reduce 语法的版本:
to-report weighted-rand [ values votes ]
; Calculate the cumulative probability list
let cum reduce [ [ acc curr ] -> lput (curr + (ifelse-value (empty? acc) [0] [ last acc ])) acc ] (fput [] votes)
; Roll a uniform random number weighted by the cumulative probability vector
let x random-float sum votes
let j -1
let found false
while [(not found) and (j < (length cum))]
[
set j (j + 1)
if (x <= item j cum) [set found true]
]
report item j values
end