Skip to content

Mean Estimation

Problem Formulation

Given a dataset of \(n\) samples \(X \in \mathbb{R}^{n \times d}\), estimate the mean vector \(\mu \in \mathbb{R}^d\). The non-private estimator is the empirical mean:

\[\hat{\mu} = \frac{1}{n} \sum_{i=1}^{n} X_i\]

Under differential privacy we want a release \(\tilde{\mu}\) that satisfies \((\varepsilon, \delta)\)-DP (or a pure-DP / zCDP variant) while staying close to \(\hat{\mu}\) or to the ground-truth mean \(\mu^*\). Most DP algorithms require a bounded domain (see metadata): adding or removing one sample then moves the empirical mean by a bounded amount, which calibrates the noise.

API Reference

Types, algorithms (with their privacy arguments + hyperparameter defaults), instance generators, and metrics are documented from the source docstrings on the Mean Estimation API Reference page.

Inherited Algorithms

Mean estimation is a child of the M-Estimation task, so all M-estimation algorithms (e.g. DPGradientDescent, EmpiricalRiskMinimization, GradientDescent, StochasticGradientDescent) are available via task inheritance — the squared-loss M-estimation objective recovers the mean. See the M-Estimation task page.

Usage Example

from dp_testing_platform import ApproxDPBudget
from dp_testing_platform.tasks.mean_estimation import MeanEstimationTask
from dp_testing_platform.tasks.mean_estimation.algorithms import (
    SampleMean,
    GaussianMechanismMeanEstimation,
)
from dp_testing_platform.core import BoxDomain
import numpy as np

# Create synthetic data inside a bounded box
np.random.seed(0)
n, d = 1000, 5
mu_true = np.ones(d)
X = np.clip(mu_true + np.random.randn(n, d), -5.0, 5.0)
domain = BoxDomain(np.tile([-5.0, 5.0], (d, 1)))

metadata = MeanEstimationTask.Metadata(dim=d, n_samples=n, domain=domain)
input_data = MeanEstimationTask.Input(X=X)

# Non-private baseline
baseline = SampleMean()
budget = ApproxDPBudget(1.0, 1e-5)
base_out = baseline.run(metadata, input_data, budget, seed=0)

# DP Gaussian mechanism
gm = GaussianMechanismMeanEstimation()
dp_out = gm.run(metadata, input_data, budget, seed=0)

print(f"Baseline error: {np.linalg.norm(base_out.mean_est - mu_true):.4f}")
print(f"DP error:       {np.linalg.norm(dp_out.mean_est - mu_true):.4f}")