- ๐ญ 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 Introduction
dissertation-issues's People
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.