0

I just discovered an error in my model where I create a population with a household-size distribution and dependent age distribution. My problem is that my procedure doesn't seem to assign the probabilities for each outcome correctly when deciding the age. I am supposed to have 16% elderly but my model gives me 3% (of tot population).

I think this has to do with the internal order of the procedure, as elderly are assigned last. See below code.

Procedure for assigning household-size:

to hatch-family ; hatching the rest of the household using percentual distribution of household size in berlin population
  ifelse random-float 1 <= 0.01 [set household-size 6  set dwelling patch-here hatch 5]
  [ifelse random-float 1 <= 0.02 [set household-size 5 set dwelling patch-here hatch 4]
    [ifelse random-float 1 <= 0.06 [set household-size 4  set dwelling patch-here hatch 3]
      [ifelse random-float 1 <= 0.11 [set household-size 3 set dwelling patch-here hatch 2]
        [ifelse random-float 1 <= 0.31 [set household-size 2 set dwelling patch-here hatch 1]
          [ifelse random-float 1 <= 0.49 [set household-size 1 set dwelling patch-here]
          [hatch-family]
  ]]]]]
end

Procedure for assigning age:

to assign-age; assign age depending on household size according to distribution on csv file,
             ;i = the different rows representing different household sizes
  get-age-data
  if household-size = 1 [get-age-breed 1]
  if household-size = 2 [get-age-breed 2]
  if household-size = 3 [get-age-breed 3]
  if household-size = 4 [get-age-breed 4]
  if household-size = 5 [get-age-breed 5]
  if household-size = 6 [get-age-breed 6]
end

to get-age-data ; reading csv file and creating dataset with age distribution of the population
  file-close-all                          ; close all open files
    if not file-exists? "Data/age-dist-breeds.csv"  [
    user-message "No file 'age-dist-breeds' exists!"
    stop
  ]

  file-open "Data/age-dist-breeds.csv"  ; open the file with the turtle data
  set age-data csv:from-file "Data/age-dist-breeds.csv"
  file-close                              ; making sure to close the file
end

to get-age-breed [i]; process for assigning age after distribution for household size i, will repeat itself if no age is assigned in previous run
  let child-var item 1 item i age-data
ifelse (random-float 1 <= child-var)
   [set age random 14 set breed children set age-susceptibility 0.0025]
   [let teen-var item 2 (item i age-data)
     ifelse (random-float 1 <= teen-var)
    [set age 15 + random 4 set breed teens set age-susceptibility 0.005]
    [let adult-var item 3 (item i age-data)
        ifelse ( random-float 1 <= adult-var)
           [let age-susc-var random 49
            set age 20 + age-susc-var set breed adults set age-susceptibility (age-susc-var / 49) * 0.075 + 0.015]
           [let elder-var item 4 (item i age-data)
  ifelse ( random-float 1 <= elder-var )
        [ set age 70 + random 30 set breed elderly set age-susceptibility 0.08]
        [get-age-breed i]
    ]]
  ]
end

I tried to make a random-var at the beginning instead of recalculating it for each step but then I ended up with no elderly whatsoever.

Is there a better way than the random-float procedure to accurately assign non-normal probability distributions?

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Johanna
  • 11
  • 4

2 Answers2

1

Your problem is that you keep on drawing a new random number. This is your code structure, indented so you can see your logic:

to hatch-family
  ifelse random-float 1 <= 0.01
  []
  [ ifelse random-float 1 <= 0.02
    []
    [ ifelse random-float 1 <= 0.06
      []
      [ ifelse random-float 1 <= 0.11
        []
        [ ifelse random-float 1 <= 0.31
          []
          [ ifelse random-float 1 <= 0.49
            []
            [ hatch-family ]
          ]
        ]
      ]
    ]
   ]
end

So it draws a number, 1% chance of satisfying the first condition, if not it draws another number and so on until it gets to the end. What's more, it does the whole thing again about half the time because the procedure calls itself as the false branch of the final draw.

So, the first step is to draw the random number only once and simply compare that value, which would look something like this:

to hatch-family
  let my-draw random-float 1
  ifelse my-draw <= 0.01 []
  [ ifelse my-draw <= 0.02 []
    [ ifelse my-draw <= 0.06 []

But you can also use the multiple choice ifelse to clean up the code (assuming you are using current version of NetLogo) and that would look like:

to hatch-family
  let my-draw random-float 1
  ( ifelse
     my-draw <= 0.01 []
     my-draw <= 0.02 []
     my-draw <= 0.06 []

Note the opening ( to let NetLogo know that more than two clauses are expected.

Or you can use the rnd extension as already noted by Steve.

JenB
  • 17,620
  • 2
  • 17
  • 45
  • Thank you very much for such clear and thorough advice! I will try with my-draw variable and multiple choice `ifelse`. Could it be that the probabilities should be cumulative? Otherwise I think the likelihoods for the latter `ifelse`options will be smaller than they should (and the highest probability is 0.49 so if the my-draw variable is higher than that I still need to repeat or put the 0.49 one as the last "else"). Or maybe it is even possible to randomly select a number/percentage of turtles without using a stochastic process? – Johanna Apr 03 '21 at 00:52
  • Also, my main problem is the csv-file in which the probabilities for age (depending on household-size) does not always have the order of least -> highest probability as these vary between the household-size groups. I tried doing this procedure with the my-draw type variable but the result got even more skewed than with how it currently looks. – Johanna Apr 03 '21 at 00:53
  • 2
    I'm glad you solved it, but in the future please ask only one question per question. The point of StackOverflow is to provide a resource to help people with their code issues, not just to solve yours. As it stands, I am not entirely clear what problem you were actually trying to solve - something about not reading the csv file correctly, or something about weighted random draws or something else. – JenB Apr 03 '21 at 19:24
1

I finally solved it with some input from @JenB.

The code now looks as follows:

Procedure for hatching the rest of the households according to -accumulative- household-size distribution:

; hatching the rest of the household using percentual distribution of household size of Berlin population (Zensus Datenbank)
; (nr of households with specific size / total number of households in Berlin, 
; hence the percentage of the total population will be accurate as the population increases with each hatching)
to hatch-family
ask turtles
  [ 
  let my-draw random-float 1
  (ifelse
   my-draw <= 0.01 [set household-size 6 set dwelling patch-here hatch 5]
   my-draw <= 0.03 [set household-size 5 set dwelling patch-here hatch 4]
   my-draw <= 0.09 [set household-size 4 set dwelling patch-here hatch 3]
   my-draw <= 0.20 [set household-size 3 set dwelling patch-here hatch 2]
   my-draw <= 0.51 [set household-size 2 set dwelling patch-here hatch 1]
      my-draw <= 1 [set household-size 1 set dwelling patch-here]
    )
  ]
end

Procedure for assigning breed and age depending on distributions of age for each household-size:

(This one I solved with up-to-n-of command instead of random-float to address the problem with the probabilities not always being in order of lowest->highest)

to assign-age; assign age depending on household size according to distribution on csv file,
             ;second item [i] = the different rows representing different household sizes
  ask turtles [set age 0]
  get-age-data ; reading csv file and naming it age-data
  get-age-breed 1
  get-age-breed 2
  get-age-breed 3
  get-age-breed 4
  get-age-breed 5
  get-age-breed 6
end

to get-age-breed [i]; process for assigning age after distribution for household size i
  let child-var up-to-n-of ((count turtles with [household-size = i]) * item 1 (item i age-data)) (turtles with [household-size = i and age = 0])
  ask child-var [set age random 14 set breed children set age-susceptibility 0.0025]
  let teen-var up-to-n-of (count turtles with [household-size = i] * item 2 item i age-data) (turtles with [household-size = i and age = 0])
  ask teen-var [set age 15 + random 4 set breed teens set age-susceptibility 0.005]
  let elder-var up-to-n-of (count turtles with [household-size = i] * item 4 item i age-data) (turtles with [household-size = i and age = 0])
  ask elder-var [set age 70 + random 30 set breed elderly set age-susceptibility 0.08]
  let adult-var up-to-n-of (count turtles with [household-size = i] * item 3 item i age-data) (turtles with [household-size = i and age = 0])
  ask adult-var [let age-susc-var random 49 set age 20 + age-susc-var set breed adults set age-susceptibility (age-susc-var / 49) * 0.075 + 0.015]
 
end
desertnaut
  • 57,590
  • 26
  • 140
  • 166
Johanna
  • 11
  • 4