Skip to content

Commit a242c96

Browse files
committed
Add report() function
1 parent 4de674b commit a242c96

33 files changed

+4253
-53
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Authors@R:
1111
Description: Implements the audit sampling workflow as discussed in Derks et al. (2019) <doi:10.31234/osf.io/9f6ub>. The package makes it easy for an auditor to plan an audit sample, sample from the population, and evaluating that sample using various confidence bounds according to the International Standards on Auditing. Furthermore, the package implements Bayesian equivalents of these methods.
1212
BugReports: https://github.com/koenderks/jfa/issues
1313
URL: https://github.com/koenderks/jfa, https://koenderks.github.io/jfa/
14-
Suggests: testthat, knitr, rmarkdown
14+
Suggests: testthat, knitr, rmarkdown, kableExtra
1515
Language: en-US
1616
License: GPL-3
1717
Encoding: UTF-8

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ S3method(print,jfaSelection)
1313
export(auditPrior)
1414
export(evaluation)
1515
export(planning)
16+
export(report)
1617
export(selection)

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# jfa 0.5.0
22

3+
- Add a function `report()` that automatically generates an audit report.
34
- Removed the `sampling()` function, which is now replaced entirely with the `selection()` function.
45
- Changed the output of the `evaluation()` function when an estimator is used.
56

