This vignette explores the vsoe (Vehicle Sequence of Events) data to visualize crash sequence patterns.
vsoe is one of three event-based data files, the
others being cevent and vevent.
According to the CRSS
Analytical User’s Manual, vevent “has the same data
elements as the cevent data file” plus “a data element
that records the sequential event number for each vehicle,” and the
vsoe file “has a subset of the data elements contained
in the Vevent data file (it is a simplified
vevent data file)” (p. 16). rfars
therefore omits cevent and vevent.
Below we get one year of data for one state, Virginia.
mydata <- rfars::get_gescrss(years=2019:2020, regions = "s")
#>
#> ── Column specification ────────────────────────────────────────────────────────
#> cols(
#> .default = col_character(),
#> year = col_double(),
#> psu = col_double(),
#> psustrat = col_double(),
#> casenum = col_double(),
#> weight = col_double(),
#> id = col_double(),
#> veh_no = col_double(),
#> per_no = col_double(),
#> minute = col_double(),
#> mod_year = col_logical(),
#> model = col_double(),
#> peds = col_double(),
#> permvit = col_double(),
#> pernotmvit = col_double(),
#> psu_var = col_double(),
#> pvh_invl = col_double(),
#> str_veh = col_double(),
#> ve_forms = col_double(),
#> ve_total = col_double()
#> )
#> ℹ Use `spec()` for the full column specifications.
my_events <- mydata$events
The Vsoe data is stored in the events
tibble of the object returned by get_gescrss()
. Here we see
the top 10 individual events:
my_events %>%
group_by(soe) %>% summarize(n=n()) %>%
arrange(desc(n)) %>%
slice(1:10) %>%
ggplot(aes(x=n, y=reorder(soe, n), label=scales::comma(n))) +
geom_col() +
geom_label()
We can also see the top 10 most common sequences:
my_events %>%
select(-aoi) %>%
pivot_wider(names_from = "veventnum", values_from = "soe", values_fill = "x",
names_prefix = "event") %>%
select(starts_with("event")) %>%
group_by_all() %>%
summarize(n=n(), .groups = "drop") %>%
arrange(desc(n)) %>%
slice(1:10) %>%
select(event1, event2, n)
#> # A tibble: 10 × 3
#> event1 event2 n
#> <chr> <chr> <int>
#> 1 Motor Vehicle In-Transport x 135121
#> 2 Motor Vehicle In-Transport Motor Vehicle In-Transport 7921
#> 3 Parked Motor Vehicle x 6384
#> 4 Pedestrian x 4736
#> 5 Live Animal x 3567
#> 6 Pedalcyclist x 3536
#> 7 Ran Off Roadway - Right Parked Motor Vehicle 1738
#> 8 Cross Centerline Motor Vehicle In-Transport 1530
#> 9 Rollover/Overturn x 963
#> 10 Ran Off Roadway - Right Utility Pole/Light Support 811
Below we consider all state transitions - the transition from one event to the next in the sequence. For example, the sequence A-B-C-D has three transitions: A to B, B to C, and C to D. The graph below shows a subset of the more common transitions in the crash sequences. It is interpreted as follows: the event on the y-axis was followed by the event on the x-axis in the percentage of sequences shown at the intersection of the two events. For example, vehicles went from ‘re-entering roadway’ to ‘cross centerline’ in 36% of sequences. Note that we have added a state labelled ‘Pre-Crash’ to help account for sequences with just one event.
my_events %>%
group_by(year, casenum, veh_no) %>%
dplyr::rename(event_to = soe) %>%
mutate(event_from = data.table::shift(event_to, fill = "Pre-Crash")) %>%
select(event_from, event_to) %>%
group_by(event_from, event_to) %>% summarize(n=n()) %>%
group_by(event_from) %>% mutate(n_from = sum(n)) %>%
mutate(n_pct = n/n_from) %>%
filter(n_pct>.1, n>5) %>%
mutate(event_from = stringr::str_wrap(event_from, 40),
event_to = stringr::str_wrap(event_to, 40)) %>%
ggplot(aes(y=event_from, x=event_to, fill=n_pct, label=scales::percent(n_pct, accuracy = 1))) +
viridis::scale_fill_viridis() +
geom_label() +
theme(
axis.text.x.bottom = element_text(angle=270, hjust = 0, vjust=.5),
legend.position = "none"
)
#> Adding missing grouping variables: `year`, `casenum`, `veh_no`
#> `summarise()` has grouped output by 'event_from'. You can override using the
#> `.groups` argument.