Skip to content

Commit 84604c2

Browse files
Release: 1.1.0
2 parents b452f4d + 3885eaa commit 84604c2

12 files changed

+510
-21
lines changed

DESCRIPTION

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Collate:
4444
'QuadprogSolver.R'
4545
'Solver.R'
4646
'SolverFactory.R'
47+
'Validation.R'
4748
'constants.R'
4849
'exports.R'
4950
'logo.R'

NAMESPACE

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22

33
export(generate_model)
44
export(powerly)
5+
export(validate)

NEWS.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# Coming changes
2+
[x] Add function to validate the results of a sample size analysis.
3+
[ ] Add tests for `Validation` class.
24
[ ] Add implementation for `summary` and `print` methods for the `Method` class.
35
[ ] Option to set seeds for the cluster via `parallel::setclusterSetRNGStream`
46
[ ] Document the `plot` method in `Method` class.

R/StepOne.R

+20-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ StepOne <- R6::R6Class("StepOne",
77
.measure_value = NULL,
88
.statistic_value = NULL,
99

10-
.measure = NULL,
10+
.measure_type = NULL,
11+
.statistic_type = NULL,
12+
.model_type = NULL,
13+
1114
.statistic = NULL,
1215
.model = NULL,
1316

@@ -26,7 +29,7 @@ StepOne <- R6::R6Class("StepOne",
2629
env$replications <- private$.replications
2730
env$partition <- private$.range$partition
2831
env$true_model_parameters <- private$.true_model_parameters
29-
env$measure <- private$.measure
32+
env$measure <- private$.measure_type
3033

3134
# Function calls.
3235
env$monte_carlo <- private$.monte_carlo
@@ -106,6 +109,10 @@ StepOne <- R6::R6Class("StepOne",
106109

107110
# Set the true model based on the type.
108111
set_model = function(type) {
112+
# Record the type.
113+
private$.model_type <- type
114+
115+
# Create instance based on the type via the factory.
109116
private$.set_model(type)
110117
},
111118

@@ -125,12 +132,15 @@ StepOne <- R6::R6Class("StepOne",
125132

126133
# Set the measure of interest (e.g., sensitivity).
127134
set_measure = function(measure, value) {
128-
private$.measure <- measure
135+
private$.measure_type <- measure
129136
private$.measure_value <- value
130137
},
131138

132139
# Set the statistic computed on the measure values.
133140
set_statistic = function(statistic, value) {
141+
# Record the statistic type.
142+
private$.statistic_type = statistic
143+
134144
# Create an instance of the statistic via the factory.
135145
private$.set_statistic(statistic)
136146

@@ -223,7 +233,7 @@ StepOne <- R6::R6Class("StepOne",
223233
)
224234
title(
225235
main = "Monte Carlo Replicated Measures",
226-
ylab = paste0("Values for measure '", toupper(private$.measure), "'"),
236+
ylab = paste0("Values for measure '", toupper(private$.measure_type), "'"),
227237
cex.main = 1,
228238
cex.lab = 1
229239
)
@@ -283,15 +293,17 @@ StepOne <- R6::R6Class("StepOne",
283293

284294
active = list(
285295
range = function() { return(private$.range) },
286-
replications = function() { return(private$.replications) },
287-
measure_value = function() { return(private$.measure_value) },
288-
statistic_value = function() { return(private$.statistic_value) },
289-
measure = function() { return(private$.measure) },
290296
statistic = function() { return(private$.statistic) },
291297
model = function() { return(private$.model) },
298+
measure_type = function() { return(private$.measure_type) },
299+
statistic_type = function() { return(private$.statistic_type) },
300+
model_type = function() { return(private$.model_type) },
301+
measure_value = function() { return(private$.measure_value) },
302+
statistic_value = function() { return(private$.statistic_value) },
292303
true_model_parameters = function() { return(private$.true_model_parameters) },
293304
measures = function() { return(private$.measures) },
294305
statistics = function() { return(private$.statistics) },
306+
replications = function() { return(private$.replications) },
295307
duration = function() { return(private$.duration) }
296308
)
297309
)

R/StepThree.R

+4-3
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ StepThree <- R6::R6Class("StepThree",
337337
density = c(NA, NA),
338338
bty = "n",
339339
border = c("#bc8f8f52", "#4683b48e"),
340-
cex = 1
340+
cex = 0.7
341341
)
342342

343343
# Sample size of interest.
@@ -379,13 +379,13 @@ StepThree <- R6::R6Class("StepThree",
379379
abline(v = boot_statistics_median, col = "#5f5f5f", lty = 3)
380380
mtext(round(boot_statistics_median, 3), side = 1, at = boot_statistics_median, col = "rosybrown", font = 2, line = 0.3, cex = .9)
381381

382-
# Plot quantiles of bootstrapped statistics.
382+
# Plot percentiles of bootstrapped statistics.
383383
plot(
384384
private$.step_2$step_1$range$sequence,
385385
private$.ci[, "50%"],
386386
type = "l",
387387
lwd = 2,
388-
main = paste0("Quantiles (", 0.5 * 100, "th)"),
388+
main = paste0("Percentiles (", 0.5 * 100, "th)"),
389389
ylab = paste0("Bootstrapped statistics"),
390390
xlab = "",
391391
xaxt = "n",
@@ -416,6 +416,7 @@ StepThree <- R6::R6Class("StepThree",
416416
),
417417

418418
active = list(
419+
step_1 = function() { return(private$.step_2$step_1) },
419420
step_2 = function() { return(private$.step_2) },
420421
boots = function() { return(private$.boots) },
421422
lower_ci = function() { return(private$.lower_ci) },

R/Validation.R

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#' @include Range.R StepOne.R
2+
3+
Validation <- R6::R6Class("Validation",
4+
private = list(
5+
.backend = NULL,
6+
.recommendation = NULL,
7+
.validator = NULL,
8+
9+
# Extract the recommendation for `StepThree` samples.
10+
.set_recommendation = function(step_3, ci = 0.5) {
11+
private$.recommendation <- step_3$samples[paste0(ci * 100, "%")]
12+
},
13+
14+
# Configure new `StepOne` instance (aka `validator`) based on previous one.
15+
.configure_validator = function(step_3) {
16+
# Create instance of `StepOne` that will act as the validator.
17+
private$.validator <- StepOne$new()
18+
19+
# Set set the `validator` instance based on the configuration used to obtain the current results.
20+
private$.validator$set_model(step_3$step_1$model_type)
21+
private$.validator$set_true_model_parameters(matrix = step_3$step_1$true_model_parameters)
22+
private$.validator$set_measure(step_3$step_1$measure_type, step_3$step_1$measure_value)
23+
private$.validator$set_statistic(step_3$step_1$statistic_type, step_3$step_1$statistic_value)
24+
},
25+
26+
# Run the validation for a request sample size.
27+
.run = function(sample, replications) {
28+
# Create `Range` instance with the recommended sample size.
29+
range <- Range$new(sample, sample, tolerance = -1)
30+
31+
# Feed the range to the validator.
32+
private$.validator$set_range(range)
33+
34+
# Run the validation.
35+
private$.validator$simulate(replications, private$.backend)
36+
37+
# Compute the statistics.
38+
private$.validator$compute()
39+
}
40+
),
41+
42+
public = list(
43+
# Register backend.
44+
register_backend = function(backend) {
45+
# Make sure we are provided an active backend.
46+
if (!is.null(backend) && !backend$active) {
47+
# Warn the users.
48+
warning("Please provide an active backend. Will not use this one.")
49+
} else {
50+
# Register the backend.
51+
private$.backend <- backend
52+
}
53+
},
54+
55+
# Prepare for validation.
56+
configure_validator = function(step_3, ci = 0.5) {
57+
# Extract and store the recommended sample size.
58+
private$.set_recommendation(step_3, ci)
59+
60+
# Configure the `validator` instance.
61+
private$.configure_validator(step_3)
62+
},
63+
64+
# Perform the validation.
65+
run = function(sample, replications = 3000) {
66+
# If no sample is provided, then use the recommendation.
67+
if(missing(sample)) {
68+
sample <- private$.recommendation
69+
}
70+
71+
# Run.
72+
private$.run(sample, replications)
73+
},
74+
75+
# Plot the validation results.
76+
plot = function() {
77+
# Revert the changes on exit.
78+
on.exit({
79+
# Restore margins to default.
80+
par(mar = c(5.1, 4.1, 4.1, 2.1))
81+
})
82+
83+
# Adjust margins for layout.
84+
par(mar = c(5.1, 4.1, 4.1, 2.1) + 1)
85+
86+
# Plot histogram of performance measures.
87+
hist(
88+
private$.validator$measures,
89+
col = "#00000023",
90+
border = FALSE,
91+
main = paste0("Sample: ", private$.validator$range$partition, " | ",
92+
"Measure at ", self$percentile, " pert.: ", round(self$percentile_value, 3), " | ",
93+
"Statistic: ", round(private$.validator$statistics, 3)),
94+
xaxt = "n",
95+
xlab = ""
96+
)
97+
title(
98+
xlab = paste0("Performance measure values (", toupper(private$.validator$measure_type), ")"),
99+
line = 4.5,
100+
cex.main = 1,
101+
cex.lab = 1
102+
)
103+
axis(
104+
side = 1,
105+
at = round(seq(min(private$.validator$measures), max(private$.validator$measures), length.out = 15), 2),
106+
line = 1.5,
107+
las = 2,
108+
cex.axis = .9
109+
)
110+
# Value at percentile of interest,
111+
abline(v = self$percentile_value, lwd = 2, lty = 3, col = "darkred")
112+
mtext(round(self$percentile_value, 3), side = 1, at = self$percentile_value, col = "darkred", font = 2, line = 0.3, cex = 1)
113+
}
114+
),
115+
116+
active = list(
117+
recommendation = function() { return(private$.recommendation) },
118+
validator = function() { return(private$.validator) },
119+
measures = function() { return(private$.validator$measures) },
120+
statistic = function() { return(private$.validator$statistics) },
121+
sample = function() { return(private$.validator$range$partition) },
122+
123+
# The desired percentile as a string.
124+
percentile = function() {
125+
return(paste0((1 - private$.validator$statistic_value) * 100, "th"))
126+
},
127+
128+
# The performance measure value at the desired percentile.
129+
percentile_value = function() {
130+
return(quantile(private$.validator$measures, probs = 1 - private$.validator$statistic_value))
131+
}
132+
)
133+
)

0 commit comments

Comments
 (0)