N <- 19
tries <- c(1443, 694, 455, 353, 272, 256, 240, 217, 200, 237, 202, 192, 174,
167, 201, 195, 191, 147, 152)
successes <- c(1346, 577, 337, 208, 149, 136, 111, 69, 67, 75, 52, 46, 54,
28, 27, 31, 33, 20, 24)
dist <- 2:20 * 12 # converting to inches
golf <- data.frame(tries, successes, dist)
# The golf ball has diameter 2r = 1.68 inches
r <- 1.68/2
# and the hole has diameter 2R = 4.25 inches
R <- 4.25/2
# estimated parameter from the paper
sigma <- 0.026
theta0 <- function(x) {
asin((R - r) / x)
}
golf %<>%
mutate(
p = successes / tries,
error_sd = sqrt((p * (1 - p)) / tries),
lower = p - 2 * error_sd,
upper = p + 2 * error_sd,
fit = 2 * pnorm(theta0(dist) / sigma) - 1
)
limits <- with(golf, aes(ymax = upper, ymin = lower))
p <- ggplot(golf, aes(x = dist / 12, y = p))
p <- p + geom_pointrange(limits)
p <- p + geom_line(aes(y = fit), colour = "red")
p <- p + xlab("Distance (feet)") +
ylab("Proportion of Success") +
theme_bw()
p
This model is defined in golf.stan
file
functions {
real theta0(real x, real R, real r) {
return asin((R - r) / x);
}
}
data {
int N;
int<lower = 0> tries[N];
int<lower = 0> successes[N];
real<lower = 0> dist[N];
}
transformed data {
real R;
real r;
R <- 4.25 / 2;
r <- 1.68 / 2;
}
parameters {
real<lower = 0> sigma;
}
model {
real p[N];
for (n in 1:N) {
p[n] <- 2 * Phi(theta0(dist[n], R, r) / sigma) - 1;
}
sigma ~ cauchy(0, 2.5);
successes ~ binomial(tries, p);
}
generated quantities {
real sigma_degrees;
sigma_degrees <- 180/pi() * sigma;
}
Data is passed directly from the R environment to Stan.
golf_fit <- stan(file = "golf.stan", iter = 200)
##
## SAMPLING FOR MODEL 'golf' NOW (CHAIN 1).
##
## Chain 1, Iteration: 1 / 200 [ 0%] (Warmup)
## Chain 1, Iteration: 20 / 200 [ 10%] (Warmup)
## Chain 1, Iteration: 40 / 200 [ 20%] (Warmup)
## Chain 1, Iteration: 60 / 200 [ 30%] (Warmup)
## Chain 1, Iteration: 80 / 200 [ 40%] (Warmup)
## Chain 1, Iteration: 100 / 200 [ 50%] (Warmup)
## Chain 1, Iteration: 101 / 200 [ 50%] (Sampling)
## Chain 1, Iteration: 120 / 200 [ 60%] (Sampling)
## Chain 1, Iteration: 140 / 200 [ 70%] (Sampling)
## Chain 1, Iteration: 160 / 200 [ 80%] (Sampling)
## Chain 1, Iteration: 180 / 200 [ 90%] (Sampling)
## Chain 1, Iteration: 200 / 200 [100%] (Sampling)#
## # Elapsed Time: 0.002103 seconds (Warm-up)
## # 0.002134 seconds (Sampling)
## # 0.004237 seconds (Total)
## #
##
## SAMPLING FOR MODEL 'golf' NOW (CHAIN 2).
##
## Chain 2, Iteration: 1 / 200 [ 0%] (Warmup)
## Chain 2, Iteration: 20 / 200 [ 10%] (Warmup)
## Chain 2, Iteration: 40 / 200 [ 20%] (Warmup)
## Chain 2, Iteration: 60 / 200 [ 30%] (Warmup)
## Chain 2, Iteration: 80 / 200 [ 40%] (Warmup)
## Chain 2, Iteration: 100 / 200 [ 50%] (Warmup)
## Chain 2, Iteration: 101 / 200 [ 50%] (Sampling)
## Chain 2, Iteration: 120 / 200 [ 60%] (Sampling)
## Chain 2, Iteration: 140 / 200 [ 70%] (Sampling)
## Chain 2, Iteration: 160 / 200 [ 80%] (Sampling)
## Chain 2, Iteration: 180 / 200 [ 90%] (Sampling)
## Chain 2, Iteration: 200 / 200 [100%] (Sampling)#
## # Elapsed Time: 0.00274 seconds (Warm-up)
## # 0.002709 seconds (Sampling)
## # 0.005449 seconds (Total)
## #
##
## SAMPLING FOR MODEL 'golf' NOW (CHAIN 3).
##
## Chain 3, Iteration: 1 / 200 [ 0%] (Warmup)
## Chain 3, Iteration: 20 / 200 [ 10%] (Warmup)
## Chain 3, Iteration: 40 / 200 [ 20%] (Warmup)
## Chain 3, Iteration: 60 / 200 [ 30%] (Warmup)
## Chain 3, Iteration: 80 / 200 [ 40%] (Warmup)
## Chain 3, Iteration: 100 / 200 [ 50%] (Warmup)
## Chain 3, Iteration: 101 / 200 [ 50%] (Sampling)
## Chain 3, Iteration: 120 / 200 [ 60%] (Sampling)
## Chain 3, Iteration: 140 / 200 [ 70%] (Sampling)
## Chain 3, Iteration: 160 / 200 [ 80%] (Sampling)
## Chain 3, Iteration: 180 / 200 [ 90%] (Sampling)
## Chain 3, Iteration: 200 / 200 [100%] (Sampling)#
## # Elapsed Time: 0.002454 seconds (Warm-up)
## # 0.002107 seconds (Sampling)
## # 0.004561 seconds (Total)
## #
##
## SAMPLING FOR MODEL 'golf' NOW (CHAIN 4).
##
## Chain 4, Iteration: 1 / 200 [ 0%] (Warmup)
## Chain 4, Iteration: 20 / 200 [ 10%] (Warmup)
## Chain 4, Iteration: 40 / 200 [ 20%] (Warmup)
## Chain 4, Iteration: 60 / 200 [ 30%] (Warmup)
## Chain 4, Iteration: 80 / 200 [ 40%] (Warmup)
## Chain 4, Iteration: 100 / 200 [ 50%] (Warmup)
## Chain 4, Iteration: 101 / 200 [ 50%] (Sampling)
## Chain 4, Iteration: 120 / 200 [ 60%] (Sampling)
## Chain 4, Iteration: 140 / 200 [ 70%] (Sampling)
## Chain 4, Iteration: 160 / 200 [ 80%] (Sampling)
## Chain 4, Iteration: 180 / 200 [ 90%] (Sampling)
## Chain 4, Iteration: 200 / 200 [100%] (Sampling)#
## # Elapsed Time: 0.002247 seconds (Warm-up)
## # 0.002186 seconds (Sampling)
## # 0.004433 seconds (Total)
## #
golf_fit
## Inference for Stan model: golf.
## 4 chains, each with iter=200; warmup=100; thin=1;
## post-warmup draws per chain=100, total post-warmup draws=400.
##
## mean se_mean sd 2.5% 25% 50% 75%
## sigma 0.03 0.00 0.00 0.03 0.03 0.03 0.03
## sigma_degrees 1.53 0.00 0.02 1.48 1.52 1.53 1.55
## lp__ -2926.80 0.05 0.77 -2929.06 -2926.93 -2926.53 -2926.33
## 97.5% n_eff Rhat
## sigma 0.03 172 1.00
## sigma_degrees 1.57 172 1.00
## lp__ -2926.26 203 1.01
##
## Samples were drawn using NUTS(diag_e) at Thu Apr 28 21:03:59 2016.
## For each parameter, n_eff is a crude measure of effective sample size,
## and Rhat is the potential scale reduction factor on split chains (at
## convergence, Rhat=1).
sigma <- rstan::extract(golf_fit, pars = 'sigma') $sigma
sigma_deg <- rstan::extract(golf_fit, pars = 'sigma_degrees')$sigma_degrees
plot_dens <- function(param) {
ggplot(as.data.frame(param), aes(x = param)) +
geom_line(stat = "density") + theme_bw()
}
plot_dens(sigma) + xlab("Sigma")
plot_dens(sigma_deg) + xlab("Sigma Degrees")
fits <- sapply(sigma, FUN = function(x, y) 2 * pnorm(theta0(y), sd = x) - 1, y = golf$dist)
dim(fits)
## [1] 19 400
head(fits)[, 1:6]
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 0.9516929 0.9527677 0.9500655 0.9570835 0.9596918 0.9514495
## [2,] 0.8118555 0.8139836 0.8086748 0.8227666 0.8282768 0.8113766
## [3,] 0.6763448 0.6786804 0.6728697 0.6884131 0.6945994 0.6758203
## [4,] 0.5702067 0.5724352 0.5668981 0.5817629 0.5877276 0.5697069
## [5,] 0.4894228 0.4914663 0.4863922 0.5000407 0.5055417 0.4889647
## [6,] 0.4272050 0.4290606 0.4244550 0.4368579 0.4418703 0.4267891
fits <- data.frame(fits, dist = golf$dist)
fits <- gather(fits, key = fit, value = measurement, -dist)
dim(fits)
## [1] 7600 3
head(fits)
## dist fit measurement
## 1 24 X1 0.9516929
## 2 36 X1 0.8118555
## 3 48 X1 0.6763448
## 4 60 X1 0.5702067
## 5 72 X1 0.4894228
## 6 84 X1 0.4272050
p + geom_line(data = fits, aes(x = dist / 12, y = measurement, group = fit), alpha = 1/150) + theme_bw()