Code Monkey home page Code Monkey logo

dissertation-issues's Introduction

Greetings ๐Ÿ‘‹

  • ๐Ÿ”ญ Iโ€™m currently a PhD student at the Institute for Transport Studies in Leeds
  • ๐ŸŒฑ Iโ€™m interested in transport modelling and working on projects related to sustainable transport. Specific interests include:
    • Agent-based simulations of transport networks
    • Optimization problems for bus networks
    • Bicycle Networks
    • Network science applications to transport resilience
    • Reproducible research
  • ๐Ÿ’ฌ Ask me about:
    • R and open source software!
    • Open source packages and tools for transport analysis

dissertation-issues's People

Watchers

 avatar

dissertation-issues's Issues

How to Distribute Target Cycling Increase to MSOA pairs?

Let's imagine TfL want to increase their cycling mode share to 20% of all trips. How do we use a distance decay function to distribute these 'potential trips' across the different OD pairs. I do not want to assign 'potential trips' to OD pairs based on their current mode share, but on the average mode share associated with the distance separating them

Here I use MSOA data from the census

library(tidyverse)
library(pct)
library(sf)
#> Warning: package 'sf' was built under R version 3.6.2
#> Linking to GEOS 3.7.2, GDAL 2.4.2, PROJ 5.2.0

#Download the data using the pct package and keep only the necessary columns
flow_sub <- pct::get_pct(region = "london", layer = "rf") %>%
  st_drop_geometry %>%
  select(geo_code1, geo_code2, all, bicycle, rf_dist_km) %>%
  rename(dist = rf_dist_km)

# get % of cyclists 
flow_sub$perc_cycle <- flow_sub$bicycle / flow_sub$all

# group rows based on distance column. Change 'by' to edit number of groups
flow_sub$distance_groups <- cut(flow_sub$dist, breaks = seq(from = 0, to = 50, by = 1))
#show
flow_sub
#> # A tibble: 61,051 x 7
#>    geo_code1 geo_code2   all bicycle  dist perc_cycle distance_groups
#>  * <chr>     <chr>     <dbl>   <dbl> <dbl>      <dbl> <fct>          
#>  1 E02000001 E02000002    74       0  19.9    0       (19,20]        
#>  2 E02000001 E02000003   212       2  18.9    0.00943 (18,19]        
#>  3 E02000001 E02000008   156       1  19.4    0.00641 (19,20]        
#>  4 E02000001 E02000009   119       2  18.5    0.0168  (18,19]        
#>  5 E02000001 E02000012   227       1  16.3    0.00441 (16,17]        
#>  6 E02000001 E02000013   103       1  17.9    0.00971 (17,18]        
#>  7 E02000001 E02000014   121       0  19.1    0       (19,20]        
#>  8 E02000001 E02000016   213       2  13.9    0.00939 (13,14]        
#>  9 E02000001 E02000017   145       1  15.1    0.00690 (15,16]        
#> 10 E02000001 E02000018   125       1  16.9    0.008   (16,17]        
#> # โ€ฆ with 61,041 more rows
# group by distance categories created above and get summary stats
flow_grouped <- flow_sub %>%
  group_by(distance_group = as.character(distance_groups)) %>%
  summarise(distance = mean(dist),
            perc_cycle = sum(bicycle)/ sum(all))
#show
flow_grouped
#> # A tibble: 20 x 3
#>    distance_group distance perc_cycle
#>    <chr>             <dbl>      <dbl>
#>  1 (0,1]             0.850     0.0382
#>  2 (1,2]             1.56      0.0474
#>  3 (10,11]          10.5       0.0486
#>  4 (11,12]          11.5       0.0445
#>  5 (12,13]          12.5       0.0388
#>  6 (13,14]          13.5       0.0316
#>  7 (14,15]          14.5       0.0271
#>  8 (15,16]          15.5       0.0231
#>  9 (16,17]          16.5       0.0193
#> 10 (17,18]          17.5       0.0172
#> 11 (18,19]          18.6       0.0139
#> 12 (19,20]          19.5       0.0134
#> 13 (2,3]             2.53      0.0612
#> 14 (3,4]             3.52      0.0681
#> 15 (4,5]             4.51      0.0689
#> 16 (5,6]             5.50      0.0678
#> 17 (6,7]             6.49      0.0652
#> 18 (7,8]             7.50      0.0625
#> 19 (8,9]             8.50      0.0589
#> 20 (9,10]            9.51      0.0550
# show probabilty of cycling vs distance
ggplot(flow_grouped) +
  geom_point(aes(distance, perc_cycle)) + 
  labs( x="Commuting Distance (km)", y = "Probability of Trip Being Cycled")

# model to predict the distance group based on the % of commuters who cycle
glm1 <- glm(perc_cycle ~ distance_group, data = flow_grouped, family = "quasibinomial")

