This repository implements function privatization under geo-privacy metrics, and conducts empirical experiments on synthetic Gaussian curves, CRAWDAD cab mobility dataset, PTB-XL ECG dataset. The implementation covers all mechanisms mentioned in the paper, including
Dependencies. We recommend Python 3.9+ (our experiments are done under Python 3.9). Core functionality requires NumPy (≥ 1.21.0) for basic computations, SciPy (≥ 1.7.0) for numerical integration, wfdb (≥ 4.0.0) for processing ECG data, CVXPY (≥ 1.7.3) for solving QPs, and pathos (≥ 0.3.4) for multiprocessing. Auxiliary functionality requires Matplotlib, pandas, and tqdm. Our experiment environment is detailed in requirements.txt.
Downloading Datasets. Please download the CRAWDAD cab mobility dataset and decompress everything into cabspottingdata/. For the PTB-XL ECG dataset, please download the records100/00000/ directory of the dataset into ptb-xl/records100/00000/, and it is recommended to be done via AWS CLI.
tar -xvzf cabspottingdata.tar.gz cabspottingdata/
aws s3 sync --no-sign-request s3://physionet-open/ptb-xl/1.0.3/records100/00000/ ptb-xl/records100/00000/
Running the Full Experiment. A shell script expt.sh is provided to run all experiments. The whole process normally takes 10 to 16 hours. Upon completion, the results will be stored in corresponding folders under results/. The numerical summaries will be generated under sub-folders, and the figures will be plotted under results/figs/.
Our Experiment Results. The results we used in our paper are uploaded to this repository under results/. This includes the raw output (archived as Zip files) and the figures generated (in corresponding folders under results/figs/). A shell script plot_archived_results.sh is provided to extract archives and plot figures according to our raw results.
This core functionality is implemented in PrivPwcApprox.py, where the class
A solver can be created with solver = PrivatePiecewiseApprox(interval, breakpoints, basis_type, degree, parallel), where the Boolean parameter
-
$\texttt{Polynomial}$ : polynomial basis, with degree specified in$\texttt{degree}$ . When degree is at most 2, the basis generated is orthonormal. -
$\texttt{Linear-2D}$ : 2D linear basis equivalent to$\phi_1(t)=(1,0)$ ,$\phi_2(t)=(t,0)$ ,$\phi_3(t)=(0,1)$ , and$\phi_4(t)=(0,t)$ ; converted into orthonormal basis by default. -
$\texttt{Fourier}$ : partial Fourier basis$\phi_0(x)=1$ and$\phi_k(x)=\sin(2k\pi x),\phi_k'(x)=\cos(2k\pi x)$ for$k=1,2,\cdots,\texttt{degree}$ . -
$\texttt{Sinc}$ : bounded sinc function$\phi_k(x)=\sin(\pi(x-k))/(\pi(x-k))$ for$k=1,2,\cdots,\texttt{degree}$ , where the degree is also known as the shift; note that it has no value (0) outside$\texttt{interval}$ . -
$\texttt{Sinc-unbounded}$ : unbounded sinc function similar to above, but has value everywhere on$\mathbb{R}$ ; must be orthonormal.
The
A least-squares functional approximation of a function solver.fit(func). For 2D function, to speed-up computation, we may convert solver.fit(func, func_2D). An additional solver.createApprox().
To privatize the approximation, call solver.privatize(eps, method), where the mechanisms supported are solver.createPriv().
The solver.eval(type). type = 'Approx' returns type = 'Priv' returns solver.evalPrivLoss() measures
To guarantee continuity of privatized curve, call solver.smooth(method). Here the solver.eval('Priv') or solver.evalPrivLoss() after calling the
We added efficient integration for scipy.integrate.quad, and enabling multiprocessing is recommended.
The adaptive basis selection mechanism AdaptBasis.py. To apply it on a function adaptive_basis(func, interval, basis, eps, method), which returns a
AdaptApprox.py implements the adaptive segmentation mechanism adaptive_approx(func, interval, basis, degree, eps, beta, method), which returns a solver.privatize(eps = B, method) immediately afterwards to privatize with privacy budget
For both adaptive mechanisms, the detailed runtime decisions of SVTs are recorded in info.log during execution.
The experiment on synthetic Gaussian curves is implmented in Synthetic.py and SyntheticAdapt.py. Both script will randomly generate the same 50 synthetic Gaussian curves with seed 42, where each curve is a linear combination of 1 to 5 random Gaussian curves on interval Synthetic.py applies SyntheticAdapt.py adopts
The taxi trajectory dataset is located under cabspottingdata/. There are 536 trajectories in the dataset, each with the mobility information of a specific taxi during a time period of 20 to 40 days.
PreprocCabData.py preprocesses the data by converting latitude and longitude into coordinates (with meter as unit) and removing erroneous datapoints. SelectCabData.py truncates the curves by the 12-hour time window "8:00 ~ 20:00 HKT, 18 May, 2008", and filters out those with less than 500 samples. There will be 304 curves left, and each curve is considered as a 2D time series.
TaxiTrajectory.py privatizes the selected curves with 2D linear basis, and record the TaxiTrajectory.py without arguments will execute in interactive mode, where one example curve of 100 points is privatized under GP with results/TaxiTrajectory/taxi_{eps}/ directory.
python PreprocCabData.py
python SelectCabData.py
python TaxiTrajectory.py Laplace 0.01 1 > results/taxi_cmd.log
The ECG dataset is located under ptb-xl/. Since we will only use the first 100 records of 100 Hz frequency, we only need the records under ptb-xl/records100/00000/ directory. The records are scaled to the unit of microvolt (μv). Here we use public info of average QRS interval length and scale the time by a factor of 80. Each ECG record consists of 1000 data points and spans 10 seconds (thus 800 seconds after scaling).
ECG.py loads the records and privatizes them with bounded/unbounded sinc basis. For bounded sinc basis, the time range is split into ECG.py will execute in interactive mode with results/ECG/ECG_{eps}_{basis}/ directory.
python ECG.py Laplace 1.0 20 > results/ECG_cmd.log
python ECG.py Laplace 1.0 -1 > results/ECG_unbounded_cmd.log
The baseline methods for synthetic Gaussian curves are directly included in Synthetic.py and SyntheticAdapt.py. The number of samples used is
Baseline methods for CRAWDAD dataset and PTB-XL dataset are implemented in Baseline.py. It accepts three arguments:
ExptFigs.py plots the line graphs of CRAWDAD dataset and PTB-XL dataset. It includes both ExptFigs_quant.py plots the median along with lower (25%) and upper (75%) quantiles.
The shell script expt.sh runs all experiments with our algorithm and baseline methods, generate result statistics, and plot line graphs for comparisons.