最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

netlogo - Is there a better way to get lines from a CSV? - Stack Overflow

programmeradmin3浏览0评论

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
Add a comment  | 

1 Answer 1

Reset to default 1

For 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.

发布评论

评论列表(0)

  1. 暂无评论