| Title: | Differentially Private Synthetic Data with Guaranteed Utility |
|---|---|
| Description: | Differentially private (DP) synthetic data generation for tabular data. Provides DP Gaussian mixture models, DP Gaussian copulas, DP histogram marginals and a Private Aggregation of Teacher Ensembles (PATE) synthesizer for mixed-type data, together with a standardized utility evaluation framework (univariate fidelity, propensity score MSE, multivariate dependence, downstream task performance), empirical disclosure risk auditing (membership inference, attribute disclosure, record linkage) and privacy budget accounting (basic, advanced and Renyi DP composition). The implementation follows Dwork and Roth (2014) <doi:10.1561/0400000042> and Dwork et al. (2006) <doi:10.1007/11681878_14> for the DP mechanisms, Papernot et al. (2017) <doi:10.1145/3133956.3133982> for the PATE synthesizer, and Woo et al. (2009) <doi:10.2202/1557-4679.1203> for the disclosure risk evaluation framework. |
| Authors: | Mukul Bijalwan [aut, cre], Gunjan Aggarwal [aut], Mukul Jain [aut] |
| Maintainer: | Mukul Bijalwan <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-09-28 16:28:20 UTC |
| Source: | https://github.com/mukulbijalwan/dpsynth |
A synthetic microdata sample modeled on American Community Survey PUMS structure, used as an example in DPSynth.
acs_pums_sampleacs_pums_sample
A data frame with 500 rows and 5 variables:
age in years
annual income in USD
educational attainment
married indicator
weeks worked last year
A synthetic, anonymized subsample modeled on the UCI Adult census-income dataset, used as an example throughout DPSynth. No real personal records are included.
adult_sampleadult_sample
A data frame with 500 rows and 8 variables:
age in years
employment sector
years of education
marital status
working hours per week
sex
capital gain in USD
binary income class
Assumes an attacker knows known_vars for a target record and
uses nearest neighbours in the synthetic data to infer
sensitive_var. Reports the normalized prediction error and the
rate of high-confidence disclosures.
audit_attribute_disclosure( synth, orig, known_vars = NULL, sensitive_var = NULL, n_neighbors = 5 )audit_attribute_disclosure( synth, orig, known_vars = NULL, sensitive_var = NULL, n_neighbors = 5 )
synth |
synthetic data frame |
orig |
original data frame |
known_vars |
column names the attacker observes; default: all
common columns except |
sensitive_var |
sensitive column to predict; default: last column |
n_neighbors |
number of synthetic neighbours used |
list with mean_disclosure_error and high_risk_rate
Estimates how many real records can be uniquely re-identified by matching against the synthetic data: a real record is "linked" when its nearest synthetic neighbour is closer than a quantile threshold of the within-original distance distribution.
audit_linkage_risk(synth, orig, threshold_quantile = 0.05)audit_linkage_risk(synth, orig, threshold_quantile = 0.05)
synth |
synthetic data frame |
orig |
original data frame |
threshold_quantile |
quantile of within-original NN distances used as the linkage threshold |
list with linkage_rate, linked_records,
threshold
Simulates the simplest membership inference attack: for each original record, compute the distance to its nearest synthetic record. Records whose nearest synthetic neighbour is unusually close are considered at risk of a correct "member" verdict.
audit_membership_risk(synth, orig, method = "nearest_neighbor")audit_membership_risk(synth, orig, method = "nearest_neighbor")
synth |
synthetic data frame |
orig |
original data frame |
method |
currently only |
list with risk_score, mean_min_distance and
high_risk_records
Check remaining privacy budget
check_synth_budget(budget)check_synth_budget(budget)
budget |
a |
named vector with remaining_epsilon, spent_epsilon
and fraction_used; also prints a summary
Clamp every column of a data frame (or matrix) to user-specified bounds. Clamping bounds sensitivity and is a prerequisite for calibrated DP noise.
clip_data(data, bounds)clip_data(data, bounds)
data |
data frame or matrix |
bounds |
named list with elements |
data frame with values clipped to the bounds
Separates the synthesis problem into (1) DP marginal distributions – per-column histograms released with Laplace noise – and (2) a DP dependence structure – a Gaussian copula correlation matrix estimated on rank-transformed pseudo-observations, perturbed with Gaussian noise and projected onto the positive-definite cone. Generation inverts the DP marginals through the DP copula (post-processing).
dp_copula_synth( data, n_synth = nrow(data), epsilon = 1, delta = 1e-06, n_bins = 20, copula_type = "gaussian" )dp_copula_synth( data, n_synth = nrow(data), epsilon = 1, delta = 1e-06, n_bins = 20, copula_type = "gaussian" )
data |
data frame (numeric, factor or character columns) |
n_synth |
number of synthetic records |
epsilon |
total privacy parameter epsilon |
delta |
privacy parameter delta |
n_bins |
number of histogram bins for numeric marginals |
copula_type |
currently only |
object of class dp_copula / dp_synthetic
Fits a Gaussian mixture model with diagonal covariances using the perturb-and-postprocess paradigm: sufficient statistics (component counts, means, variances) are perturbed with calibrated Laplace / Gaussian noise so that the released model satisfies (epsilon, delta)-DP. Sampling from the fitted model is post-processing and consumes no additional privacy budget.
dp_gmm_synth( data, n_synth = nrow(data), K = 3, epsilon = 1, delta = 1e-06, bounds = NULL, max_iter = 20 )dp_gmm_synth( data, n_synth = nrow(data), K = 3, epsilon = 1, delta = 1e-06, bounds = NULL, max_iter = 20 )
data |
data frame of purely numeric columns |
n_synth |
number of synthetic records to generate |
K |
number of mixture components |
epsilon |
privacy parameter epsilon (> 0) |
delta |
privacy parameter delta (in (0, 1)) |
bounds |
optional list with |
max_iter |
maximum EM iterations |
object of class dp_gmm / dp_synthetic with the
synthetic data, model parameters and privacy parameters
Synthesizes each column independently from a differentially private histogram (numeric columns) or DP multinomial (categorical columns). No dependence structure is preserved; useful as a fast baseline and for consistent-marginal releases in official statistics.
dp_marginals_synth(data, n_synth = nrow(data), epsilon = 1, n_bins = 20)dp_marginals_synth(data, n_synth = nrow(data), epsilon = 1, n_bins = 20)
data |
data frame |
n_synth |
number of synthetic records |
epsilon |
privacy parameter epsilon (split evenly across columns) |
n_bins |
number of bins for numeric columns |
object of class dp_marginals / dp_synthetic
Partitions the private data into disjoint teacher datasets, fits a teacher model on each partition (no privacy cost), and releases each per-record query through a noisy aggregation of teacher votes. The privacy cost scales with the number of released records.
dp_pate_synth(data, n_synth = nrow(data), epsilon = 1, n_teachers = 10)dp_pate_synth(data, n_synth = nrow(data), epsilon = 1, n_teachers = 10)
data |
data frame |
n_synth |
number of synthetic records |
epsilon |
total privacy parameter (spent across all released records via basic composition) |
n_teachers |
number of disjoint teacher partitions |
object of class dp_pate / dp_synthetic
Top-level orchestrator that dispatches to a DP synthesizer, optionally evaluates utility and audits disclosure risk, and attaches a privacy report.
dp_synthesize( data, method = "copula", n_synth = nrow(data), epsilon = 1, delta = 1e-06, utility_eval = TRUE, risk_audit = TRUE, ... )dp_synthesize( data, method = "copula", n_synth = nrow(data), epsilon = 1, delta = 1e-06, utility_eval = TRUE, risk_audit = TRUE, ... )
data |
original data frame |
method |
one of |
n_synth |
number of synthetic records |
epsilon |
privacy parameter |
delta |
privacy parameter |
utility_eval |
run |
risk_audit |
run disclosure-risk audits? |
... |
further arguments passed to the underlying synthesizer |
object of class dp_synthesis_result
dp_copula_synth, dp_gmm_synth,
dp_marginals_synth, dp_pate_synth
set.seed(1) dat <- data.frame(x = rnorm(200), y = rnorm(200) + 0.5 * rnorm(200)) res <- dp_synthesize(dat, method = "copula", epsilon = 2) print(res)set.seed(1) dat <- data.frame(x = rnorm(200), y = rnorm(200) + 0.5 * rnorm(200)) res <- dp_synthesize(dat, method = "copula", epsilon = 2) print(res)
Trains the same linear model on the synthetic and the original data and
compares out-of-sample RMSE on held-out real data. A
utility_ratio close to 1 indicates good analytic utility.
evaluate_downstream( synth, orig, target_var, predictors = NULL, test_prop = 0.2 )evaluate_downstream( synth, orig, target_var, predictors = NULL, test_prop = 0.2 )
synth |
synthetic data frame |
orig |
original data frame |
target_var |
name of the numeric target column |
predictors |
optional predictor column names; default all others |
test_prop |
held-out fraction of the original data |
list with RMSEs and the utility ratio
Compares the correlation structure (numeric columns) of original and synthetic data via the relative Frobenius-norm distance between correlation matrices and Gaussian-approximated mutual information.
evaluate_multivariate(synth, orig)evaluate_multivariate(synth, orig)
synth |
synthetic data frame |
orig |
original data frame |
list with correlation distance and mutual-information summaries
Fits a logistic model to distinguish synthetic from original records.
Under perfect synthesis the expected pMSE is with
; the reported ratio is 0 for
indistinguishable data and grows as fidelity degrades.
evaluate_propensity(synth, orig)evaluate_propensity(synth, orig)
synth |
synthetic data frame |
orig |
original data frame |
list with pMSE, ratio (standardised) and c
Compares original and synthetic columns with Kolmogorov-Smirnov statistics, Hellinger distance (histogram-based for numeric columns, Jensen-Shannon divergence for categorical columns) and relative moment errors.
evaluate_univariate(synth, orig)evaluate_univariate(synth, orig)
synth |
synthetic data frame |
orig |
original data frame |
data frame of per-variable fidelity metrics
Runs any combination of univariate, multivariate, propensity (pMSE) and
downstream (TSTR) fidelity metrics and returns a
dp_utility_report.
evaluate_utility( synthetic_data, original_data, metrics = c("univariate", "multivariate", "propensity"), target_var = NULL )evaluate_utility( synthetic_data, original_data, metrics = c("univariate", "multivariate", "propensity"), target_var = NULL )
synthetic_data |
synthetic data frame |
original_data |
original data frame |
metrics |
character vector of metric groups to run |
target_var |
optional target for the downstream metric |
object of class dp_utility_report
Release a statistic under (epsilon, delta)-DP by adding Gaussian noise
calibrated to the L2 sensitivity via the classical analytic bound
.
gaussian_mech(value, sensitivity, epsilon, delta = 1e-06)gaussian_mech(value, sensitivity, epsilon, delta = 1e-06)
value |
numeric statistic (scalar or vector) |
sensitivity |
L2 sensitivity of the statistic |
epsilon |
privacy parameter epsilon (> 0) |
delta |
privacy parameter delta (in (0, 1)) |
numeric vector: noisy release of value
Create a privacy budget tracker
new_synth_budget( epsilon, delta = 0, accounting = c("basic", "advanced", "rdp") )new_synth_budget( epsilon, delta = 0, accounting = c("basic", "advanced", "rdp") )
epsilon |
total epsilon available |
delta |
total delta available |
accounting |
one of |
object of class synth_privacy_budget
Print a synthesis result
## S3 method for class 'dp_synthesis_result' print(x, ...)## S3 method for class 'dp_synthesis_result' print(x, ...)
x |
a |
... |
unused |
No return value, called for side effects. The input x is returned
invisibly.
Draw n independent Laplace(location, scale) variates
using inverse-CDF sampling. The Laplace mechanism adds
Lap(sensitivity / epsilon) noise to achieve pure epsilon-DP.
rlaplace(n, location = 0, scale = 1)rlaplace(n, location = 0, scale = 1)
n |
number of draws |
location |
location parameter |
scale |
scale parameter (must be > 0) |
numeric vector of length n
Records a DP release consuming epsilon (and optionally
delta) and updates the accumulated spend under the configured
composition rule. Issues a warning when the total budget is exceeded.
spend_synth(budget, epsilon, delta = 0, description = "")spend_synth(budget, epsilon, delta = 0, description = "")
budget |
a |
epsilon |
epsilon spent by this step |
delta |
delta spent by this step |
description |
free-text description of the step |
updated budget object