I've been building an ABM in NetLogo that takes in a bunch of GIS data (e.g., suburban centres, proximity to CBDs, malls, roads, etc.) and calculates the utility to four agent classes (dp = deprived, li = low-income, mi = mid-income, and hi = high income).
I've been typing those weights manually but now I'd like to go through do some sensitivity testing using an external CSV file to set all the weights for all classes (e.g., in Excel).
I've looked at this question, the CSV extension docs, and its repo to get my bearings, but what I found most useful was this example.
I've written the following code for a load-weight function but coming from my background in Python it looks very inefficient. Any suggestions?
extensions [ csv ]
globals [
data dp-weight li-weight mi-weight hi-weight
dpu-suburb dpu-neigbhour dpu-bu dpu-cbd dpu-mall dpu-markets dpu-road dpu-density dpu-schools dpu-attractive dpu-health dpu-random dpu-water
liu-suburb liu-neigbhour liu-bu liu-cbd liu-mall liu-markets liu-road liu-density liu-schools liu-attractive liu-health liu-random liu-water
miu-suburb miu-neigbhour miu-bu miu-cbd miu-mall miu-markets miu-road miu-density miu-schools miu-attractive miu-health miu-random miu-water
hiu-suburb hiu-neigbhour hiu-bu hiu-cbd hiu-mall hiu-markets hiu-road hiu-density hiu-schools hiu-attractive hiu-health hiu-random hiu-water
dp-w-list li-w-list mi-w-list hi-w-list
]
to setup
clear-all
file-close-all ;; Close any files open from last run
file-open "../data/interim/weights.csv" ;; a csv formated with a header row and column and integers for the weights
set [dp-w-list li-w-list mi-w-list hi-w-list] [[][][][]]
reset-ticks
end
to go
load-weights
show hiu-water
tick
end
to load-weights
;; code based on /Extensions%20Examples/csv/CSV%20Example.nlogo
file-close-all ;; Close any open files
file-open "../data/interim/weights.csv"
set data csv:from-file "../data/interim/weights.csv"
set dp-weight item 1 data ;; I skip the first row as it contains only the headers
set li-weight item 2 data
set mi-weight item 3 data
set hi-weight item 4 data
let i 0
repeat length dp-weight [
let w item i dp-weight
if i > 0 [set dp-w-list lput w dp-w-list] ;; I skip the first column, as it contains the line header (e.g., 'dp')
set i i + 1
]
set i 0
repeat length li-weight [
let w item i li-weight
if i > 0 [set li-w-list lput w li-w-list]
set i i + 1
]
set i 0
repeat length mi-weight [
let w item i mi-weight
if i > 0 [set mi-w-list lput w mi-w-list]
set i i + 1
]
set i 0
repeat length hi-weight [
let w item i hi-weight
if i > 0 [set hi-w-list lput w hi-w-list]
set i i + 1
]
set [ dpu-suburb dpu-neigbhour dpu-bu dpu-cbd dpu-mall dpu-markets dpu-road dpu-density dpu-schools dpu-attractive dpu-health dpu-random dpu-water ] dp-w-list
set [ liu-suburb liu-neigbhour liu-bu liu-cbd liu-mall liu-markets liu-road liu-density liu-schools liu-attractive liu-health liu-random liu-water ] li-w-list
set [ miu-suburb miu-neigbhour miu-bu miu-cbd miu-mall miu-markets miu-road miu-density miu-schools miu-attractive miu-health miu-random miu-water ] mi-w-list
set [ hiu-suburb hiu-neigbhour hiu-bu hiu-cbd hiu-mall hiu-markets hiu-road hiu-density hiu-schools hiu-attractive hiu-health hiu-random hiu-water ] hi-w-list
file-close ;; Close any open files
end
For clarification, the CSV file should look like this:
agent,suburban,neighbour,bu,cbd,mall,markets,road,density,schools,attractive,health,random,water
dp,3,9,9,4,2,7,3,9,4,2,2,1,10
li,8,7,9,7,2,7,8,9,4,2,4,1,7
mi,6,7,7,4,7,7,6,6,4,7,4,1,5
hi,5,7,2,7,9,6,5,1,4,10,3,1,8
I've been building an ABM in NetLogo that takes in a bunch of GIS data (e.g., suburban centres, proximity to CBDs, malls, roads, etc.) and calculates the utility to four agent classes (dp = deprived, li = low-income, mi = mid-income, and hi = high income).
I've been typing those weights manually but now I'd like to go through do some sensitivity testing using an external CSV file to set all the weights for all classes (e.g., in Excel).
I've looked at this question, the CSV extension docs, and its repo to get my bearings, but what I found most useful was this example.
I've written the following code for a load-weight function but coming from my background in Python it looks very inefficient. Any suggestions?
extensions [ csv ]
globals [
data dp-weight li-weight mi-weight hi-weight
dpu-suburb dpu-neigbhour dpu-bu dpu-cbd dpu-mall dpu-markets dpu-road dpu-density dpu-schools dpu-attractive dpu-health dpu-random dpu-water
liu-suburb liu-neigbhour liu-bu liu-cbd liu-mall liu-markets liu-road liu-density liu-schools liu-attractive liu-health liu-random liu-water
miu-suburb miu-neigbhour miu-bu miu-cbd miu-mall miu-markets miu-road miu-density miu-schools miu-attractive miu-health miu-random miu-water
hiu-suburb hiu-neigbhour hiu-bu hiu-cbd hiu-mall hiu-markets hiu-road hiu-density hiu-schools hiu-attractive hiu-health hiu-random hiu-water
dp-w-list li-w-list mi-w-list hi-w-list
]
to setup
clear-all
file-close-all ;; Close any files open from last run
file-open "../data/interim/weights.csv" ;; a csv formated with a header row and column and integers for the weights
set [dp-w-list li-w-list mi-w-list hi-w-list] [[][][][]]
reset-ticks
end
to go
load-weights
show hiu-water
tick
end
to load-weights
;; code based on https://github/NetLogo/models/blob/master/Code%20Examples/Extensions%20Examples/csv/CSV%20Example.nlogo
file-close-all ;; Close any open files
file-open "../data/interim/weights.csv"
set data csv:from-file "../data/interim/weights.csv"
set dp-weight item 1 data ;; I skip the first row as it contains only the headers
set li-weight item 2 data
set mi-weight item 3 data
set hi-weight item 4 data
let i 0
repeat length dp-weight [
let w item i dp-weight
if i > 0 [set dp-w-list lput w dp-w-list] ;; I skip the first column, as it contains the line header (e.g., 'dp')
set i i + 1
]
set i 0
repeat length li-weight [
let w item i li-weight
if i > 0 [set li-w-list lput w li-w-list]
set i i + 1
]
set i 0
repeat length mi-weight [
let w item i mi-weight
if i > 0 [set mi-w-list lput w mi-w-list]
set i i + 1
]
set i 0
repeat length hi-weight [
let w item i hi-weight
if i > 0 [set hi-w-list lput w hi-w-list]
set i i + 1
]
set [ dpu-suburb dpu-neigbhour dpu-bu dpu-cbd dpu-mall dpu-markets dpu-road dpu-density dpu-schools dpu-attractive dpu-health dpu-random dpu-water ] dp-w-list
set [ liu-suburb liu-neigbhour liu-bu liu-cbd liu-mall liu-markets liu-road liu-density liu-schools liu-attractive liu-health liu-random liu-water ] li-w-list
set [ miu-suburb miu-neigbhour miu-bu miu-cbd miu-mall miu-markets miu-road miu-density miu-schools miu-attractive miu-health miu-random miu-water ] mi-w-list
set [ hiu-suburb hiu-neigbhour hiu-bu hiu-cbd hiu-mall hiu-markets hiu-road hiu-density hiu-schools hiu-attractive hiu-health hiu-random hiu-water ] hi-w-list
file-close ;; Close any open files
end
For clarification, the CSV file should look like this:
agent,suburban,neighbour,bu,cbd,mall,markets,road,density,schools,attractive,health,random,water
dp,3,9,9,4,2,7,3,9,4,2,2,1,10
li,8,7,9,7,2,7,8,9,4,2,4,1,7
mi,6,7,7,4,7,7,6,6,4,7,4,1,5
hi,5,7,2,7,9,6,5,1,4,10,3,1,8
Share
Improve this question
edited Apr 3 at 13:35
desertnaut
60.5k32 gold badges155 silver badges181 bronze badges
asked Mar 17 at 5:34
Alexandre PereiraAlexandre Pereira
1532 silver badges8 bronze badges
1 Answer
Reset to default 1For your purpose it may make sense to use the table
extension to build a dictionary of dictionaries, rather than making individual variables for each parameter. For example:
extensions [ csv table ]
globals [ params param-cols]
turtles-own [ class ]
to setup
ca
let fpath "weights.csv"
let csv-rows csv:from-file fpath
; Define params as a dictionary
set params table:make
; Pull key values as csv header (minus agent column)
let header-row first csv-rows
set param-cols but-first header-row
; Iterate over the value rows
foreach but-first csv-rows [ row ->
; Pull current agent class
let cur-class first row
; Pull values as csv items (minus agent column)
let vals but-first row
; Convert to a keypair list then to a dictionary
let key-vals ( map [ [ i j ] -> list i j ] param-cols vals )
let dict table:from-list key-vals
; Add entry to params
table:put params cur-class dict
]
print params
reset-ticks
end
to-report class-param [ class_ item_ ]
report table:get (table:get params class_) item_
end
to go
print "LI cbd value:"
print class-param "li" "cbd"
print "Class parameter values sum:"
foreach [ "dp" "li" "mi" "hi" ] [ cls ->
print word cls ":"
print sum map [ i -> class-param cls i ] param-cols
]
end
Output from go
:
LI cbd value:
7
Class parameter values sum:
dp:
65
li:
75
mi:
71
hi:
68
This could allow for easier adaptation to added / removed parameters or agent classes etc. but does mean a little extra effort if you want to update the table values after the fact (eg. while running) since you need to use the appropriate table
functions (eg. table:put
) to update.