Structurally faithful development surrogates for tabular data.
masque makes a synthetic copy of a confidential table that keeps its
design, missing values and correlations. Analysts write and test code on
the copy. The data custodian then runs the finished code on the real data,
using a private recipe that translates names and labels.
It is for custodians of confidential research data who want an outside analyst to build the analysis without seeing the data, and for the analysts who build it. The input can be a single table, a folder of files or a multi-sheet workbook.
Security note. Clones made with masque 0.13.0 or earlier can reveal which alias stands for which label. If you shared one, make it again with 0.14.0 and share the new clone instead. The same seed gives the same values.
The changelog lists what changed in each release.
Every table masque returns is a data.table.
Pre-built binaries from r-universe:
install.packages(
"masque",
repos = c("https://max578.r-universe.dev", "https://cloud.r-project.org")
)Or from GitHub:
# install.packages("pak")
pak::pak("max578/masque")library(masque)
# Read a small public fixture (alpha-design field trial; John & Williams, 1995).
f <- system.file("extdata", "john_alpha.csv", package = "masque")
df <- read.csv(f, stringsAsFactors = TRUE)
# One guided call: read -> propose roles -> (review) -> mask -> audit.
# In an interactive session it pauses to let you review the plan;
# ask = FALSE skips the pause.
m <- masque(df, mode = "collaborate", seed = 1L)
synth <- synthetic(m) # hand this to the analyst
rec <- recipe(m) # keep this private
# Analyst builds a pipeline against the synthetic namespace ...
fit <- lm(yield ~ gen + rep, data = synth)
# ... and the custodian re-targets it to the original data.
preds <- predict(fit, newdata = apply_recipe(df, rec))A folder of files or a multi-sheet workbook works the same way. Pass the
path to masque() and it masks every table at once, aliasing shared keys
consistently so the synthetic tables still join.
If the table needs tidying first, clean_table() makes column names valid
and trims whitespace, and conform_table() merges near-duplicate labels
and sets column types, reporting each change.
detect_design() recognises environment columns, such as site or year, and
the design within each environment. In collaborate mode the environment
labels are aliased and every row stays in its environment. The clone does
not keep genotype-by-environment effects, so it is no substitute for the
real data in scientific inference.
masque is not a privacy-preserving or differential-privacy tool. It is a
structurally faithful development surrogate with explicit confidentiality
guardrails. Read
Confidentiality and the threat model
before using it.
What masque does
- Preserves enough structure for pipelines to run unchanged.
- Provides two explicit modes:
localfor owner-only realistic surrogates, andcollaboratefor controlled sharing with opaque aliasing, numeric jitter, and an automatic leakage audit. - Keeps treatment, block and environment means on request
(
conditional = TRUE). Treatment means on the clone then track those of the real data, and block and environment effects stay detectable. What a conditional clone keeps of the design tests this on eight field designs. - Records every translation (column names, factor levels) in a private
recipe. The recipe holds the real labels, the original column names and the seed, so together with the synthetic it undoes every alias. Keep it with the original data and never send it with the synthetic. - Audits its own output (
audit_mask()), raises HIGH findings as classed warnings the guided flow never silences, and refuses package-managed writes while a HIGH finding stands (an explicitallow_high = TRUEoverride is available, warned and recorded in the recipe).
What masque does not do
- It is not a universal anonymiser, and it does not provide differential-privacy guarantees.
- It does not make outputs safe for public release.
- It does not anonymise rare strata, small designs, or operational metadata (small site-by-year combinations, contact names, geolocations).
- It does not certify compliance with any privacy, health, banking, or research-governance obligation. It can contribute evidence to such a decision; the decision itself is organisational and legal.
- It does not rewrite arbitrary pipeline source code.
Bottom line. Generating a synthetic table is not a release decision.
In the Five Safes framework for controlled data access, masque
contributes to Safe Data and Safe Outputs;
Safe People, Safe Projects, and Safe Settings are governance questions no
package can answer. The collaborate workflow assumes only the synthetic
crosses the trust boundary.
- synthpop makes synthetic versions of confidential microdata for release, synthesising one variable at a time from conditional models, and measures their utility and disclosure risk.
- sdcMicro anonymises microdata for public- and scientific-use files and estimates disclosure risk.
Both produce data meant to be analysed in place of the original. masque
produces a development copy: analysts write code on it and the custodian
runs that code on the real data through the private recipe. It keeps the
experimental design (treatments, blocks, plots), and a conditional clone
(conditional = TRUE) also keeps the treatment means of the outcome.
Every column's role and action is checked against a fixed vocabulary
before anything is masked.
Articles, in reading order:
- Getting started with masque: the one-call path on a public fixture.
- Recipe anatomy and the round-trip: what a recipe holds and how a pipeline built on the synthetic runs on the original.
- Confidentiality and the threat model: what a clone protects, the two modes, and the depth controls.
- What a conditional clone keeps of the design: eight classic field designs tested against one pass rule.
The function reference documents every exported function. Also on the site: API stability policy, changelog, contributing guide and licence.
Bug reports and suggestions are welcome as GitHub issues. Read the contributing guide before opening a pull request.
citation("masque")The package also ships a CITATION.cff file.
MIT. See the licence.
