forked from avehtari/BDA_R_demos
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtrafficdeaths.Rmd
More file actions
154 lines (130 loc) · 4.95 KB
/
Copy pathtrafficdeaths.Rmd
File metadata and controls
154 lines (130 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
---
title: "Bayesian data analysis - traffic deaths in Finland"
author: "Aki Vehtari"
date: '`r format(Sys.Date())`'
output:
html_document: default
html_notebook: default
---
License: CC-BY
This notebook demonstrates time series analysis for traffic deaths per year in Finland. Currently when the the number of traffic deaths during previous year are reported, the press release claims that the the traffic safety in Finland has improved or worsened depending whether the number is smaller or larger than the year before. Time series analysis can be used to separate random fluctuation from the slowly changing traffic safety.
Load some libraries:
```{r, comment=NA}
library(ggplot2)
library(tidyr)
library(gridExtra)
library(rstanarm)
library(rstan)
library(bayesplot)
library(loo)
rstan_options(auto_write = TRUE)
options(mc.cores = parallel::detectCores())
source("stan_utility.R")
```
Read the data (there would data for earlier years, too, but this is sufficient for the demonstration)
```{r}
# file preview shows a header row
deaths <- read.csv("trafficdeaths.csv", header = TRUE)
head(deaths)
```
First plot just the data.
```{r}
ggplot() +
geom_point(aes(year, deaths), data = deaths, size = 1) +
labs(y = 'Traffic deaths', x= "Year") +
guides(linetype = F) +
theme_bw()
```
The number of deaths is count data, so we use Poisson observation model. First we use log-linear model for the Poisson intensity, which corresponds to assuming constant proportional change in the rate.
```{r, comment=NA}
fit_lin <- stan_glm(deaths ~ year, deaths, family="poisson", refresh=1000, iter=1000, chains=4, seed=583829)
```
```{r, comment=NA}
summary(fit_lin)
```
n_eff's and Rhat's are ok. Let's look at the posterior predictive distribution (median and 5% and 95% intervals).
```{r}
x_predict=seq(1993,2023)
N_predict=length(x_predict)
y_predict <- posterior_predict(fit_lin, newdata=data.frame(year=x_predict))
mu <- apply(t(y_predict), 1, quantile, c(0.05, 0.5, 0.95)) %>%
t() %>% data.frame(x = x_predict, .) %>% gather(pct, y, -x)
pfit <- ggplot() +
geom_point(aes(year, deaths), data = deaths, size = 1) +
geom_line(aes(x, y, linetype = pct), data = mu, color = 'red') +
scale_linetype_manual(values = c(2,1,2)) +
labs(x = 'Year', y = 'Traffic deaths') +
guides(linetype = F) +
theme_bw()
(pfit)
```
Next we test non-linear spline model with stan_gamm4
```{r}
fit_gam <- stan_gamm4(deaths ~ s(year), data=deaths, family="poisson", refresh=1000, iter=1000, chain=4, seed=583829)
summary(fit_gam)
```
n_eff is clearly smaller than for the linear model, but Rhat's are ok.
Let's look at the posterior predictive distribution.
```{r}
x_predict=seq(1993,2023)
N_predict=length(x_predict)
y_predict <- posterior_predict(fit_gam, newdata=data.frame(year=x_predict))
mu <- apply(t(y_predict), 1, quantile, c(0.05, 0.5, 0.95)) %>%
t() %>% data.frame(x = x_predict, .) %>% gather(pct, y, -x)
pfit <- ggplot() +
geom_point(aes(year, deaths), data = deaths, size = 1) +
geom_line(aes(x, y, linetype = pct), data = mu, color = 'red') +
scale_linetype_manual(values = c(2,1,2)) +
labs(x = 'Year', y = 'Traffic deaths') +
guides(linetype = F) +
theme_bw()
(pfit)
```
The predictive median is clearly nonlinear. The predictive mean for future years stays at the same level as the most recent observations, but uncertainty increases quickly.
Finally we test Gaussian process centered on linear model. This is not yet available in rstanarm, and has been written directly in Stan language:
```{r, comment=NA}
writeLines(readLines("poisson_gp.stan"))
```
```{r}
N<-nrow(deaths)
Ey<-mean(deaths$deaths)
d_data <- list(N=N, x=deaths$year, y=deaths$deaths, Ey=Ey, N_predict=N_predict, x_predict=x_predict, alpha0=2, beta0=4)
fit_gp <- stan(file='poisson_gp.stan', data=d_data, refresh=1000, iter=1000,
chains=4, seed=583829, init=0, control=list(adapt_delta=0.99))
```
```{r}
check_treedepth(fit_gp)
check_energy(fit_gp)
check_div(fit_gp)
```
```{r}
gp_params <- rstan::extract(fit_gp)
mu <- apply(t(gp_params$y_predict), 1, quantile, c(0.05, 0.5, 0.95)) %>%
t() %>% data.frame(x = x_predict, .) %>% gather(pct, y, -x)
pfit <- ggplot() +
geom_point(aes(year, deaths), data = deaths, size = 1) +
geom_line(aes(x, y, linetype = pct), data = mu, color = 'red') +
scale_linetype_manual(values = c(2,1,2)) +
labs(x = 'Year', y = 'Traffic deaths') +
guides(linetype = F) +
theme_bw()
(pfit)
```
Finally PSIS-LOO estimates.
```{r}
(loo_lin<-loo(fit_lin))
(loo_gam<-loo(fit_gam))
compare(loo_lin,loo_gam)
(loo_gp<-loo(gp_params$log_lik))
compare(loo_lin,loo_gp)
```
There are no practical differences in predictive performance, which is partially due to small number of observations. Based on the posterior predictive distributions there are clear differences in the future predictions.
<br />
### Appendix: Session information
```{r}
sessionInfo()
```
<br />
### Appendix: Licenses
* Code © 2017, Aki Vehtari, licensed under BSD-3.
* Text © 2017, Aki Vehtari, licensed under CC-BY-NC 4.0.