R/evaluation.R

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
#' \item{populationK}{the assumed total errors in the population. Used in inferences with \code{hypergeometric} method.}
8484
#' \item{prior}{an object of class 'jfaPrior' to represents the prior distribution.}
8585
#' \item{posterior}{an object of class 'jfaPosterior' to represents the posterior distribution.}
86+
#' \item{data}{a data frame containing the relevant columns from the \code{sample} input.}
8687
#'
8788
#' @author Koen Derks, \email{k.derks@nyenrode.nl}
8889
#'
@@ -357,10 +358,10 @@ evaluation <- function(confidence = 0.95, method = "binomial", N = NULL,
357358
result[["mle"]] <- as.numeric(mle)
358359
if(!is.null(precision))
359360
result[["precision"]] <- as.numeric(precision)
361+
if(!is.null(populationBookValue))
362+
result[["popBookvalue"]] <- as.numeric(populationBookValue)
360363
if(method %in% c("direct", "difference", "quotient", "regression")){
361364
# These methods yield an interval instead of a bound
362-
result[["popBookvalue"]] <- as.numeric(populationBookValue)
363-
result[["pointEstimate"]] <- as.numeric(out[["pointEstimate"]])
364365
result[["lowerBound"]] <- as.numeric(out[["lowerBound"]])
365366
result[["upperBound"]] <- as.numeric(out[["upperBound"]])
366367
} else {
@@ -377,12 +378,17 @@ evaluation <- function(confidence = 0.95, method = "binomial", N = NULL,
377378
result[["populationK"]] <- as.numeric(populationK)
378379
# Produce relevant conclusions conditional on the analysis result
379380
approvePrecision <- TRUE
380-
if(minPrecision != 1)
381-
approvePrecision <- result[["precision"]] <= minPrecision
381+
if(minPrecision != 1){
382+
if(method %in% c("direct", "difference", "quotient", "regression")){
383+
approvePrecision <- (result[["precision"]] / populationBookValue) < minPrecision
384+
} else {
385+
approvePrecision <- result[["precision"]] < minPrecision
386+
}
387+
}
382388
approveMateriality <- TRUE
383389
if(materiality != 1){
384390
if(method %in% c("direct", "difference", "quotient", "regression")){
385-
approveMateriality <- populationBookValue <= result[["upperBound"]] && populationBookValue >= result[["lowerBound"]]
391+
approveMateriality <- (result[["upperBound"]] / populationBookValue) < materiality
386392
} else {
387393
approveMateriality <- result[["confBound"]] < materiality
388394
}
@@ -466,6 +472,16 @@ evaluation <- function(confidence = 0.95, method = "binomial", N = NULL,
466472
# Add class 'jfaPosterior' to the posterior distribution object.
467473
class(result[["posterior"]]) <- "jfaPosterior"
468474
}
475+
if(!is.null(sample)){
476+
indexa <- which(colnames(sample) == auditValues)
477+
indexb <- which(colnames(sample) == bookValues)
478+
frame <- as.data.frame(sample[, c(indexb, indexa)])
479+
frame <- cbind(as.numeric(rownames(frame)), frame)
480+
frame[["difference"]] <- frame[, 2] - frame[, 3]
481+
frame[["taint"]] <- frame[, 4] / frame[, 2]
482+
colnames(frame) <- c("Row", bookValues, auditValues, "Difference", "Taint")
483+
result[["data"]] <- frame
484+
}
469485
# Add class 'jfaEvaluation' to the result.
470486
class(result) <- "jfaEvaluation"
471487
return(result)

R/hidden.R

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ print.jfaEvaluation <- function(x, digits = 2, ...){
180180
# ------------------------------------------------------------
181181
# Output:
182182
#
183-
# Most likely error: ", round(x[["pointEstimate"]], digits), "
183+
# Most likely error: ", round(x[["mle"]], digits), "
184184
# Lower bound: ", round(x[["lowerBound"]], digits),"
185185
# Upper bound: ", round(x[["upperBound"]], digits),"
186186
# Precision: ", round(x[["precision"]], digits),"
@@ -382,13 +382,23 @@ plot.jfaEvaluation <- function(x, ...){
382382
if(x[["method"]] %in% c("stringer", "stringer-meikle", "stringer-lta", "stringer-pvz", "rohrbach", "moment", "coxsnell"))
383383
stop("No plotting method available for a confidence bound from this method.")
384384
if(x[["method"]] %in% c("direct", "difference", "quotient", "regression")){
385-
ymin <- x[["lowerBound"]] - (x[["pointEstimate"]] - x[["lowerBound"]])
386-
ymax <- x[["upperBound"]] + (x[["upperBound"]] - x[["pointEstimate"]])
387-
ticks <- pretty(ymin, ymax, min.n = 5)
388-
graphics::plot(x = 0, y = x[["pointEstimate"]], bty = "n", cex = 2, pch = 19, xlab = "Population book value", ylab = "", ylim = c(min(ticks), max(ticks)), xlim = c(-0.1, 0.1), axes = FALSE)
389-
graphics::arrows(x0 = 0, x1 = 0, y0 = x[["lowerBound"]], y1 = x[["upperBound"]], code = 3, lwd = 2, col = "black", angle = 90)
390-
graphics::axis(2, at = ticks, las = 1)
391-
graphics::abline(h = x[["popBookvalue"]], lty = 2)
385+
ymin <- x[["mle"]] - 2 * x[["precision"]]
386+
ymax <- x[["mle"]] + 2 * x[["precision"]]
387+
graphics::plot(0, type = "n", ylim = c(ymin, ymax), ylab = expression(E), xlim = c(0, 1), bty = "n", xaxt = "n", xlab = "", yaxt = "n", main = paste0(round(x[["confidence"]] * 100, 2), "% Confidence interval"))
388+
yBreaks <- base::pretty(c(ymin, ymax), n = 6)
389+
graphics::axis(side = 2, at = yBreaks, labels = base::format(round(yBreaks), scientific = F, big.mark = ","), las = 1)
390+
graphics::segments(x0 = 0, x1 = 1, y0 = 0, y1 = 0, lty = 2, col = "gray")
391+
if(x[["materiality"]] != 1)
392+
graphics::segments(x0 = 0, x1 = 1, y0 = (x[["popBookvalue"]] * x[["materiality"]]), y1 = (x[["popBookvalue"]] * x[["materiality"]]), lty = 2, col = "red")
393+
graphics::points(x = 0.5, y = x[["mle"]], pch = 19)
394+
graphics::arrows(x0 = 0.5, x1 = 0.5, y0 = x[["lowerBound"]], y1 = x[["upperBound"]], code = 3, lwd = 2, col = "black", angle = 90)
395+
graphics::text(x = 0.86, y = x[["mle"]], labels = paste0("Most likely error = ", format(round(x[["mle"]], 2), scientific = FALSE, big.mark = ",")), cex = 0.75, adj = c(1, 0.5))
396+
graphics::text(x = 0.87, y = x[["lowerBound"]], labels = paste0("Lower bound = ", format(round(x[["lowerBound"]], 2), scientific = FALSE, big.mark = ",")), cex = 0.75, adj = c(1, 0.5))
397+
graphics::text(x = 0.87, y = x[["upperBound"]], labels = paste0("Upper bound = ", format(round(x[["upperBound"]], 2), scientific = FALSE, big.mark = ",")), cex = 0.75, adj = c(1, 0.5))
398+
graphics::segments(x0 = 0.40, x1 = 0.40, y0 = x[["mle"]], y1 = x[["upperBound"]], col = "black")
399+
graphics::segments(x0 = 0.40, x1 = 0.42, y0 = x[["mle"]], y1 = x[["mle"]], col = "black")
400+
graphics::segments(x0 = 0.40, x1 = 0.42, y0 = x[["upperBound"]], y1 = x[["upperBound"]], col = "black")
401+
graphics::text(x = 0.15, y = (x[["upperBound"]] - x[["precision"]]/2), labels = paste0("Precision = ", format(round(x[["precision"]], 2), scientific = FALSE, big.mark = ",")), cex = 0.75, adj = c(0, 0.5))
392402
} else {
393403
limx <- length(0:x[["n"]])
394404
if(limx > 51){

R/internal.R

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,13 @@
1717
# .dCoxAndSnellF <- function(x, df1, df2, multiplicationFactor){
1818
# # Rewritten using Wolfram Mathematica
1919
# (df1 ** (df1 / 2) * df2**(df2 / 2) * (x / multiplicationFactor) ** (- 1 + df1 / 2) * (df2 + (df1 * x) / multiplicationFactor)**(( -df1 - df2) / 2))/(abs(multiplicationFactor) * beta(df1/2, df2/2))
20-
# }
20+
# }
21+
22+
.getfun<-function(x) {
23+
if(length(grep("::", x))>0) {
24+
parts<-strsplit(x, "::")[[1]]
25+
getExportedValue(parts[1], parts[2])
26+
} else {
27+
x
28+
}
29+
}

R/report.R

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#' Generate an Audit Report
2+
#'
3+
#' @description This function takes an object of class \code{jfaEvaluation}, creates a report containing the results, and saves the report to a file in your working directory.
4+
#'
5+
#' For more details on how to use this function see the package vignette:
6+
#' \code{vignette("jfa", package = "jfa")}
7+
#'
8+
#' @usage report(object = NULL, file = NULL, format = "html_document")
9+
#'
10+
#' @param object an object of class 'jfaEvaluation' as returned by the \code{evaluation()} function.
11+
#' @param file a string that gives the desired name of the file (e.g. \code{"report.html"}). The report is created in your current working directory.
12+
#' @param format can be either one of \code{"html_document"} or \code{"pdf_document"} (required MikTex).
13+
#'
14+
#' @return A html or pdf report containing the results of the evaluation.
15+
#'
16+
#' @author Koen Derks, \email{k.derks@nyenrode.nl}
17+
#'
18+
#' @seealso \code{\link{evaluation}}
19+
#'
20+
#' @examples
21+
#' library(jfa)
22+
#' set.seed(1)
23+
#'
24+
#' # Generate some audit data (N = 1000):
25+
#' data <- data.frame(ID = sample(1000:100000, size = 1000, replace = FALSE),
26+
#' bookValue = runif(n = 1000, min = 700, max = 1000))
27+
#'
28+
#' # Using monetary unit sampling, draw a random sample from the population.
29+
#' s1 <- selection(population = data, sampleSize = 100, units = "mus",
30+
#' bookValues = "bookValue", algorithm = "random")
31+
#' s1_sample <- s1$sample
32+
#' s1_sample$trueValue <- s1_sample$bookValue
33+
#' s1_sample$trueValue[2] <- s1_sample$trueValue[2] - 500 # One overstatement is found
34+
#'
35+
#' e2 <- evaluation(sample = s1_sample, bookValues = "bookValue", auditValues = "trueValue",
36+
#' method = "stringer", materiality = 0.05, counts = s1_sample$counts)
37+
#'
38+
#' # Generate report
39+
#' # report(e2, file = "myFile.html")
40+
#'
41+
#' @keywords evaluation report audit
42+
#'
43+
#' @export
44+
45+
report <- function(object = NULL, file = NULL, format = "html_document"){
46+
47+
if(!class(object) == "jfaEvaluation")
48+
stop("Object must be of class 'jfaEvaluation'.")
49+
50+
#Determine the template
51+
theFile <- system.file("rmd/report.Rmd", package = "jfa")
52+
53+
#Process the Arguments
54+
args <- list()
55+
args$input <- theFile
56+
args$output_dir <- getwd()
57+
args$output_format <- format
58+
args$output_file <- file
59+
60+
#Run the render
61+
outputFileName <- do.call(.getfun('rmarkdown::render'), args = args)
62+
invisible(outputFileName)
63+
}

README.Rmd

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ library(jfa)
8282

8383
### Vignettes
8484

85+
The package vignettes contain explanations about the functionality of `jfa` illustated using simple examples.
86+
8587
* [Get started](https://koenderks.github.io/jfa/articles/jfa.html)
8688
* [The audit sampling workflow](https://koenderks.github.io/jfa/articles/v1auditWorkflow.html)
8789
* [Constructing a prior distribution](https://koenderks.github.io/jfa/articles/v2priorDistributions.html)
@@ -104,6 +106,12 @@ If you are willing to contribute to the improvement of the package by adding a b
104106

105107
Below is a list of the available functions in the current version of `jfa`, sorted by their occurrence in the standard audit sampling workflow.
106108

109+
* [`auditPrior()`](#create-a-prior-distribution-with-the-auditprior-function)
110+
* [`planning()`](#plan-a-sample-with-the-planning-function)
111+
* [`selection()`](#select-transactions-with-the-selection-function)
112+
* [`evaluation()`](#evaluate-a-sample-with-the-evaluation-function)
113+
* [`report()`](#generate-a-report-with-the-report-function)
114+
107115
### Create a prior distribution with the `auditPrior()` function:
108116

109117
The `auditPrior()` function creates a prior distribution according to one of several methods, including the audit risk model and assessments of the inherent and control risk. The returned object is of class `jfaPrior` and can be used with associated `print()` and `plot()` methods. `jfaPrior` results can also be used as input argument for the `prior` argument in other functions.
@@ -197,9 +205,19 @@ The `evaluation()` function takes a sample data frame or summary statistics abou
197205
| `quotient` | Touw and Hoogduin (2011) | Quotient estimator | `populationBookValue` |
198206
| `regression` | Touw and Hoogduin (2011) | Regression estimator | `populationBookValue` |
199207

208+
### Generate a report with the `report()` function:
209+
210+
The `report()` function takes an object of class `jfaEvaluation` as returned by the `evaluation()` function, automatically generates a `html` or `pdf` report containing the analysis results and their interpretation, and saves the report to your local computer.
211+
212+
*Full function with default arguments:*
213+
214+
`report(object = NULL, file = NULL, format = "html_document")`
215+
216+
For an example report, see the following [link](https://github.com/koenderks/jfa/tree/master/man/figures/readme/report/report.pdf).
217+
200218
## References
201219

202-
- Bickel, P. J. (1992). Inference and auditing: The Stringer Bound. *International Statistical Review*, 60(2), 197–209. - [View online](https://www.jstor.org/stable/1403650)
220+
- Bickel, P. J. (1992). Inference and auditing: The Stringer bound. *International Statistical Review*, 60(2), 197–209. - [View online](https://www.jstor.org/stable/1403650)
203221
- Cox, D. R., & Snell, E. J. (1979). On sampling and the estimation of rare errors. *Biometrika*, 66(1), 125-132. - [View online](https://doi.org/10.1093/biomet/66.1.125)
204222
- Derks, K. (2020). jfa: Bayesian and classical audit sampling. R package version 0.4.0. - [View online](https://cran.r-project.org/package=jfa)
205223
- Derks, K., de Swart, J., van Batenburg, P., Wagenmakers, E.-J., & Wetzels, R. (2020). Priors in a Bayesian audit: How integration of existing information into the prior distribution can improve audit transparency and efficiency. *Under review*. - [View online](https://psyarxiv.com/8fhkp/)

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ The `jfa` package can then be loaded in R or RStudio by typing:
8888

8989
### Vignettes
9090

91+
The package vignettes contain explanations about the functionality of
92+
`jfa` illustated using simple examples.
93+
9194
- [Get started](https://koenderks.github.io/jfa/articles/jfa.html)
9295
- [The audit sampling
9396
workflow](https://koenderks.github.io/jfa/articles/v1auditWorkflow.html)
@@ -129,6 +132,12 @@ Below is a list of the available functions in the current version of
129132
`jfa`, sorted by their occurrence in the standard audit sampling
130133
workflow.
131134

135+
- [`auditPrior()`](#create-a-prior-distribution-with-the-auditprior-function)
136+
- [`planning()`](#plan-a-sample-with-the-planning-function)
137+
- [`selection()`](#select-transactions-with-the-selection-function)
138+
- [`evaluation()`](#evaluate-a-sample-with-the-evaluation-function)
139+
- [`report()`](#generate-a-report-with-the-report-function)
140+
132141
### Create a prior distribution with the `auditPrior()` function:
133142

134143
The `auditPrior()` function creates a prior distribution according to
@@ -254,9 +263,23 @@ FALSE, nPrior = 0, kPrior = 0, rohrbachDelta = 2.7, momentPoptype =
254263
| `quotient` | Touw and Hoogduin (2011) | Quotient estimator | `populationBookValue` |
255264
| `regression` | Touw and Hoogduin (2011) | Regression estimator | `populationBookValue` |
256265

266+
### Generate a report with the `report()` function:
267+
268+
The `report()` function takes an object of class `jfaEvaluation` as
269+
returned by the `evaluation()` function, automatically generates a
270+
`html` or `pdf` report containing the analysis results and their
271+
interpretation, and saves the report to your local computer.
272+
273+
*Full function with default arguments:*
274+
275+
`report(object = NULL, file = NULL, format = "html_document")`
276+
277+
For an example report, see the following
278+
[link](https://github.com/koenderks/jfa/tree/master/man/figures/readme/report/report.pdf).
279+
257280
## References
258281

259-
- Bickel, P. J. (1992). Inference and auditing: The Stringer Bound.
282+
- Bickel, P. J. (1992). Inference and auditing: The Stringer bound.
260283
*International Statistical Review*, 60(2), 197–209. - [View
261284
online](https://www.jstor.org/stable/1403650)
262285
- Cox, D. R., & Snell, E. J. (1979). On sampling and the estimation of

cran-comments.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
## This is a submission for version 0.5.0
22
This is jfa version 0.5.0. In this version I have:
33

4+
* Added a report function.
45
* Deprecated the sampling function.
6+
* Extended unit tests.
57

68
## Test environments
79
* OS X install (on travis-ci), R release

0 commit comments

Comments
 (0)