简体   繁体   中英

Netlogo - selecting a value from a weighted list based on a randomly drawn number

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!

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.

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.

Notes regarding the way you draw your random number

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 .

  1. It can give negative numbers but negative numbers are not contemplated in your 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 (ie "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 .
  2. I see that your 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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM