-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdistribution_fit.R
59 lines (50 loc) · 1.93 KB
/
distribution_fit.R
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
skewness = function(x)
{
mean((x - mean(x))^3) / (mean((x - mean(x))^2)^1.5)
}
skew_normal_objective = function(x, target)
{
central = target[1]
lower = target[2]
upper = target[3]
xi = x[1]
omega = x[2]
alpha = x[3]
delta = alpha / sqrt(1 + alpha^2)
mean = xi + omega * delta * sqrt(2 / pi)
lq = sn::psn(lower, xi, omega, alpha)
uq = sn::psn(upper, xi, omega, alpha)
return ((central - mean) ^ 2 + (lq - 0.025) ^ 2 + (uq - 0.975) ^ 2)
}
skew_normal_solve = function(central, lower, upper, adj_react2)
{
d = NULL;
set.seed(12345)
for (i in seq_along(central))
{
if (adj_react2[i]) {
# Get point estimate of q, crude seroprevalence (non-adjusted)
p = central[i]
sensitivity = 0.844
specificity = 0.986
q = p * (sensitivity) + (p - 1) * (specificity - 1)
# Model p with uncertainty over sensitivity and specificity
sensitivity = rbeta(100000, shape1 = 31.65, shape2 = 6.3)
specificity = rbeta(100000, 4*98.6, 4*1.4)[sensitivity > q]
sensitivity = sensitivity[sensitivity > q]
p = (q + specificity - 1) / (sensitivity + specificity - 1);
# Get skew-normal distribution that matches these parameters
par = cp2dp(c(mean(p), sd(p), min(0.98, skewness(p))), "SN");
d = rbind(d,
data.table(xi = par[1], omega = par[2], alpha = par[3]));
} else {
solution = optim(par = c(central[i], (upper[i] - lower[i]) / 4, 0), fn = skew_normal_objective,
target = c(central[i], lower[i], upper[i]),
method = "Nelder-Mead", control = list(maxit = 10000, abstol = 0, reltol = 0));
d = rbind(d,
data.table(xi = solution$par[1], omega = solution$par[2], alpha = solution$par[3])
);
}
}
return (d)
}