Skip to content

Commit bfc6b85

Browse files
committed
Fix bug in Issue #49
Also fix a bug that becomes apparent after fixing the original bug: Not all partitions in the bootstrap replication are necessarily be filled, yielding NaN values when the statistic is calculated. Add data validation to ensure only calculating statistic on partitions that contain values.
1 parent a94cd77 commit bfc6b85

1 file changed

Lines changed: 23 additions & 14 deletions

File tree

R/mechanism-bootstrap.R

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,29 @@
55
#' @param sensitivity Sensitivity of the function
66
#' @param epsilon Numeric differential privacy parameter
77
#' @param fun Function to evaluate
8+
#' @param inputObject the Bootstrap mechanism object on which the input function will be evaluated
89
#' @return Value of the function applied to one bootstrap sample
910
#' @import stats
1011
#' @export
1112

12-
bootstrap.replication <- function(x, n, sensitivity, epsilon, fun) {
13+
bootstrap.replication <- function(x, n, sensitivity, epsilon, fun, inputObject, ...) {
1314
partition <- rmultinom(n=1, size=n, prob=rep(1 / n, n))
14-
max.appearances <- max(partition)
15-
probs <- sapply(1:max.appearances, dbinom, size=n, prob=(1 / n))
16-
stat.partitions <- vector('list', max.appearances)
17-
for (i in 1:max.appearances) {
18-
variance.i <- (i * probs[i] * (sensitivity^2)) / (2 * epsilon)
19-
stat.i <- fun(x[partition == i])
20-
noise.i <- dpNoise(n=length(stat.i), scale=sqrt(variance.i), dist='gaussian')
21-
stat.partitions[[i]] <- i * stat.i + noise.i
15+
# make a sorted vector of the partitions of the data
16+
# because it is not guaranteed that every partition from 1:max.appearances will have a value in it
17+
# so we need to loop through only the partitions that have data
18+
validPartitions <- sort(unique(partition[,1]))
19+
# we do not want the 0 partition, so we remove it from the list
20+
validPartitions <- validPartitions[2:length(validPartitions)]
21+
# print the unique values of the partition, to track which entries may result in NaN
22+
print(validPartitions)
23+
probs <- sapply(1:length(validPartitions), dbinom, size=n, prob=(1 / n))
24+
stat.partitions <- vector('list', length(validPartitions))
25+
for (i in 1:length(validPartitions)) {
26+
currentPartition <- validPartitions[i]
27+
variance.currentPartition <- (currentPartition * probs[i] * (sensitivity^2)) / (2 * epsilon)
28+
stat.currentPartition <- inputObject$bootStatEval(x[partition == currentPartition], fun, ...)
29+
noise.currentPartition <- dpNoise(n=length(stat.currentPartition), scale=sqrt(variance.currentPartition), dist='gaussian')
30+
stat.partitions[[i]] <- currentPartition * stat.currentPartition + noise.currentPartition
2231
}
2332
stat.out <- do.call(rbind, stat.partitions)
2433
return(apply(stat.out, 2, sum))
@@ -39,10 +48,10 @@ mechanismBootstrap <- setRefClass(
3948
)
4049

4150
mechanismBootstrap$methods(
42-
bootStatEval = function(xi) {
51+
bootStatEval = function(xi, fun, ...) {
4352
fun.args <- getFuncArgs(fun, inputList=list(...), inputObject=.self)
44-
input.vals = c(list(x=x), fun.args)
45-
stat <- do.call(boot.fun, input.vals)
53+
input.vals = c(list(x=xi), fun.args)
54+
stat <- do.call(fun, input.vals)
4655
return(stat)
4756
})
4857

@@ -58,11 +67,11 @@ mechanismBootstrap$methods(
5867
})
5968

6069
mechanismBootstrap$methods(
61-
evaluate = function(fun, x, sens, postFun) {
70+
evaluate = function(fun, x, sens, postFun, ...) {
6271
x <- censordata(x, .self$var.type, .self$rng)
6372
x <- fillMissing(x, .self$var.type, .self$impute.rng[0], .self$impute.rng[1])
6473
epsilon.part <- epsilon / .self$n.boot
65-
release <- replicate(.self$n.boot, bootstrap.replication(x, n, sens, epsilon.part, fun=.self$bootStatEval))
74+
release <- replicate(.self$n.boot, bootstrap.replication(x, n, sens, epsilon.part, fun=fun, inputObject = .self, ...))
6675
std.error <- .self$bootSE(release, .self$n.boot, sens)
6776
out <- list('release' = release, 'std.error' = std.error)
6877
out <- postFun(out)

0 commit comments

Comments
 (0)