-
Notifications
You must be signed in to change notification settings - Fork 6
Methods
So you want to add a new statistical method to jfa
? Great, your help on this open-source project is much appreciated. First, if you do not have a fork and a clone of the jfa
repository, please read the Wiki page on setting up the jfa
repository. In this guide, we will go through the process of adding a new method to jfa
step by step. You will learn where to change the underlying R
code and how to make a pull request to merge your changes.
- Step 1: Create a new method in
methods.R
- Step 2: Add the new method to the
evaluation()
function - Step 3: Creating a unit test for your method
- Step 4: Making a pull request
Navigate to your local clone of the jfa repository. You should see a folder R
in there. In this folder is a file methods.R
that contains most of the existing methods in jfa
.
As possible input options for your new method, you have (among others) access to:
-
conf.level
: A numeric value between 0 and 1 specifying the confidence level. -
n
: An integer larger than 0 specifying sample size used. -
bookvalues
: A numeric vector of book values of lengthn
. -
bookvalues
: A numeric vector of audit values of lengthn
. -
taints
: A numeric vector of taints of lengthn
. -
N.units
: An integer larger than 0 specifying the population size.
For example, check out the function .rohrbach()
that calculates Rohrbach's augmented variance estimator.
.rohrbach <- function(taints, conf.level, n, N.units = NULL, r.delta) {
if (is.null(N.units))
stop("'N.units' missing for evaluation")
w <- 1 - taints
mu <- mean(taints)
vars <- sum(w^2) / n - (2 - (r.delta / n)) * ((1 / 2) * ((sum(w^2) / n) - stats::var(w)))
result <- list()
result[["ub"]] <- mu + stats::qnorm(p = conf.level) * sqrt((1 - (n / N.units)) * (vars / n))
result[["mle"]] <- sum(taints) / n
result[["precision"]] <- result[["ub"]] - result[["mle"]]
return(result)
}
As you can see, the function takes taints
, conf.level
, n
, N.units
, and r.delta
as input arguments, performs some calculations, and then returns a returns a result
object. It is essential that this result
object contains at least the three following entries: ub
(the upper bound), mle
(the most likely error), and precision
(the precision; usually the upper bound minus the most likely error).
Now you are ready to add your method to jfa
. Navigate to the file evaluation.R
and locate the following piece of code:
out <- switch(method,
'stringer' = .stringer(t, conf.level, n.obs), # Classical evaluation using the Stringer bound
'stringer.meikle' = .stringer(t, conf.level, n.obs, correction = 'meikle'), # Classical evaluation using the Stringer bound with Meikle's adjustment
'stringer.lta' = .stringer(t, conf.level, n.obs, correction = 'lta'), # Classical evaluation using the Stringer bound with the LTA adjustment
'stringer.pvz' = .stringer(t, conf.level, n.obs, correction = 'pvz'), # Classical evaluation using the Stringer bound with PvZ adjustment
'rohrbach' = .rohrbach(t, conf.level, n.obs, N.units, r.delta), # Classical evaluation using Rohrbachs augmented variance bound
'moment' = .moment(t, conf.level, n.obs, m.type), # Classical evaluation using the Modified Moment bound
'coxsnell' = .coxsnell(t, conf.level, n.obs, cs.a, cs.b, cs.mu, 1 + prior.x, 1 + prior.n - prior.x), # Bayesian evaluation using the Cox and Snell bound
'mpu' = .mpu(t, conf.level, n.obs), # Classical evaluation using the Mean-per-unit estimator
'direct' = .direct(bookvalues, auditvalues, conf.level, N.items, n.obs, N.units), # Classical evaluation using the Direct estimator
'difference' = .difference(bookvalues, auditvalues, conf.level, N.items, n.obs), # Classical evaluation using the Difference estimator
'quotient' = .quotient(bookvalues, auditvalues, conf.level, N.items, n.obs), # Classical evaluation using the Quotient estimator
'regression' = .regression(bookvalues, auditvalues, conf.level, N.items, n.obs, N.units), # Classical evaluation using the Regression estimator
'newmethod' = NULL) # Add new method here
mle <- out[["mle"]]
ub <- out[["ub"]]
precision <- out[["precision"]]
Comment out the code and replace NULL
with the function that calls your new method (e.g., .functionFromMethodsFile()
). The evaluation()
function should handle the rest by saving the appropriate results in the following code. Test your method carefully by calling the evaluation()
, summary.jfaEvaluation()
, and plot.jfaEvaluation()
functions.
Each new method requires a benchmark so that it can regularly be tested for inconsistencies and errors. Check out how to contribute a new benchmark to jfa for a guide on how to add a unit test that checks your method.
When the benchmark of the new method has passed the tests, you may commit and push your changes to your version of the jfa
repository. Next, you can open a new pull request to merge your changes into the development
branch of koenderks/jfa. First, navigate to the koenderks/jfa repository on GitHub. There, go to the Pull request tab. Click on New pull request.
Select Compare across forks, and select the branch that contains your added benchmark.
Click on Create pull request to create the pull request. You are now finished adding the method. Keep an eye on the status and conversation in the pull request to see if any changes are requested by the maintainer.