Reputation: 21
I'm looking for some help with selecting a value from a weighted list based on a randomly drawn number.
Think of my list as an empirical cumulative distribution function for a random variable, where the random variable is flood-prob. The first number in each pair of the list represents a depth and the last number in the pair is the weight/probability.
Suppose the random number drawn for the flood-prob variable is 0.66, how would I then select the corresponding depth from my list? or the approximate value?
extensions [ rnd ]
globals [probabilities depths ecdf flood-prob]
to-report create-ecdf
set probabilities [0.056 0.061 0.073 0.083 0.087 0.095 0.103 0.110 0.115 0.117 0.121 0.125 0.132 0.135 0.141 0.144 0.146 0.153 0.158 0.161 0.166 0.171 0.176 0.183 0.186 0.193 0.199 0.205 0.206 0.211 0.219 0.225 0.229 0.232 0.242 0.246 0.253 0.256 0.261 0.270 0.273 0.280 0.290 0.293 0.300 0.309 0.315 0.317 0.328 0.332 0.335 0.342 0.348 0.357 0.360 0.369 0.379 0.383 0.392 0.399 0.403 0.415 0.424 0.429 0.432 0.442 0.447 0.450 0.462 0.463 0.472 0.486 0.491 0.499 0.507 0.520 0.525 0.540 0.548 0.561 0.571 0.583 0.596 0.605 0.612 0.628 0.636 0.646 0.661 0.679 0.685 0.695 0.715 0.726 0.735 0.752 0.762 0.771 0.790 0.800 0.814 0.826 0.836 0.847 0.859 0.872 0.880 0.883 0.898 0.904 0.911 0.920 0.926 0.935 0.939 0.953 0.957 0.967 0.974 0.979 0.986 0.987 0.993 0.997 0.999]
set depths [2.80399990081787 2.82999992370605 2.88599991798401 2.92899990081787 2.94400000572205 2.97499990463257 3.00300002098083 3.02500009536743 3.04200005531311 3.04800009727478 3.06100010871887 3.07200002670288 3.09299993515015 3.1010000705719 3.11800003051758 3.125 3.13100004196167 3.14800000190735 3.16100001335144 3.17000007629395 3.18099999427795 3.19400000572205 3.20600008964539 3.22300004959106 3.22900009155273 3.24499988555908 3.2590000629425 3.27099990844727 3.27300000190735 3.28299999237061 3.29999995231628 3.31200003623962 3.3199999332428 3.32699990272522 3.34599995613098 3.35400009155273 3.36800003051758 3.37400007247925 3.3840000629425 3.3989999294281 3.40599989891052 3.41899991035461 3.43600010871887 3.44099998474121 3.4539999961853 3.46900010108948 3.48000001907349 3.48399996757507 3.50200009346008 3.50799989700317 3.51399993896484 3.52500009536743 3.53500008583069 3.54999995231628 3.5550000667572 3.5699999332428 3.58599996566772 3.59299993515015 3.60700011253357 3.61800003051758 3.62400007247925 3.64299988746643 3.65700006484985 3.66499996185303 3.66899991035461 3.68499994277954 3.69300007820129 3.69700002670288 3.71499991416931 3.71799993515015 3.73099994659424 3.75200009346008 3.75999999046326 3.77300000190735 3.78500008583069 3.80399990081787 3.81299996376038 3.83500003814697 3.84800004959106 3.86800003051758 3.88299989700317 3.90199995040894 3.92199993133545 3.93600010871887 3.94799995422363 3.97300004959106 3.98699998855591 4.00299978256226 4.02799987792969 4.05800008773804 4.06799983978271 4.08500003814697 4.11999988555908 4.1399998664856 4.15799999237061 4.19000005722046 4.20900011062622 4.22800016403198 4.26599979400635 4.28800010681152 4.31799983978271 4.34700012207031 4.37099981307983 4.39900016784668 4.42999982833862 4.46600008010864 4.49100017547607 4.5 4.55100011825562 4.57000017166138 4.59600019454956 4.63199996948242 4.65500020980835 4.69799995422363 4.7189998626709 4.7979998588562 4.82399988174438 4.89799976348877 4.95699977874756 5.02099990844727 5.11899995803833 5.13100004196167 5.27099990844727 5.44799995422363 5.64300012588501]
set ecdf (map list depths probabilities) ;; First number is depth, second number is probability.
set flood-prob random-normal 0.26 0.22
;; Need help from here onwards in selecting the appropriate value...
end
I have tried using rnd:weighted-one-of-list but it is unsuitable. I think I need some code that uses the drawn value of flood-prob to relate to an item index in the list that is approximate to it, from which I can extract the corresponding depth.
I've been stuck on this for a while so any help is greatly appreciated, thanks in advance!
Upvotes: 2
Views: 190
Reputation: 2926
I second Luke's remarks on (1) making sure whether you want to use random-normal
rather than just a uniform 0-to-1 sample, considering that the values in the probabilities
list already shape the distribution (but there is more to this, I'll talk about it at the end of the answer), and (2) moving the creation of your global values to setup
so that this happens only once.
That said, here I propose a different, light approach to achieve your goal which only relies on the two existing lists and might also have the advantage of readability.
In English: create your random value and compare it to each value in the probabilities
list, in order, until you find a value in the probabilities
list that is not smaller than the random value. Keep track of the position of the item (from probabilities
) being compared. When you find the probability value that is not smaller than the random value, extract the item from depths
that is found in the same position.
In NetLogo:
globals [ depths probabilities ]
to setup
clear-all
set depths [2.80399990081787 2.82999992370605 2.88599991798401 2.92899990081787 2.94400000572205 2.97499990463257 3.00300002098083 3.02500009536743 3.04200005531311 3.04800009727478 3.06100010871887 3.07200002670288 3.09299993515015 3.1010000705719 3.11800003051758 3.125 3.13100004196167 3.14800000190735 3.16100001335144 3.17000007629395 3.18099999427795 3.19400000572205 3.20600008964539 3.22300004959106 3.22900009155273 3.24499988555908 3.2590000629425 3.27099990844727 3.27300000190735 3.28299999237061 3.29999995231628 3.31200003623962 3.3199999332428 3.32699990272522 3.34599995613098 3.35400009155273 3.36800003051758 3.37400007247925 3.3840000629425 3.3989999294281 3.40599989891052 3.41899991035461 3.43600010871887 3.44099998474121 3.4539999961853 3.46900010108948 3.48000001907349 3.48399996757507 3.50200009346008 3.50799989700317 3.51399993896484 3.52500009536743 3.53500008583069 3.54999995231628 3.5550000667572 3.5699999332428 3.58599996566772 3.59299993515015 3.60700011253357 3.61800003051758 3.62400007247925 3.64299988746643 3.65700006484985 3.66499996185303 3.66899991035461 3.68499994277954 3.69300007820129 3.69700002670288 3.71499991416931 3.71799993515015 3.73099994659424 3.75200009346008 3.75999999046326 3.77300000190735 3.78500008583069 3.80399990081787 3.81299996376038 3.83500003814697 3.84800004959106 3.86800003051758 3.88299989700317 3.90199995040894 3.92199993133545 3.93600010871887 3.94799995422363 3.97300004959106 3.98699998855591 4.00299978256226 4.02799987792969 4.05800008773804 4.06799983978271 4.08500003814697 4.11999988555908 4.1399998664856 4.15799999237061 4.19000005722046 4.20900011062622 4.22800016403198 4.26599979400635 4.28800010681152 4.31799983978271 4.34700012207031 4.37099981307983 4.39900016784668 4.42999982833862 4.46600008010864 4.49100017547607 4.5 4.55100011825562 4.57000017166138 4.59600019454956 4.63199996948242 4.65500020980835 4.69799995422363 4.7189998626709 4.7979998588562 4.82399988174438 4.89799976348877 4.95699977874756 5.02099990844727 5.11899995803833 5.13100004196167 5.27099990844727 5.44799995422363 5.64300012588501]
set probabilities [0.056 0.061 0.073 0.083 0.087 0.095 0.103 0.110 0.115 0.117 0.121 0.125 0.132 0.135 0.141 0.144 0.146 0.153 0.158 0.161 0.166 0.171 0.176 0.183 0.186 0.193 0.199 0.205 0.206 0.211 0.219 0.225 0.229 0.232 0.242 0.246 0.253 0.256 0.261 0.270 0.273 0.280 0.290 0.293 0.300 0.309 0.315 0.317 0.328 0.332 0.335 0.342 0.348 0.357 0.360 0.369 0.379 0.383 0.392 0.399 0.403 0.415 0.424 0.429 0.432 0.442 0.447 0.450 0.462 0.463 0.472 0.486 0.491 0.499 0.507 0.520 0.525 0.540 0.548 0.561 0.571 0.583 0.596 0.605 0.612 0.628 0.636 0.646 0.661 0.679 0.685 0.695 0.715 0.726 0.735 0.752 0.762 0.771 0.790 0.800 0.814 0.826 0.836 0.847 0.859 0.872 0.880 0.883 0.898 0.904 0.911 0.920 0.926 0.935 0.939 0.953 0.957 0.967 0.974 0.979 0.986 0.987 0.993 0.997 0.999]
end
to-report depth-based-on-probability
let this-random-number random-normal 0.26 0.22
let index 0
while [this-random-number > item index probabilities] [
set index index + 1
]
report item index depths
end
However, note that while this is a fast and light approach, it still needs some aspects to be fixed which require some further considerations. See below.
random-normal
can generate values that are outside of your range of probabilities
. This is true in general, but also very much in particular for your random-normal 0.26 0.22
.
probabilities
list. You would not get an error in that case, because this-random-number > item index probabilities
will evaluate as FALSE
on the first iteration of while
and the procedure will just report the first element of depths
. However this makes me wonder whether occasionally having negative values is something you planned for, considering that the effect of this is to increase the probability that the first element of depths
is extracted (i.e. "increase" beyond the level specified in probabilities
, which is 0.056). Using random-float 1
instead of random-normal
will eliminate this issue while still following the shape of your distribution, because the shape is given by the values in probabilities
.probabilities
reach 0.999. There is absolutely no guarantee that random-normal 0.26 0.22
will give values lower than 0.999, as it can actually give values that are not only greater than 0.999 but also greater than 1. This will give you an error, because at some point the index
value will grow to the point that item index probabilities
does not exist, and the model will interrupt with an error. If my understanding is correct, your intention is to have probabilities
and depths
such that these two lists map all the possible events. Again, a correct way to do it would be to use random-float 1
(which guarantees that you get a value 0 <= x < 1) AND setting the last item of your probabilities
list as 1 (and not 0.999).Summarising the above, the resulting code would look like:
globals [ depths probabilities ]
to setup
clear-all
set depths [2.80399990081787 2.82999992370605 2.88599991798401 2.92899990081787 2.94400000572205 2.97499990463257 3.00300002098083 3.02500009536743 3.04200005531311 3.04800009727478 3.06100010871887 3.07200002670288 3.09299993515015 3.1010000705719 3.11800003051758 3.125 3.13100004196167 3.14800000190735 3.16100001335144 3.17000007629395 3.18099999427795 3.19400000572205 3.20600008964539 3.22300004959106 3.22900009155273 3.24499988555908 3.2590000629425 3.27099990844727 3.27300000190735 3.28299999237061 3.29999995231628 3.31200003623962 3.3199999332428 3.32699990272522 3.34599995613098 3.35400009155273 3.36800003051758 3.37400007247925 3.3840000629425 3.3989999294281 3.40599989891052 3.41899991035461 3.43600010871887 3.44099998474121 3.4539999961853 3.46900010108948 3.48000001907349 3.48399996757507 3.50200009346008 3.50799989700317 3.51399993896484 3.52500009536743 3.53500008583069 3.54999995231628 3.5550000667572 3.5699999332428 3.58599996566772 3.59299993515015 3.60700011253357 3.61800003051758 3.62400007247925 3.64299988746643 3.65700006484985 3.66499996185303 3.66899991035461 3.68499994277954 3.69300007820129 3.69700002670288 3.71499991416931 3.71799993515015 3.73099994659424 3.75200009346008 3.75999999046326 3.77300000190735 3.78500008583069 3.80399990081787 3.81299996376038 3.83500003814697 3.84800004959106 3.86800003051758 3.88299989700317 3.90199995040894 3.92199993133545 3.93600010871887 3.94799995422363 3.97300004959106 3.98699998855591 4.00299978256226 4.02799987792969 4.05800008773804 4.06799983978271 4.08500003814697 4.11999988555908 4.1399998664856 4.15799999237061 4.19000005722046 4.20900011062622 4.22800016403198 4.26599979400635 4.28800010681152 4.31799983978271 4.34700012207031 4.37099981307983 4.39900016784668 4.42999982833862 4.46600008010864 4.49100017547607 4.5 4.55100011825562 4.57000017166138 4.59600019454956 4.63199996948242 4.65500020980835 4.69799995422363 4.7189998626709 4.7979998588562 4.82399988174438 4.89799976348877 4.95699977874756 5.02099990844727 5.11899995803833 5.13100004196167 5.27099990844727 5.44799995422363 5.64300012588501]
set probabilities [0.056 0.061 0.073 0.083 0.087 0.095 0.103 0.110 0.115 0.117 0.121 0.125 0.132 0.135 0.141 0.144 0.146 0.153 0.158 0.161 0.166 0.171 0.176 0.183 0.186 0.193 0.199 0.205 0.206 0.211 0.219 0.225 0.229 0.232 0.242 0.246 0.253 0.256 0.261 0.270 0.273 0.280 0.290 0.293 0.300 0.309 0.315 0.317 0.328 0.332 0.335 0.342 0.348 0.357 0.360 0.369 0.379 0.383 0.392 0.399 0.403 0.415 0.424 0.429 0.432 0.442 0.447 0.450 0.462 0.463 0.472 0.486 0.491 0.499 0.507 0.520 0.525 0.540 0.548 0.561 0.571 0.583 0.596 0.605 0.612 0.628 0.636 0.646 0.661 0.679 0.685 0.695 0.715 0.726 0.735 0.752 0.762 0.771 0.790 0.800 0.814 0.826 0.836 0.847 0.859 0.872 0.880 0.883 0.898 0.904 0.911 0.920 0.926 0.935 0.939 0.953 0.957 0.967 0.974 0.979 0.986 0.987 0.993 0.997 1]
end
to-report depth-based-on-probability
let this-random-number random-float 1
let index 0
while [this-random-number >= item index probabilities] [
set index index + 1
]
report item index depths
end
Note above the use of random-float
and the new last item of probabilities
.
However also note that an important difference is in the condition for while
: I included >=
instead of simply >
. This has to do with the way conditions with random-float
(or random
if working with integers) are conceived in NetLogo. In fact, random x
reports a value greater than or equal to 0, but strictly less than x. This means that a 50% chance is represented by random 2 < 1
, and you can write a 12% chance as random 100 < 12
or random-float 1 < 0.12
.
It follows that, looking for example at the first element of your lists, you want to extract the depth of 2.80399990081787 if random-float 1 < 0.56
. It means that you want the condition to evaluate as FALSE
when this-random-number < item index probabilities
, which means that it has to evaluate as TRUE
when this-random-number >= item index probabilities
.
Having the last item of probabilities
as 1 will ensure that this-random-number >= item index probabilities
is always FALSE
for the last item (because random-float 1
is always strictly less than 1), which is exactly what you need when using while
loops in order to avoid infinite loops or, in your case, runtime errors (as explained in point 2 above).
Upvotes: 1
Reputation: 10301
If you're using this ecdf in the way I'm imagining (to generate random points within your empirical distribution), you may want to confirm that random-normal
is the correct distribution to sample for your generation rather than a random uniform selection from 0 to 1 to sample from the inverse cdf- but I may be misunderstanding your purpose here (and, I haven't looked at the shape of your provided points).
If you just want to match the closest values between your flood-prob
and the list of possible probabilities, you could determine the minimum absolute differences between flood-prob
and the list then use that new list to pull the index value to pull from your depths:
globals [ probabilities depths ]
to setup
ca
set probabilities [0.056 0.061 0.073 0.083 0.087 0.095 0.103 0.110 0.115 0.117 0.121 0.125 0.132 0.135 0.141 0.144 0.146 0.153 0.158 0.161 0.166 0.171 0.176 0.183 0.186 0.193 0.199 0.205 0.206 0.211 0.219 0.225 0.229 0.232 0.242 0.246 0.253 0.256 0.261 0.270 0.273 0.280 0.290 0.293 0.300 0.309 0.315 0.317 0.328 0.332 0.335 0.342 0.348 0.357 0.360 0.369 0.379 0.383 0.392 0.399 0.403 0.415 0.424 0.429 0.432 0.442 0.447 0.450 0.462 0.463 0.472 0.486 0.491 0.499 0.507 0.520 0.525 0.540 0.548 0.561 0.571 0.583 0.596 0.605 0.612 0.628 0.636 0.646 0.661 0.679 0.685 0.695 0.715 0.726 0.735 0.752 0.762 0.771 0.790 0.800 0.814 0.826 0.836 0.847 0.859 0.872 0.880 0.883 0.898 0.904 0.911 0.920 0.926 0.935 0.939 0.953 0.957 0.967 0.974 0.979 0.986 0.987 0.993 0.997 0.999]
set depths [2.80399990081787 2.82999992370605 2.88599991798401 2.92899990081787 2.94400000572205 2.97499990463257 3.00300002098083 3.02500009536743 3.04200005531311 3.04800009727478 3.06100010871887 3.07200002670288 3.09299993515015 3.1010000705719 3.11800003051758 3.125 3.13100004196167 3.14800000190735 3.16100001335144 3.17000007629395 3.18099999427795 3.19400000572205 3.20600008964539 3.22300004959106 3.22900009155273 3.24499988555908 3.2590000629425 3.27099990844727 3.27300000190735 3.28299999237061 3.29999995231628 3.31200003623962 3.3199999332428 3.32699990272522 3.34599995613098 3.35400009155273 3.36800003051758 3.37400007247925 3.3840000629425 3.3989999294281 3.40599989891052 3.41899991035461 3.43600010871887 3.44099998474121 3.4539999961853 3.46900010108948 3.48000001907349 3.48399996757507 3.50200009346008 3.50799989700317 3.51399993896484 3.52500009536743 3.53500008583069 3.54999995231628 3.5550000667572 3.5699999332428 3.58599996566772 3.59299993515015 3.60700011253357 3.61800003051758 3.62400007247925 3.64299988746643 3.65700006484985 3.66499996185303 3.66899991035461 3.68499994277954 3.69300007820129 3.69700002670288 3.71499991416931 3.71799993515015 3.73099994659424 3.75200009346008 3.75999999046326 3.77300000190735 3.78500008583069 3.80399990081787 3.81299996376038 3.83500003814697 3.84800004959106 3.86800003051758 3.88299989700317 3.90199995040894 3.92199993133545 3.93600010871887 3.94799995422363 3.97300004959106 3.98699998855591 4.00299978256226 4.02799987792969 4.05800008773804 4.06799983978271 4.08500003814697 4.11999988555908 4.1399998664856 4.15799999237061 4.19000005722046 4.20900011062622 4.22800016403198 4.26599979400635 4.28800010681152 4.31799983978271 4.34700012207031 4.37099981307983 4.39900016784668 4.42999982833862 4.46600008010864 4.49100017547607 4.5 4.55100011825562 4.57000017166138 4.59600019454956 4.63199996948242 4.65500020980835 4.69799995422363 4.7189998626709 4.7979998588562 4.82399988174438 4.89799976348877 4.95699977874756 5.02099990844727 5.11899995803833 5.13100004196167 5.27099990844727 5.44799995422363 5.64300012588501]
reset-ticks
end
to-report pull-depth-from-dist
; Random flood dist value
let flood-prob random-normal 0.26 0.22
; Select the closest prob (could also average the depths values instead if preferred)
let dif-vals map [ i -> abs ( i - flood-prob ) ] probabilities
let dif-index position ( min dif-vals ) dif-vals
let closest-depth item dif-index depths
print word "flood-prob: " flood-prob
print word "closest prob: " item dif-index probabilities
report closest-depth
end
Note that I've moved the definition of probabilities / depths to the setup so that it's only being called on setup, rather than within the reporter.
Upvotes: 0