forked from torkar/icse_tutorial
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathfoo.R
More file actions
164 lines (138 loc) · 5.93 KB
/
Copy pathfoo.R
File metadata and controls
164 lines (138 loc) · 5.93 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
155
156
157
158
159
160
161
162
163
164
# This R file differs from the Rmd and html files. This is a improvement over
# the Rmd/html. Used in a research seminar (español) autumn 2022.
library(rethinking) # math-like model specification language
library(foreign) # for loading funky data files install.packages("foreign")
# d/l from PROMISE (Sayyad & Menzies), contributed by Martin Shepperd
download.file("http://promise.site.uottawa.ca/SERepository/datasets/desharnais.arff", # nolint
"desharnais.arff")
d <- read.arff("desharnais.arff")
# lots of juicy stuff here
str(d)
# see https://www.kaggle.com/datasets/toniesteves/desharnais-dataset for a data
# dictionary.
# Remove columns we don't need
d <- d[-c(1:5, 7:11)]
# convert Language (factor) to numeric because we hate factors
d$Language <- as.numeric(d$Language)
# check out the new data frame
str(d)
##### Step 1 Likelihood?
# We have a count (i.e., Poisson), but what about assumptions?
var(d$Effort)
mean(d$Effort)
# so clearly we break assumptions and need to fall back on negative-binomial
# i.e., for Poisson(lambda), lambda measures both mean and variance.
###############################################################################
# Step 2 Simplified prior analysis
# What is a suitable prior for alpha, i.e., grand mean?
# note we're using LogNormal since we use a log link function
###############################################################################
# num. of max hours in a project / 1500 ~ num. FTEs/yr
max(rlnorm(1e6, 0, 2)) / 1500
# Let's plot the density distribution also
curve(dlnorm(x, meanlog = 0, sdlog = 2), from = 0, to = 3e4)
###############################################################################
# Step 3 Design models
#
# m_cp = complete pooling
# m_np = no pooling
# m_pp = partial pooling
#
##############################################################################
m_cp <- ulam(
alist(
Effort ~ dgampois(lambda, phi),
log(lambda) <- alpha,
alpha ~ dnorm(0, 2),
phi ~ dexp(1)
), data = d, cores = 4, chains = 4, cmdstan = TRUE, log_lik = TRUE, iter = 5e3
)
m_np <- ulam(
alist(
Effort ~ dgampois(lambda, phi),
log(lambda) <- a + a_lang[Language],
a ~ dnorm(0, 2),
a_lang[Language] ~ dnorm(0, 1),
phi ~ dexp(1)
), data = d, cores = 4, chains = 4, cmdstan = TRUE, log_lik = TRUE, iter = 5e3
)
m_pp <- ulam(
alist(
Effort ~ dgampois(lambda, phi),
log(lambda) <- a + a_lang[Language],
a ~ dnorm(0, 3),
a_lang[Language] ~ dnorm(mu_l, sigma_l),
mu_l ~ dnorm(0, 1),
sigma_l ~ dexp(1),
phi ~ dexp(1)
), data = d, cores = 4, chains = 4, cmdstan = TRUE, log_lik = TRUE,
iter = 5e3, control = list(adapt_delta = 0.99)
)
###############################################################################
# Step 4 Model comparison
#
##############################################################################
(ll <- compare(m_cp, m_np, m_pp)) # Use WAIC, even though LOO is SoA
plot(compare(m_cp, m_np, m_pp))
# In short, no model is really significantly better
###############################################################################
# Step 5 Inference
#
##############################################################################
# We're interested to look at the effect Language has on effort.
# Let's look at the two models where we have intercepts for each language
precis(m_np, depth = 2, pars = c("a_lang"))
precis(m_pp, depth = 2, pars = c("a_lang"))
# Plot and compare
par(mfrow = c(1, 2))
plot(precis(m_np, depth = 2, pars = c("a_lang")), main = "No pooling")
plot(precis(m_pp, depth = 2, pars = c("a_lang")), main = "Partial pooling")
par(mfrow = c(1, 1))
# Let's compare the estimates for Language 3 in both models and see how they
# differ on the outcome scale
post_np <- extract.samples(m_np) # contains all samples
post_pp <- extract.samples(m_pp)
exp(mean(post_pp$a) + mean(post_pp$a_lang[, 3])) -
exp(mean(post_np$a) + mean(post_np$a_lang[, 3]))
# so they only differ in ~150 hours on relative effect scale
# But how much do they differ on absolute effect scale (i.e., prediction)
sim_np <- sim(m_np)
sim_pp <- sim(m_pp)
mean(sim_np - sim_pp)
# So m_np predicts -20/+20 higher on the outcome scale xD
# Compare all combinations of languages, but let's first look at
# diff between language 1 and 2.
# Create empty plot window
plot(NULL, xlim = c(-2, 4), ylim = c(0, 1), ylab = "", xlab = "")
# Add the two densities and text
dens(post_np$a_lang[, 1], add = TRUE, col = "blue")
text(2, 0.5, "Language 1", col = "blue")
abline(v = mean(post_np$a_lang[, 1]), col = "blue")
dens(post_np$a_lang[, 2], add = TRUE, col = "red")
text(0, 0.5, "Language 2", , col = "red")
abline(v = mean(post_np$a_lang[, 2]), , col = "red")
# So visually we see that Language 2 is "better", since it seems the mean
# is lower (the vertical lines). Can we quantify that probabilistically?
# Let's use the power of arithmetics :) Take the 1e5 samples and simply
# use subtraction, i.e., L1 - L2
comp_12 <- post_np$a_lang[, 1] - post_np$a_lang[, 2]
dens(comp_12) # plot the difference first
# so slightly positive, i.e., Language 1 has slightly higher values,
# which implies that Language 2 is slightly better then!
# Let's look at what that means!
table(sign(comp_12))
# this is what I get (it can differ somewhat b/c we use stochastic algorithms):
# -1 1
#2547 7453
# ~25% of the time, Language *1* gets lower values than Language *2*.
# ~75% of the time, Language *2* gets lower values than Language *1*.
# If forced to choose, we should pick Language 2, no matter if it's significant
# or not!
# As an exercise for you, you can now compare L1 w/ L3 and L2 w/ L3 also!
# You will see that it's a clear cut case that L3 should be picked, even though
# it's not 'significant'! However, these type of probabilistic statements can
# be made once we have a posterior probability distribution.
#
# In the data set we also have many more independent variables. We remove them
# at the beginning, but we don't have to...
# https://www.kaggle.com/datasets/toniesteves/desharnais-dataset