Skip to contents

Takes one data frame and a user-edited roles table (from propose_roles(), possibly adjusted with set_role()) and produces a synthetic clone according to each column's action. Returns a masque S7 object holding the synthetic data and a private masque_recipe.

Usage

mask(
  df,
  roles,
  mode = c("local", "collaborate"),
  seed = NULL,
  clean = c("auto", "report", "off"),
  alias_names = FALSE,
  conditional = FALSE,
  coords = NULL,
  allow_unmasked_coords = FALSE,
  .shared_maps = list(),
  ...
)

Arguments

df

A data frame.

roles

A roles table from propose_roles() (possibly edited). Tables from masque <= 0.5.0 are upgraded with a deprecation warning; see roles_validate().

mode

Either "local" or "collaborate". When omitted, inherit attr(roles, "mode"), falling back to "local" for a roles table with no mode provenance. An explicit collaborate-to-local downgrade raises a classed masque_mode_downgrade warning.

seed

Optional integer for reproducibility.

clean

Label and column-name hygiene before masking, passed to clean_table(): one of "auto" (default - trim whitespace and report near-duplicate labels), "report" (report only), or "off" (skip). Invalid column names are legalised in every mode – an invalid name silently rewritten during synthesis corrupts the clone – and the repair is raised as a masque_name_repaired warning. The roles table's column references are remapped to the legalised names, the fixes are recorded in the recipe, and apply_recipe() / unmask() reverse them on the round-trip.

alias_names

Hide the column names themselves. FALSE (the default) keeps them. TRUE replaces every retained column name with an opaque alias (col_001, col_002, ... in column order). A character vector names just the columns to alias. The original-to-alias map is stored in the recipe and inverted by apply_recipe() / unmask(), so a pipeline written against the aliased synthetic round-trips. Column names are the last identifying surface a kept or design column exposes; alias them when even the schema is sensitive.

conditional

Logical scalar (default FALSE). The collaborate-grade conditional clone. When FALSE, scrambled numeric columns are re-simulated from one global Gaussian copula - marginals and global covariance survive, but the treatment-to-outcome relationship does not, so a causal model fitted on the clone recovers a null effect. When TRUE, the numeric block is re-simulated within each treatment-by-design stratum, so a row's synthetic outcome inherits the location of the treatment that row carries. A causal model fitted on the conditional clone recovers the real treatment effect within sampling tolerance - the data-side analogue of preserving a conditional mean embedding rather than a pooled marginal. The conditioning columns (treatment plus retained design) are recorded on the recipe.

The stratum is chosen by a coarsening ladder. Treatment crossed with every retained design column is the finest rung, but on a replicated factorial that rung holds one row per cell, which is too thin to synthesise. The ladder then drops design columns, finest first, until the cells hold at least five rows; treatment columns are never dropped. Whatever remains below that floor is pooled into a global fallback. The rung reached is recorded on the recipe as conditioning_used, the pooled share as fallback_frac, and any coarsening or residual pooling raises a classed masque_conditional_degraded warning – including the case where no treatment or design column survives at all, in which case the clone is the pooled copula.

coords

Optional geographic-coordinate declaration. Supply one or more latitude/longitude pairs and each is coarsened in place by an on-land jitter (see jitter_coordinates()) instead of being copula-scrambled into implausible locations. A pair is a named vector c(lat = "lat_col", lon = "lon_col") or a named list that also carries jitter parameters (by, method, min_km, max_km, sd_km, on_land); pass several pairs as a list. Defaults to a donut of 5-20 km on land. One displacement is drawn per site and broadcast to that site's rows: by names the columns of df that identify a site, and is omitted when rows sharing an identical input coordinate already identify one. A declared pair always survives masking, coarsened; the recipe records the parameters and the site grouping it was coarsened under, and apply_recipe() retargets to the real coordinates.

allow_unmasked_coords

Single logical. A masked table must not carry a real coordinate, so by default mask() stops when a column whose name says coordinate (gps, lat, lon, easting, ...) would be written through unmasked, and warns when a column detected only by the shape of its values would be. State otherwise by declaring the pair to coords (coarsened), giving the column a masking action (drop or scramble), or – having decided the coordinate is not sensitive – setting this to TRUE, which is recorded on the recipe.

.shared_maps

Internal. A named list of pre-computed original -> alias level maps for cross-table linked columns, set by mask_set(). Not for direct use.

...

Must be empty. An unused argument (for example a misspelled name) errors rather than being silently ignored.

Value

A masque S7 object. Use synthetic() and recipe() to extract the components.

Details

mode = "local" marks the synthetic for owner development only; the reminder is recorded on the recipe and shown when the object prints. mode = "collaborate" additionally jitters re-simulated numerics within their measurement resolution (stochastically rounding integers) and runs audit_mask() automatically; a HIGH finding is raised as a classed warning (masque_high_leakage) and blocks the package-managed writers (masque()'s out, write_set()) until it is resolved or explicitly overridden. Which columns are aliased, kept, or dropped is decided by the action column of roles - propose_roles() resolves mode-appropriate defaults, so the table you reviewed is the plan that runs.

Collaborate mode adjusts the transformations and runs the audit; it does not model where the output will go. Whether a synthetic table is appropriate for a given collaborator, environment, or jurisdiction is a release decision that stays with the data custodian - masque informs that decision, it does not make it.

Behaviour by action

keep

Byte-identical pass-through, both modes.

scramble

Numeric outcome / covariate columns are re-simulated jointly via a Gaussian copula on the global Pearson covariance, with empirical-quantile marginals. Categorical, date, and text columns are row-permuted within non-NA positions, class preserved. Treatment columns get a seeded label permutation - the assignment structure never moves.

alias

As scramble where applicable, plus opaque label substitution: treatments become trt_NNN (<col>_trt_NNN when two or more treatment factors are aliased), categorical covariates <col>_LNNN, design labels <col>_DNNN (in place - structure intact), ids <col>_INNN (in place - row linkage intact), text values <col>_TNNN.

drop

Column excluded from the synthetic, both modes.

The NA mask of every retained column is preserved cell-by-cell. RNG state is preserved across the call.

Examples

r <- propose_roles(iris)
r <- set_role(r, "Sepal.Length", role = "outcome")
m <- mask(iris, r, seed = 1)
head(synthetic(m))
#> # A tibble: 6 × 5
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#>          <dbl>       <dbl>        <dbl>       <dbl> <fct>  
#> 1          5.1         3.2          4           1.5 setosa 
#> 2          6           3            3.7         0.4 setosa 
#> 3          5           3            4.6         1.1 setosa 
#> 4          7.2         2.6          5.8         1.7 setosa 
#> 5          6.1         2.4          5.8         1.5 setosa 
#> 6          5           2.7          4.5         1.4 setosa