Generation
This guide explains how to generate privacy-preserving synthetic data, covering both the streamlined
AIMGenerator interface and the lower-level calibration function.
How Marginal-Based Generation Works
Main Generation Algorithm
This library uses the AIM (Adaptive and Iterative Mechanism)[1] algorithm for privacy-preserving synthetic data generation. AIM belongs to the Select-Measure-Generate family of algorithms, which work in three steps:
Select which statistics of the original data to preserve.
Measure those statistics with calibrated noise added—this is how we get the privacy guarantees using differential privacy.
Generate synthetic data that matches the noisy statistics.
The statistics that AIM preserves are called marginals. A marginal is a frequency table over a subset of columns. For example, suppose a dataset has columns for city, income bracket, and age group:
A 1-way marginal of “city” counts how many people live in each city.
A 2-way marginal of (“city”, “income bracket”) counts how many people in each city fall into each income bracket—capturing the relationship between city and income.
A 3-way marginal of (“city”, “income bracket”, “age group”) captures the three-way interaction—for example, that high-income young people concentrate in certain cities.
The number of columns in a marginal is its degree. Higher-degree marginals capture more complex relationships, but there are exponentially more of them. AIM adaptively selects which marginals to measure, focusing the privacy budget on the marginals that matter most for the data distribution.
Pre-Processing
To provide end-to-end privacy guarantees, we need to ensure there is no leakage privacy in the entire synthetic data generation pipeline, and that includes pre-processing. The AIM algorithm expects to take as input the following data domain information:
Bounds. The minimum and maximum values of numeric features
Binning. Marginals are inherently discrete, thus we have to discretize numeric features by clustering the domain
Both of these pre-processing procedures can come with privacy leakage, as in the worst-case adversaries could learn information about outliers with extreme values of their features. Unless the bounds and bins are specified from domain knowledge, we need to allocate a part of the privacy budget, i.e., a part of all of the randomness used to ensure the target level of risk, to pre-processing.
AIMGenerator
Parameters
risk
The Risk specification defining the privacy guarantee. See the
Risk Modeling guide for how to choose this.
degree (default: 2)
The maximum degree of marginals that AIM will try to preserve. This is the most important parameter for controlling the utility-privacy trade-off:
degree=1: Only preserves individual column distributions. Each column’s frequencies will be close to the original, but correlations between columns (e.g., “older people tend to have higher incomes”) will not be captured. Very private, since few statistics need measuring—but the synthetic data may be misleading for any analysis that depends on relationships between columns.degree=2(default): Preserves pairwise relationships between columns. Captures correlations like “city and income are related” or “age and health status are correlated.” A good starting point for most datasets.degree=3: Preserves three-way interactions. Captures patterns like “the relationship between income and health status differs by city.” Better for datasets where multi-column dependencies matter, but requires more privacy budget since there are many more three-way marginals to measure.
The trade-off: Increasing degree captures more complex patterns but spreads the privacy budget across more marginals, adding more noise to each one. For a given privacy budget, there is a sweet spot: going too high can hurt utility because of the added noise.
max_model_size (default: 80)
Controls the maximum size (in MB) of the internal graphical model that AIM builds. A larger value enables AIM to include more marginals in the model, potentially improving fidelity. The default of 80 works well in most cases. Increasing this value may improve utility for datasets with many columns but will increase computation time and memory usage.
compress (default: True)
Enables compression in AIM, which reduces the number of marginals that need to be measured by combining related ones. This generally improves utility for a given privacy budget and should be left enabled unless you have a specific reason to disable it.
proc_epsilon (default: 0.1)
Controls the amount of randomness via the classical epsilon parameter in differential privacy that is allocated to pre-processing procedures: estimation of domain bounds and clustering of numeric features. It is highly recommended to at least provide domain bounds whenever possible, as detailed next.
Domain Specification
The domain parameter in fit() tells the generator the range of possible values for each column:
domain = {
# Numeric columns: specify lower and upper bounds
"age": {"lower": 18, "upper": 100},
"income": {"lower": 0, "upper": 500000},
# Categorical columns: list all possible values (inferred from data if omitted)
"city": ["NYC", "LA", "SF", "Chicago"],
}
For numeric columns, providing bounds avoids private preprocessing and preserves more privacy budget for generation. For categorical columns, the domain is inferred from the data if not specified.
Full Example
import pandas as pd
from risksyn import Risk, AIMGenerator
df = pd.DataFrame({
"age": [25, 30, 35, 40, 45],
"income": [50000, 60000, 70000, 80000, 90000],
"city": ["NYC", "LA", "NYC", "SF", "LA"],
})
domain = {
"age": {"lower": 18, "upper": 100},
"income": {"lower": 0, "upper": 500000},
}
risk = Risk.from_advantage(0.2)
gen = AIMGenerator(risk=risk, degree=3, max_model_size=80)
gen.fit(df, domain=domain)
synthetic_df = gen.generate(count=1000)
Saving and Loading
Fitted generators can be saved to disk and loaded later:
# Save
gen.store("my_generator")
# Load and generate
loaded = AIMGenerator.load("my_generator")
synthetic_df = loaded.generate(count=1000)
Using Calibration Utilities with dpmm
For users who need direct control over the dpmm
pipeline—for example, to use a different pipeline type, customize the generation process, or
integrate into an existing workflow—calibrate_parameters_to_risk converts a Risk specification
into the
(epsilon, delta) parameters that dpmm expects. Importantly, these (epsilon, delta) values
are not supposed to be used for interpretation of the privacy guarantees—the risk level is
input to the calibration procedure—but rather an intermediate technical crutch to set the
noise levels in the backend.
Without Private Preprocessing
When you provide complete domain bounds for all numeric columns, no private preprocessing is needed. The full privacy budget goes to generation:
from risksyn import Risk, calibrate_parameters_to_risk
from dpmm.pipelines import AIMPipeline
risk = Risk.from_advantage(0.2)
params = calibrate_parameters_to_risk(risk)
pipeline = AIMPipeline(
epsilon=params["epsilon"],
delta=params["delta"],
gen_kwargs={"degree": 3},
)
pipeline.fit(df, domain)
synthetic_df = pipeline.generate(n_records=1000)
With Private Preprocessing
When numeric columns lack explicit bounds, dpmm can estimate them privately. You must reserve part of
the privacy budget for this by passing proc_epsilon:
params = calibrate_parameters_to_risk(risk, proc_epsilon=0.1)
pipeline = AIMPipeline(
epsilon=params["epsilon"],
delta=params["delta"],
proc_epsilon=params["proc_epsilon"],
gen_kwargs={"degree": 3},
)
pipeline.fit(df) # bounds estimated privately
synthetic_df = pipeline.generate(n_records=1000)
Preprocessing Responsibility
When using AIMGenerator, preprocessing is handled automatically—it detects whether numeric
columns need private domain estimation and allocates the budget accordingly.
When using the calibration utilities directly, you are responsible for getting this right. The
proc_epsilon values passed to calibrate_parameters_to_risk and to AIMPipeline must be
consistent. The calibration function deducts the preprocessing budget from the total privacy budget
before computing the generation parameters. If dpmm performs private preprocessing without the budget
being accounted for in the calibration step, the overall privacy guarantee may not hold at the
specified risk level.