# predict cycling probability on all OD pairs
flow_sub$prob_cycle <- predict(glm1, data.frame(distance_group = flow_sub$distance_groups), type = "response")
#show
flow_sub
#> # A tibble: 61,051 x 8
#>    geo_code1 geo_code2   all bicycle  dist perc_cycle distance_groups prob_cycle
#>  * <chr>     <chr>     <dbl>   <dbl> <dbl>      <dbl> <fct>                <dbl>
#>  1 E02000001 E02000002    74       0  19.9    0       (19,20]             0.0134
#>  2 E02000001 E02000003   212       2  18.9    0.00943 (18,19]             0.0139
#>  3 E02000001 E02000008   156       1  19.4    0.00641 (19,20]             0.0134
#>  4 E02000001 E02000009   119       2  18.5    0.0168  (18,19]             0.0139
#>  5 E02000001 E02000012   227       1  16.3    0.00441 (16,17]             0.0193
#>  6 E02000001 E02000013   103       1  17.9    0.00971 (17,18]             0.0172
#>  7 E02000001 E02000014   121       0  19.1    0       (19,20]             0.0134
#>  8 E02000001 E02000016   213       2  13.9    0.00939 (13,14]             0.0316
#>  9 E02000001 E02000017   145       1  15.1    0.00690 (15,16]             0.0231
#> 10 E02000001 E02000018   125       1  16.9    0.008   (16,17]             0.0193
#> # โ€ฆ with 61,041 more rows

# total no. of commuters
sum(flow_sub$all)
#> [1] 2250073
# no of cyclists
sum(flow_sub$bicycle)
#> [1] 119382
# proportion of cyclists
sum(flow_sub$bicycle) / sum(flow_sub$all)
#> [1] 0.05305695

# Let's assume we want cycling mode share to increase to 20%
target_cycle <- 0.2
# no. of additional cycling trips needed to acheive target
round((target_cycle* sum(flow_sub$all)) - sum(flow_sub$bicycle))
#> [1] 330633

Created on 2020-06-05 by the reprex package (v0.3.0)
Now my question is, how do I add another column of 'potential trips' that is based on the 'prob_cycle' column? This column should add up to the 330633 target of cycling trips calculated above

How to prioritize road segments based on OSM road types

So far I am able to route between MSOA pairs, and aggregate the total flow on each road segment (based on the OD data and shortest paths). Now I have to prioritize/rank road segments for building infrastructure.

The simplest method would be just to rank segments based on total flow assigned to them, but there are issues with this:

  • We have road types such as residential, tertiary, pedestrian. Do these warrant bicycle infrastructure. I would say no. I need to develop a ranking methodology that weights the flow on each segment based on the road type. The purpose of this would be to avoid 'pedestrian' or 'residential' roads ranking highly. I would say these are low priority for investment compared to primary and secondary roads with high through traffic
  • We have only few trunk roads in such a ranking. This is because trunk roads are dangerous and the routing function penalizes time on trunk roads heavily. However, a lot of the bicycle lanes being built are currently on trunk roads (Park Lane, Camden High street, Euston Road). Should I reduce penalty for trunk roads to see the effect on shortest paths?
  • Road segments that already have cycling infrastructure do not need further investment. How do I identify these segments. Below I show that it is not as simple as highway=cycleway
library(sf)
#> Warning: package 'sf' was built under R version 3.6.2
#> Linking to GEOS 3.7.2, GDAL 2.4.2, PROJ 5.2.0
library(dodgr)
library(tidyverse)


#this downloads all the road data from OSM (equivalent to : key = 'highway')
streetnet <- dodgr_streetnet("manchester uk", expand = 0.05)

# filter out useful columns
streetnet2 <- streetnet %>% 
  dplyr::select(osm_id, bicycle, cycleway, highway,
                lanes, segregated)
# add length column
streetnet2 <- streetnet2 %>% dplyr::mutate(length_m = st_length(.))

# check different columns

#highway column
streetnet2 %>% 
  st_drop_geometry() %>%
  group_by(highway) %>% 
  summarize(segments=n(), `length (m)` = sum(length_m))
#> # A tibble: 28 x 3
#>    highway       segments `length (m)`
#>    <chr>            <int>          [m]
#>  1 bridleway          164    51941.071
#>  2 construction        29     4294.183
#>  3 corridor             6      599.112
#>  4 cycleway          1546   270300.471
#>  5 footway           9934   813544.881
#>  6 living_street       87     5747.002
#>  7 motorway           218   122607.357
#>  8 motorway_link      246    47141.973
#>  9 path              3070   277540.971
#> 10 pedestrian         512    41579.047
#> # โ€ฆ with 18 more rows

