{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Privatizing Histograms\n", "\n", "Sometimes we want to release the counts of individual outcomes in a dataset.\n", "When plotted, this makes a histogram.\n", "\n", "The library currently has two approaches:\n", "\n", "1. Known category set `make_count_by_categories`\n", "2. Unknown category set `make_count_by`\n", "\n", "The next code block imports handles boilerplate: imports, data loading, plotting." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%[ -e data.csv ] || wget https://raw.githubusercontent.com/opendp/opendp/main/docs/source/data/PUMS_california_demographics_1000/data.csv" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "import opendp.prelude as dp\n", "dp.enable_features(\"contrib\", \"floating-point\")\n", "max_influence = 1\n", "budget = (1., 1e-8)\n", "\n", "# public information\n", "col_names = [\"age\", \"sex\", \"educ\", \"race\", \"income\", \"married\"]\n", "size = 1000\n", "\n", "with open('data.csv') as input_data:\n", " data = input_data.read()\n", "\n", "def plot_histogram(sensitive_counts, released_counts):\n", " \"\"\"Plot a histogram that compares true data against released data\"\"\"\n", " import matplotlib.pyplot as plt\n", " import matplotlib.ticker as ticker\n", "\n", " fig = plt.figure()\n", " ax = fig.add_axes([1,1,1,1])\n", " plt.ylim([0,225])\n", " tick_spacing = 1.\n", " ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))\n", " plt.xlim(0,15)\n", " width = .4\n", "\n", " ax.bar(list([x+width for x in range(0, len(sensitive_counts))]), sensitive_counts, width=width, label='True Value')\n", " ax.bar(list([x+2*width for x in range(0, len(released_counts))]), released_counts, width=width, label='DP Value')\n", " ax.legend()\n", " plt.title('Histogram of Education Level')\n", " plt.xlabel('Years of Education')\n", " plt.ylabel('Count')\n", " plt.show()" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "## Private histogram via `make_count_by_categories`\n", "\n", "This approach is only applicable if the set of potential values that the data may take on is public information.\n", "If this information is not available, then use `make_count_by` instead.\n", "It typically has greater utility than `make_count_by` until the size of the category set is greater than dataset size.\n", "In this data, we know that the category set is public information:\n", "strings consisting of the numbers between 1 and 20.\n", "\n", "The counting aggregator computes a vector of counts in the same order as the input categories.\n", "It also includes one extra count at the end of the vector,\n", "consisting of the number of elements that were not members of the category set.\n", "\n", "You'll notice that `make_base_discrete_laplace` has an additional argument that explicitly sets the type of the domain, `D`.\n", "It defaults to `AtomDomain[int]` which works in situations where the mechanism is noising a scalar.\n", "However, in this situation, we are noising a vector of scalars,\n", "and thus the appropriate domain is `VectorDomain[AtomDomain[int]]`." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Educational level counts:\n", " [33, 14, 38, 17, 24, 21, 31, 51, 201, 60, 165, 76, 178, 54, 24, 13, 0, 0, 0]\n", "DP Educational level counts:\n", " [34, 13, 38, 18, 24, 22, 31, 51, 201, 59, 166, 76, 178, 54, 24, 13, 0, 0, 3]\n", "DP estimate for the number of records that were not a member of the category set: 1\n" ] }, { "data": { "image/png": "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//rXbfwuNOSCbWZm7dLChQt56KGHuOiii5pdZ+7cuUyaNIkHH3yQmTNn0qVLFyZOnLjGerW1tdxwww0ATJ06lS222ILtttuOI488kkcffZRZs2YxdOhQrrzyyhbnd+WVV9KzZ08effRRHn30Ua644gqef/751h9oC7lL3MzM2qWjjz6aLl26rHWde+65h+nTp7PbbrsB8O6777LVVlutsd6xxx7LXnvtxYUXXtigO3zOnDl8//vf5/XXX+ett97iwAMPbHF+d911F7Nnz2by5MkALFu2jKeffrpNvsLVFBdsMzNrl3r06LH6edeuXVm1atXq1/VflYoITjzxxAbXp5sycOBABg8ezP3338+UKVN4+OGHgazr/dZbb2XEiBFcffXV3HfffWtsWxq79CtaEcEll1zSqiK/IdwlbmZm7V51dTUzZswAYMaMGau7nvfff38mT57MkiVLAHj11VdZsGBBk/uora3lG9/4BkOGDGHAgAEAvPnmm/Tr14/ly5c32ZVeH3v69OkAq8+mAQ488EAuu+wyli9fDsA///lP3n777TY42qa5YJuZWbt31FFH8eqrrzJs2DAuvfRStt9+ewB22mknzj33XA444AB23nlnPvOZz7Bo0aIm93H00UfzxBNPNLg7/Ec/+hF77LEHe++9NzvuuGOT251xxhlcdtll7LLLLrzyyiur27/0pS+x0047seuuuzJ8+HBOOeUUVqxY0YZH3VCu82HnzfNhm5ltuLlz5671O8m2YZp6f9vVfNhmZmbWdlywzczMCsAF28zMrABcsM3MzArABdvMzKwAXLDNzMwKwAXbzMwqrkuXLtTU1DBs2DBGjBjBhRdeuHp0sfvuu4+ePXtSU1PD0KFDOeecc9bYfsiQITz11FMN2k4//XTOP//8ZmNWV1c3+F51e+ehSc3MrKHxPdt4f8vWucomm2yyeorNJUuWcNxxx/HGG2+sLs777LMPt99+O2+//TY1NTUccsgh7Lrrrqu3HzNmDDfccAM/+MEPAFi1ahWTJ0/mwQcfbNtjqSCfYZuZWbuy1VZbMWHCBC699FIaD+7Vo0cPRo4cyTPPPNOgvba2lkmTJq1+/cADD7DNNtuwzTbbcPjhhzNy5EiGDRvGhAkT1og3f/58hg8fvvr1BRdcwPjx4wF49tlnGT16NCNHjmSfffZh3rx5bXikreOCbWZm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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# public information\n", "categories = list(map(str, range(1, 20)))\n", "\n", "histogram = (\n", " dp.t.make_split_dataframe(separator=\",\", col_names=col_names) >>\n", " dp.t.make_select_column(key=\"educ\", TOA=str) >>\n", " # Compute counts for each of the categories and null\n", " dp.t.then_count_by_categories(categories=categories)\n", ")\n", "\n", "noisy_histogram = dp.binary_search_chain(\n", " lambda s: histogram >> dp.m.then_laplace(scale=s),\n", " d_in=max_influence, d_out=budget[0])\n", "\n", "sensitive_counts = histogram(data)\n", "released_counts = noisy_histogram(data)\n", "\n", "print(\"Educational level counts:\\n\", sensitive_counts[:-1])\n", "print(\"DP Educational level counts:\\n\", released_counts[:-1])\n", "\n", "print(\"DP estimate for the number of records that were not a member of the category set:\", released_counts[-1])\n", "\n", "plot_histogram(sensitive_counts, released_counts)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "## Private histogram via `make_count_by` and `make_base_laplace_threshold`\\n\n", "This approach is applicable when the set of categories is unknown or very large.\n", "The `make_count_by` transformation computes a hashmap containing the count of each unique key,\n", "and `make_base_laplace_threshold` adds noise to the counts and censors counts less than some threshold.\\n\n", "\n", "On `make_base_laplace_threshold`, the noise scale parameter influences the epsilon parameter of the budget, \n", "and the threshold influences the delta parameter in the budget.\n", "Any category with a count sufficiently small is censored from the release.\n", "\n", "It is sometimes referred to as a \"stability histogram\" because it only releases counts for \"stable\" categories that exist in all datasets that are considered \"neighboring\" to your private dataset.\n", "\n", "I start out by defining a function that finds the tightest noise scale and threshold for which the stability histogram is `(d_in, d_out)`-close." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "def make_base_laplace_threshold_budget(\n", " preprocess: dp.Transformation,\n", " d_in, d_out\n", ") -> dp.Measurement:\n", " \"\"\"Make a stability histogram that respects a given d_in, d_out.\"\"\"\n", " def privatize(s, t=1e8):\n", " return preprocess >> dp.m.then_base_laplace_threshold(scale=s, threshold=t)\n", " \n", " s = dp.binary_search_param(lambda s: privatize(s=s), d_in, d_out)\n", " t = dp.binary_search_param(lambda t: privatize(s=s, t=t), d_in, d_out)\n", "\n", " return privatize(s=s, t=t)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "I now use the `make_base_laplace_threshold_budget` constructor to release a private histogram on the education data." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Educational level counts:\n", " [33, 14, 38, 17, 24, 21, 31, 51, 201, 60, 165, 76, 178, 54, 24, 13, 0, 0, 0, 0]\n", "DP Educational level counts:\n", " {'3': 39, '10': 60, '1': 32, '11': 160, '13': 178, '7': 31, '14': 56, '5': 23, '8': 51, '12': 77, '6': 23, '9': 201, '15': 24}\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAewAAAFdCAYAAADBvF6wAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/d3fzzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAqSklEQVR4nO3de5xVdb3/8ddbwFAwQERCLg6YF4RkFLykWZYnRUtNDWX0mHbsoJUdraww+xme7KSlVupJwzQ1SVFQM/WU5hEtFRMQEAXzBkcUAUfFu3H5/P5Y38E9wwzMwKy9Z828n4/Hfsze33X5fNYemM9e37X296uIwMzMzNq2zSqdgJmZmW2YC7aZmVkBuGCbmZkVgAu2mZlZAbhgm5mZFYALtpmZWQG4YFu7J+kJSQdUOo9KknSkpBckvSVp903c1wGSFrdWbi2I+31Jvyl33NYmqUpSSOpc6VysWFywrdAkLZT0Lw3aTpL0t7rXETEsIqZtYD/t/Y/ohcBpEdE9Ih5ruDAd+9upoNc9vluBPOvyWedDQUT8V0R8JYdY9f69mLVV7fWPk1mbIqlzRKyqYArbA09sYJ0REfFMOZIxs5bzGba1e6Vn4ZL2kjRD0huSlkq6OK32QPr5ejq7/LikzST9QNIiScskXSepR8l+v5SW1Ur6fw3iTJA0RdL1kt4ATkqxH5b0uqQlki6TtHnJ/kLS1yQ9LelNST+StIOkh1K+N5Wu3+AYG81V0ockvQV0AuZIenYj3r8tJF0j6TVJTwJ7Nlgekj5a8voaSeeVvD5C0ux0DM9KGp3avyxpfjrW5ySdktq7Af8DbFdytr9dek+vL9nv4elyx+uSpkkaWrJsoaQzJc2VtELSZEldN+LYd5F0j6RXJT0l6ZjUvreklyV1Kln3SElz0/PNJI1Px1ubfndbtzS+WSkXbOtofgn8MiI+DOwA3JTaP5l+9kzdxg8DJ6XHp4EhQHfgMgBJuwK/Ao4H+gE9gP4NYh0BTAF6ApOA1cA3gW2AjwMHAl9rsM3BwEhgH+C7wETgX4GBwHCgponjajTXiHg/IrqndUZExA5NvjNN+yHZe7VDyu/E5m4oaS/gOuA7ZO/DJ4GFafEy4PPAh4EvAz+XtEdEvA0cAryUfhfdI+KlBvvdCbgBOAPoA9wF/LHBB5pjgNHAYGA3sven2dIHh3uA3wPbAmOBX0naNSIeAd4GPlOyyXFpXYBvAF8APgVsB7wG/HdL4ps15IJt7cFt6SzrdUmvkxXSpqwEPippm4h4KyKmr2fd44GLI+K5iHgLOAsYq+w69xeBP0bE3yLin8A5QMOB+R+OiNsiYk1EvBsRMyNiekSsioiFwK/J/qCX+mlEvBERTwDzgLtT/BVkZ51N3TC2vlyba1bp+yjp4NR+DPDjiHg1Il4ALmnBPk8Gro6Ie9L78GJELACIiDsj4tnI3A/cDezfzP0eC9yZ9ruS7Br9FsC+JetcEhEvRcSrwB+B6hbkDdmHiYUR8dv0O3sMmAqMSctvIH2AkrQVcGhqAzgVODsiFkfE+8AE4Ist/H2Y1eOCbe3BFyKiZ92Ddc9aS50M7AQskPSopM+vZ93tgEUlrxeR3ffRNy17oW5BRLwD1DbY/oXSF5J2knRH6kp9A/gvsrPtUktLnr/byOvuNG59uTbXHqXvY0T8uWTfpceyqJFtmzIQaLQbXtIhkqan7ubXyQpew/ejKfWONyLWpBxLezleLnn+Dk2/d03ZHti7wYfB44GPpOW/B46S9CHgKGBWRCwq2fbWku3mk/WwtOT3YVaPC7Z1KBHxdETUkHVxXgBMSV2fjU1b9xLZH946g4BVZEV0CTCgboGkLYDeDcM1eH05sADYMXXJfx/Qxh9Ns3PdVEvICm/pvku9A2xZ8vojJc9fIOtKrycVualkZ8Z90wetu/jg/djQNIL1jleSUo4vbmC7lngBuL/Bh5juEfFVgIh4kuxDwyHU7w6v2/aQBtt2jYjWzM86GBds61Ak/aukPumM7PXUvAZYnn4OKVn9BuCbkgZL6k52Rjw53e09BThM0r7puukENlx8twLeAN6StAvw1VY6rA3luqluAs6S1EvSALLrs6VmA8dJ6pRuKCvt5r8K+LKkA9ONWP3TsW8OfIjsfV8l6RDgoJLtlgK9VXKTXyM5fS7ttwvwbeB94KGNPEZJ6lr6AO4AdpJ0gqQu6bFn6c1tZEX6dLJr8zeXtF8B/FjS9mnnfSQdsZG5mQEu2NbxjAaeUHbn9C+Bsen68jvAj4EHUzfmPsDVwO/I7iB/HniPVKzSNeZvADeSnYG+RXYT1fvriX0m2ZnYm8CVwORWPK4mc22BOar/PexfpPZzyc4knye7zvy7BtudDhxG9gHoeOC2ugUR8XfSDWXACuB+YPuIeBP4D7LC+xrZ+3J7yXYLyD6EPJd+H9uVBoyIp8huxrsUeCXFPyzdT7Ax9iW75NDwcRDZzWYvkXWxX0D2QaPODWQfUP43Il4paf9lOp67Jb0JTAf23sjczABQxIZ6nsxsQ9JZ7etk3d3PVzgdM2uHfIZttpEkHSZpy3QN/ELgcT74ypKZWavKrWBLGijpPklPpsENTk/tP5O0IA1ocKuknqm9StK7ygZYmC3pirxyM2slR5B1lb4E7EjWve4uKzPLRW5d4pL6Af0iYlb6juJMsoEEBpBd71kl6QKAiPiepCrgjogYnktCZmZmBZbbGXZELImIWen5m2TfQ+wfEXeX3Lk6nZKvxpiZmVnjynINO5097w480mDRv5GN3lRnsKTHJN0vqbkjHpmZmbV7uQ+Tl+6enQqcERFvlLSfTTaww6TUtAQYFBG1kkaSDTc5rHSbtN04YBxAt27dRu6yyy55H4KZmVmrmjlz5isR0acl2+T6ta40oMEdwJ8j4uKS9pOAU4AD0/dfG9t2GnBmRMxoav+jRo2KGTOaXGxmZtYmSZoZEaNask2ed4mLbJSj+Q2K9WiyWYgOLy3WaSSgTun5ELK7bp/LKz8zM7MiybNLfD/gBOBxSbNT2/fJZvr5EHBPVtOZHhGnkg3t95+SVpINEXlqmmXHzMysw8utYEfE32h8bOW7mlh/Ktm1bjMzM2vAc7OamXVwK1euZPHixbz33nuVTqXd6dq1KwMGDKBLly6bvC8XbDOzDm7x4sVstdVWVFVVkS5VWiuICGpra1m8eDGDBw/e5P15LHEzsw7uvffeo3fv3i7WrUwSvXv3brWeCxdsMzNzsc5Ja76vLthmZlZRtbW1VFdXU11dzUc+8hH69++/9vU//7mxU5x/4Nxzz+Wss86q1zZ79myGDh3a5DYTJkzgwgsv3OTYrcnXsM3MrJ6q8Xe26v4Wnv+59S7v3bs3s2fPBrJC2b17d84888y1y1etWkXnzhtfrmpqahg9ejQ/+clP1rbdeOON1NTUbPQ+K8Fn2GZm1uacdNJJnHrqqey9995897vfXeeMd/jw4SxcuBCA66+/nr322ovq6mpOOeUUVq9eXW9fO+20E7169eKRRz6YzuKmm26ipqaGK6+8kj333JMRI0Zw9NFH88476w6+ecABB1A3quYrr7xCVVUVAKtXr+Y73/kOe+65J7vtthu//vWvW/ldqM8F28zM2qTFixfz0EMPcfHFFze5zvz585k8eTIPPvggs2fPplOnTkyaNGmd9WpqarjxxhsBmD59OltvvTU77rgjRx11FI8++ihz5sxh6NChXHXVVc3O76qrrqJHjx48+uijPProo1x55ZU8//zzLT/QZnKXuJmZtUljxoyhU6dO613n3nvvZebMmey5554AvPvuu2y77bbrrHfsscey7777ctFFF9XrDp83bx4/+MEPeP3113nrrbc4+OCDm53f3Xffzdy5c5kyZQoAK1as4Omnn26Vr3A1xgXbzMzapG7duq193rlzZ9asWbP2dd1XpSKCE088sd716cYMHDiQwYMHc//99zN16lQefvhhIOt6v+222xgxYgTXXHMN06ZNW2fb0tilX9GKCC699NIWFflN4S5xMzNr86qqqpg1axYAs2bNWtv1fOCBBzJlyhSWLVsGwKuvvsqiRYsa3UdNTQ3f/OY3GTJkCAMGDADgzTffpF+/fqxcubLRrvS62DNnzgRYezYNcPDBB3P55ZezcuVKAP7xj3/w9ttvt8LRNs4F28zM2ryjjz6aV199lWHDhnHZZZex0047AbDrrrty3nnncdBBB7Hbbrvx2c9+liVLljS6jzFjxvDEE0/Uuzv8Rz/6EXvvvTf77bcfu+yyS6PbnXnmmVx++eXsvvvuvPLKK2vbv/KVr7Drrruyxx57MHz4cE455RRWrVrVikddX67zYefN82GbmW26+fPnr/c7ybZpGnt/29R82GZmZtZ6XLDNzMwKwAXbzMysAFywzczMCsAF28zMrABcsM3MzArABdvMzCquU6dOVFdXM2zYMEaMGMFFF120dnSxadOm0aNHD6qrqxk6dCjnnnvuOtsPGTKEp556ql7bGWecwQUXXNBkzKqqqnrfq27rPDSpmZnVN6FHK+9vxQZX2WKLLdZOsbls2TKOO+443njjjbXFef/99+eOO+7g7bffprq6msMOO4w99thj7fZjx47lxhtv5Ic//CEAa9asYcqUKTz44IOteywV5DNsMzNrU7bddlsmTpzIZZddRsPBvbp168bIkSN55pln6rXX1NQwefLkta8feOABtt9+e7bffnu+8IUvMHLkSIYNG8bEiRPXibdw4UKGDx++9vWFF17IhAkTAHj22WcZPXo0I0eOZP/992fBggWteKQt44JtZmZt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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "preprocess = (\n", " dp.t.make_split_dataframe(separator=\",\", col_names=col_names) >>\n", " dp.t.make_select_column(key=\"educ\", TOA=str) >>\n", " dp.t.then_count_by(MO=dp.L1Distance[float], TV=float)\n", ")\n", "\n", "noisy_histogram = make_base_laplace_threshold_budget(\n", " preprocess,\n", " d_in=max_influence, d_out=budget)\n", "\n", "sensitive_counts = histogram(data)\n", "released_counts = noisy_histogram(data)\n", "# postprocess to make the results easier to compare\n", "postprocessed_counts = {k: round(v) for k, v in released_counts.items()}\n", "\n", "print(\"Educational level counts:\\n\", sensitive_counts)\n", "print(\"DP Educational level counts:\\n\", postprocessed_counts)\n", "\n", "def as_array(data):\n", " return [data.get(k, 0) for k in categories]\n", "\n", "plot_histogram(sensitive_counts, as_array(released_counts))" ] } ], "metadata": { "interpreter": { "hash": "3220da548452ac41acb293d0d6efded0f046fab635503eb911c05f743e930f34" }, "kernelspec": { "display_name": "Python 3.8.13 ('psi')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.13" } }, "nbformat": 4, "nbformat_minor": 1 }