Skip to contents

max_coverage solves the binary optimisation problem known as the "maximal covering location problem" as described by Church (http://www.geo .ucsb.edu/~forest/G294download/MAX_COVER_RLC_CSR.pdf). This package was implemented to make it easier to solve this problem in the context of the research initially presented by Chan et al (http://circ.ahajournals.org/content/127/17/1801.short) to identify ideal locations to place AEDs.

Usage

max_coverage(
  existing_facility,
  proposed_facility,
  user,
  distance_cutoff,
  n_added,
  d_existing_user = NULL,
  d_proposed_user = NULL,
  solver = "glpk"
)

Arguments

existing_facility

data.frame containing the facilities that are already in existing, with columns names lat, and long.

proposed_facility

data.frame containing the facilities that are being proposed, with column names lat, and long.

user

data.frame containing the users of the facilities, along with column names lat, and long.

distance_cutoff

numeric indicating the distance cutoff (in metres) you are interested in. If a number is less than distance_cutoff, it will be 1, if it is greater than it, it will be 0.

n_added

the maximum number of facilities to add.

d_existing_user

Optional distance matrix between existing facilities and users. Default distances are direct (geospherical ellipsoidal) distances; this allows alternative measures such as street-network distances to be submitted (see Examples).

d_proposed_user

Option distance matrix between proposed facilities and users (see Examples).

solver

character "glpk" (default) or "lpSolve". "gurobi" is currently in development, see https://github.com/njtierney/maxcovr/issues/25.

Value

dataframe of results

Examples


library(dplyr)

# already existing locations
york_selected <- york |> filter(grade == "I")

# proposed locations
york_unselected <- york |> filter(grade != "I")

mc_result <- max_coverage(existing_facility = york_selected,
                          proposed_facility = york_unselected,
                          user = york_crime,
                          distance_cutoff = 100,
                          n_added = 20)

mc_result
#> 
#> ------------------------------------------- 
#> Model Fit: maxcovr fixed location model 
#> ------------------------------------------- 
#> model_used:        max_coverage 
#> existing_facility: york_selected 
#> proposed_facility: york_unselected 
#> user:              york_crime 
#> distance_cutoff:   100 
#> n_added:           20 
#> d_existing_user:            lpSolve 
#> -------------------------------------------

summary(mc_result)
#> 
#> ------------------------------------------- 
#> Model Fit: maxcovr fixed location model 
#> ------------------------------------------- 
#> Distance Cutoff: 100m 
#> Facilities: 
#>     Added:       20 
#> Coverage (Previous): 
#>     # Users:     540    (339) 
#>     Proportion:  0.2977 (0.1869) 
#> Distance (m) to Facility (Previous): 
#>     Avg:         886 (1400) 
#>     SD:          986 (1597) 
#> -------------------------------------------

# get the facilities chosen
mc_result$facility_selected
#> [[1]]
#> # A tibble: 20 × 7
#>     long   lat object_id desig_id pref_ref name                            grade
#>    <dbl> <dbl>     <int> <chr>       <int> <chr>                           <chr>
#>  1 -1.09  54.0      5978 DYO1383    462917 NA                              II   
#>  2 -1.08  54.0      5909 DYO1297    463072 NA                              II   
#>  3 -1.08  54.0      5872 DYO1244    463186 NA                              II   
#>  4 -1.08  54.0      5847 DYO1216    463242 NA                              II   
#>  5 -1.12  54.0      5759 DYO1108    463434 FORMER JUNIOR SCHOOL BUILDING … II   
#>  6 -1.08  54.0      5748 DYO1096    463469 NA                              II   
#>  7 -1.08  54.0      5745 DYO1093    463465 NA                              II   
#>  8 -1.08  54.0      5739 DYO1086    463457 CHURCH OF ST GEORGE AND ATTACH… II   
#>  9 -1.10  54.0      5642 DYO960     463695 NA                              II   
#> 10 -1.09  53.9      5606 DYO920     463771 PRESS STAND AT YORK RACECOURSE  II   
#> 11 -1.06  54.0      5592 DYO903     463788 NA                              II   
#> 12 -1.07  54.0      5588 DYO899     463782 NA                              II   
#> 13 -1.08  54.0      5529 DYO829     463938 CHURCH OF ST THOMAS             II   
#> 14 -1.08  54.0      5454 DYO705     464133 NUMBERS 45-51 (ODD) AND ATTACH… II   
#> 15 -1.03  54.0      5373 DYO1644        NA War Memorial                    II   
#> 16 -1.12  54.0      5349 DYO572     464451 POPPLETON ROAD SCHOOL           II   
#> 17 -1.08  54.0      5328 DYO544     464508 WOODS MILL                      II   
#> 18 -1.00  54.0      3215 DYO1581    491367 STOCKTON GRANGE AND ATTACHED O… II   
#> 19 -1.08  54.0      3213 DYO1580    490659 NEW CHAPEL AT ST JOHN'S COLLEGE II   
#> 20 -1.08  54.0      4803 DYO1734        NA The Swan Public House           II   
#> 

# get the users affected
mc_result$user_affected
#> [[1]]
#> # A tibble: 201 × 16
#>    user_id user_chosen facility_id distance category   persistent_id date    lat
#>      <dbl>       <int>       <dbl>    <dbl> <chr>      <chr>         <chr> <dbl>
#>  1       1           1          66     166. anti-soci… 62299914865f… 2016…  54.0
#>  2       5           1          25     536. anti-soci… 6139f131b724… 2016…  54.0
#>  3      13           1           6    2334. anti-soci… c2aac5cdf98e… 2016…  54.0
#>  4      14           1           2   12687. anti-soci… c0908b075c68… 2016…  54.1
#>  5      15           1          24     620. anti-soci… 40c8c061c48b… 2016…  54.0
#>  6      21           1          60    1286. anti-soci… 45ce21c8785e… 2016…  53.9
#>  7      23           1          NA      NA  NA         NA            NA     NA  
#>  8      24           1          NA      NA  NA         NA            NA     NA  
#>  9      27           1          NA      NA  NA         NA            NA     NA  
#> 10      29           1           2     375. anti-soci… db6cacd76d97… 2016…  54.0
#> # ℹ 191 more rows
#> # ℹ 8 more variables: long <dbl>, street_id <chr>, street_name <chr>,
#> #   context <chr>, id <chr>, location_type <chr>, location_subtype <chr>,
#> #   outcome_status <chr>
#> 

# get the summaries
mc_result$summary
#> [[1]]
#> # A tibble: 2 × 8
#>   n_added distance_within n_cov pct_cov n_not_cov pct_not_cov dist_avg dist_sd
#>     <dbl>           <dbl> <int>   <dbl>     <int>       <dbl>    <dbl>   <dbl>
#> 1       0             100   339   0.187      1475       0.813    1400.   1597.
#> 2      20             100   540   0.298      1274       0.702     886.    986.
#> 

# Example of street-network distance calculations
if (FALSE) { # \dontrun{
library(dodgr)
net <- dodgr_streetnet_sf ("york england") |>
    weight_streetnet (wt_profile = "foot")

from <- match_points_to_graph (v, york_selected[, c ("long", "lat")])
to <- match_points_to_graph (v, york_crime[, c ("long", "lat")])
d_existing_user <- dodgr_dists (net, from = from, to = to)

from <- match_points_to_graph (v, york_unselected[, c ("long", "lat")])
d_proposed_user <- dodgr_dists (net, from = from, to = to)

mc_result <- max_coverage(existing_facility = york_selected,
                          proposed_facility = york_unselected,
                          user = york_crime,
                          distance_cutoff = 100,
                          n_added = 20,
                          d_existing_user = d_existing_user,
                          d_proposed_user = d_proposed_user)

} # }