# get all the highway types
unique(streetnet2$highway)
#>  [1] "trunk"          "residential"    "service"        "unclassified"  
#>  [5] "tertiary"       "pedestrian"     "motorway_link"  "secondary"     
#>  [9] "primary"        "motorway"       "trunk_link"     "footway"       
#> [13] "unsurfaced"     "steps"          "bridleway"      "path"          
#> [17] "cycleway"       "track"          "primary_link"   "tertiary_link" 
#> [21] "living_street"  "road"           "secondary_link" "construction"  
#> [25] NA               "corridor"       "raceway"        "rest_area"

# bicycle column
streetnet2 %>% 
  st_drop_geometry() %>%
  group_by(bicycle) %>% 
  summarize(segments=n(), `length (m)` = sum(length_m))
#> # A tibble: 8 x 3
#>   bicycle     segments `length (m)`
#>   <chr>          <int>          [m]
#> 1 designated       422 1.003700e+05
#> 2 destination        2 4.461153e+01
#> 3 dismount          87 9.577430e+03
#> 4 no               759 2.002189e+05
#> 5 permissive        25 4.567829e+03
#> 6 private           34 2.245936e+03
#> 7 yes             1991 3.491391e+05
#> 8 <NA>           51724 5.624146e+06

#cycleway column
streetnet2 %>% 
  st_drop_geometry() %>%
  group_by(cycleway) %>% 
  summarize(segments=n(), `length (m)` = sum(length_m))
#> # A tibble: 14 x 3
#>    cycleway       segments `length (m)`
#>    <chr>             <int>          [m]
#>  1 crossing              5 1.339276e+02
#>  2 designated            1 2.305803e+01
#>  3 lane                204 4.903972e+04
#>  4 no                   34 5.017903e+03
#>  5 opposite              1 7.825680e+01
#>  6 opposite_lane         9 1.018105e+03
#>  7 opposite_track        2 7.732772e+01
#>  8 right                 1 5.945335e+01
#>  9 share_busway          7 7.484069e+02
#> 10 shared                1 6.499470e+02
#> 11 shared_lane           6 7.499808e+02
#> 12 track                77 1.723046e+04
#> 13 yes                   3 4.853136e+02
#> 14 <NA>              54693 6.214998e+06

#lanes column
streetnet2 %>% 
  st_drop_geometry() %>%
  group_by(lanes) %>% 
  summarize(segments=n(), `length (m)` = sum(length_m))
#> # A tibble: 6 x 3
#>   lanes segments `length (m)`
#>   <chr>    <int>          [m]
#> 1 1          259   28045.3854
#> 2 2          636  127689.5389
#> 3 3          284   83109.1962
#> 4 4           96   33447.6552
#> 5 5            6     855.8273
#> 6 <NA>     53763 6017162.5487

#segregated column
streetnet2 %>% 
  st_drop_geometry() %>%
  group_by(segregated) %>% 
  summarize(segments=n(), `length (m)` = sum(length_m))
#> # A tibble: 3 x 3
#>   segregated segments `length (m)`
#>   <chr>         <int>          [m]
#> 1 no              273     56937.38
#> 2 yes              95     19582.60
#> 3 <NA>          54676   6213790.17

# How is bicycle=designated different to highway=cycleway

# bicycle=designated
bicycle_designated <- streetnet2 %>% filter(bicycle == 'designated')
plot(st_geometry(bicycle_designated))

# highway=cycleway
high_cycleway <- streetnet2 %>% filter(highway == 'cycleway')
plot(st_geometry(high_cycleway))

# designated bicycle lanes that do not have cycleway tag
lane_not_cycleway <- streetnet2 %>% filter(bicycle == 'designated', highway != 'cycleway')
plot(st_geometry(lane_not_cycleway))

# cycleways that do not have designated bicycle lane tag
cycleway_not_designated <- streetnet2 %>% filter(bicycle != 'designated', highway == 'cycleway')
plot(st_geometry(cycleway_not_designated))

# Plot all highway=cycleway
plot(st_geometry(cycleways))
#> Error in st_geometry(cycleways): object 'cycleways' not found

#highway=cycleway
plot(st_geometry(cycleways))
#> Error in st_geometry(cycleways): object 'cycleways' not found
#bicycle=designated
plot(st_geometry(bicycle_designated), add = TRUE, col = 'red')

# Out of all the geometries that match bicycle=designated, only the red one are not cycleways.
# This shows that the highway=cycleway alone does not covered all cycle lanes
#bicycle=designated
plot(st_geometry(bicycle_designated))
#bicycle=designated BUT highway != cycleway
plot(st_geometry(lane_not_cycleway), add = TRUE, col = 'red')

Created on 2020-06-11 by the reprex package (v0.3.0)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.