From f0cf725a08e75c6bb0f1e89fb7dcc285b806f5d3 Mon Sep 17 00:00:00 2001 From: Kulankhina Date: Wed, 23 Feb 2022 17:18:47 +0100 Subject: [PATCH 1/2] Add conference colab --- examples/conference.ipynb | 295 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 examples/conference.ipynb diff --git a/examples/conference.ipynb b/examples/conference.ipynb new file mode 100644 index 00000000..407f1df7 --- /dev/null +++ b/examples/conference.ipynb @@ -0,0 +1,295 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Conference example", + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "bW1gifIe0pUt" + }, + "source": [ + "\n", + " \n", + " \n", + "
\n", + " Run in Google Colab\n", + " \n", + " View source on GitHub\n", + "
" + ] + }, + { + "cell_type": "markdown", + "source": [ + "This is a simple example that shows how to calculate anonymized statistics using PipelineDP. The input data is a simulated dataset of an imaginary conference participants including their origin coutries. We use PipelineDP to calculate anonymized count of participants aggregated by country." + ], + "metadata": { + "id": "ddrCVxp53UjV" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zxcPpZGuAPq8" + }, + "source": [ + "# Install dependencies and download data\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "E8yzpKYNbHTF", + "cellView": "form" + }, + "outputs": [], + "source": [ + "#@markdown Install dependencies and download data\n", + "\n", + "import os\n", + "os.chdir('/content')\n", + "!pip install pipeline-dp apache_beam\n", + "\n", + "import sys\n", + "sys.path.insert(0,'/content/PipelineDP')\n", + "\n", + "from IPython.display import clear_output\n", + "clear_output()\n", + "\n", + "import apache_beam as beam\n", + "from apache_beam.runners.portability import fn_api_runner\n", + "from apache_beam.runners.interactive import interactive_runner\n", + "from apache_beam.runners.interactive.interactive_beam import *\n", + "from dataclasses import dataclass\n", + "import pipeline_dp\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oi-D38dUApM1" + }, + "source": [ + "# Construct and inspect the input data\n", + "\n", + "Below we construct the input dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "Mimkjqt9h9gr", + "cellView": "form" + }, + "outputs": [], + "source": [ + "#@markdown Construct the input data\n", + "input = [(f\"{u}\", \"Germany\") for u in range(50)]\n", + "input += [(f\"{u + 50}\", \"Switzerland\") for u in range(75)]\n", + "input += [(f\"{u + 125}\", \"France\") for u in range(30)]\n", + "input += [(f\"{u + 155}\", \"Italy\") for u in range(40)]\n", + "input += [(f\"{u + 195}\", \"UK\") for u in range(100)]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "e2SOjo8qiNnw" + }, + "source": [ + "The goal of this Colab is to demonstrate how to compute the count of participants aggregated by country in a DP manner.\n", + "\n", + "The plot below demonstrates the non-private result." + ] + }, + { + "cell_type": "code", + "source": [ + "#@title Non-private statistics\n", + "countries = [\"Germany\", \"Switzerland\", \"France\", \"Italy\", \"UK\"]\n", + "non_dp_count = [0] * len(countries)\n", + "for participant_info in input:\n", + " country = participant_info[1]\n", + " index = countries.index(country)\n", + " non_dp_count[index] = non_dp_count[index] + 1\n", + "\n", + "plt.bar(countries, non_dp_count)\n", + "plt.suptitle('Count of participants')\n", + "plt.show()\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 294 + }, + "id": "qR1dBaCiqNAa", + "outputId": "fe6e7953-cd5c-49b3-cf4e-6fe577bcc040", + "cellView": "form" + }, + "execution_count": 4, + "outputs": [ + { + "output_type": "display_data", + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + } + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Run DP pipeline\n", + "Below we compute the same statistics using differential privacy and PipelineDP." + ], + "metadata": { + "id": "IIjQrB3eFmvp" + } + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "eN9fu0NkSA6u", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "76a402a5-4ba0-459a-bc38-9b18ff97cca0" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[('Germany', MetricsTuple(privacy_id_count=51.11806528184752)), ('Switzerland', MetricsTuple(privacy_id_count=75.05021202241187)), ('France', MetricsTuple(privacy_id_count=28.699075757142054)), ('Italy', MetricsTuple(privacy_id_count=39.81641489278627)), ('UK', MetricsTuple(privacy_id_count=100.014823352647))]\n" + ] + } + ], + "source": [ + "#@title DP statistics\n", + "\n", + "# Choose the backed: local, Beam or Spark\n", + "backend = pipeline_dp.LocalBackend()\n", + "\n", + "# Define the total privacy loss that can be introduced by this pipeline\n", + "budget_accountant = pipeline_dp.NaiveBudgetAccountant(total_epsilon=1, total_delta=1e-6)\n", + "\n", + "# Create DPEngine\n", + "dp_engine = pipeline_dp.DPEngine(budget_accountant, backend)\n", + "\n", + "# Configure functions to extract partition key, privacy ID and aggregated value\n", + "# from the input data\n", + "data_extractors = pipeline_dp.DataExtractors(\n", + " partition_extractor=lambda row: row[1],\n", + " privacy_id_extractor=lambda row: row[0],\n", + " value_extractor=lambda row: 1)\n", + "\n", + "# Configure the aggregation parameters\n", + "params = pipeline_dp.AggregateParams(\n", + " noise_kind=pipeline_dp.NoiseKind.LAPLACE,\n", + " metrics=[pipeline_dp.Metrics.PRIVACY_ID_COUNT],\n", + " max_partitions_contributed=1,\n", + " max_contributions_per_partition=1,\n", + " min_value=0,\n", + " max_value=1)\n", + "\n", + "# Build computational graph for the aggregation\n", + "dp_result = dp_engine.aggregate(input, params, data_extractors)\n", + "\n", + "# Compute budget per each DP operation. \n", + "budget_accountant.compute_budgets()\n", + "\n", + "# Run computation.\n", + "dp_result = list(dp_result)\n", + "print(dp_result)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Inspect the result" + ], + "metadata": { + "id": "QsguG0DeF_8L" + } + }, + { + "cell_type": "code", + "source": [ + "#@markdown ##Inspect the result\n", + "#@markdown Below you can see the DP and non-DP results.\n", + "\n", + "dp_count = [0] * len(countries)\n", + "i = 0\n", + "for dp_count_per_country in dp_result:\n", + " dp_count[i] = dp_count_per_country[1][0]\n", + " i = i + 1\n", + "\n", + "x = np.arange(len(countries))\n", + "\n", + "width = 0.35\n", + "fig, ax = plt.subplots()\n", + "rects1 = ax.bar(x - width/2, non_dp_count, width, label='non-DP')\n", + "rects2 = ax.bar(x + width/2, dp_count, width, label='DP')\n", + "ax.set_title('Count participants per country')\n", + "ax.set_xticks(x)\n", + "ax.set_xticklabels(countries)\n", + "ax.legend()\n", + "fig.tight_layout()\n", + "plt.savefig(\"chart.png\")\n", + "plt.show()\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 297 + }, + "id": "sTkYZ0wSbo3h", + "outputId": "7d2701b4-1c9f-4232-8cc2-2c067c4526d9", + "cellView": "form" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "display_data", + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + } + } + ] + } + ] +} From 66047353e782628cff4fa34519e68940cc9cee97 Mon Sep 17 00:00:00 2001 From: Kulankhina Date: Thu, 24 Feb 2022 12:06:05 +0100 Subject: [PATCH 2/2] Fix imports and comments --- examples/conference.ipynb | 52 +++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/examples/conference.ipynb b/examples/conference.ipynb index 407f1df7..213b80df 100644 --- a/examples/conference.ipynb +++ b/examples/conference.ipynb @@ -55,31 +55,17 @@ "cell_type": "code", "execution_count": 1, "metadata": { - "id": "E8yzpKYNbHTF", - "cellView": "form" + "id": "E8yzpKYNbHTF" }, "outputs": [], "source": [ "#@markdown Install dependencies and download data\n", "\n", - "import os\n", - "os.chdir('/content')\n", "!pip install pipeline-dp apache_beam\n", "\n", - "import sys\n", - "sys.path.insert(0,'/content/PipelineDP')\n", - "\n", "from IPython.display import clear_output\n", "clear_output()\n", - "\n", - "import apache_beam as beam\n", - "from apache_beam.runners.portability import fn_api_runner\n", - "from apache_beam.runners.interactive import interactive_runner\n", - "from apache_beam.runners.interactive.interactive_beam import *\n", - "from dataclasses import dataclass\n", "import pipeline_dp\n", - "\n", - "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] @@ -105,6 +91,9 @@ "outputs": [], "source": [ "#@markdown Construct the input data\n", + "# The format of the input is: (participant_id, country).\n", + "# Participants u_0...u_49 come from Germany, participants u_50...u_149 come from\n", + "# Switzerland, etc.\n", "input = [(f\"{u}\", \"Germany\") for u in range(50)]\n", "input += [(f\"{u + 50}\", \"Switzerland\") for u in range(75)]\n", "input += [(f\"{u + 125}\", \"France\") for u in range(30)]\n", @@ -144,10 +133,10 @@ "height": 294 }, "id": "qR1dBaCiqNAa", - "outputId": "fe6e7953-cd5c-49b3-cf4e-6fe577bcc040", + "outputId": "9ccdf49d-a9f9-4fce-d7c7-6fc3d66f2fda", "cellView": "form" }, - "execution_count": 4, + "execution_count": 3, "outputs": [ { "output_type": "display_data", @@ -175,27 +164,27 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": { "id": "eN9fu0NkSA6u", "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "76a402a5-4ba0-459a-bc38-9b18ff97cca0" + "outputId": "15bf4d5c-6a2e-48a0-8830-81c1a5ecbab4" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ - "[('Germany', MetricsTuple(privacy_id_count=51.11806528184752)), ('Switzerland', MetricsTuple(privacy_id_count=75.05021202241187)), ('France', MetricsTuple(privacy_id_count=28.699075757142054)), ('Italy', MetricsTuple(privacy_id_count=39.81641489278627)), ('UK', MetricsTuple(privacy_id_count=100.014823352647))]\n" + "[('Germany', MetricsTuple(privacy_id_count=49.10272994384104)), ('Switzerland', MetricsTuple(privacy_id_count=75.26271629976691)), ('France', MetricsTuple(privacy_id_count=32.206397102141636)), ('Italy', MetricsTuple(privacy_id_count=37.134226348807715)), ('UK', MetricsTuple(privacy_id_count=97.95130274764233))]\n" ] } ], "source": [ "#@title DP statistics\n", "\n", - "# Choose the backed: local, Beam or Spark\n", + "# Choose the backend: local, Beam or Spark\n", "backend = pipeline_dp.LocalBackend()\n", "\n", "# Define the total privacy loss that can be introduced by this pipeline\n", @@ -220,13 +209,18 @@ " min_value=0,\n", " max_value=1)\n", "\n", - "# Build computational graph for the aggregation\n", + "# Create a computational graph for the aggregation.\n", + "# All computations are lazy. dp_result is iterable, but iterating it would\n", + "# fail until budget is computed (below).\n", + "# It’s possible to call DPEngine.aggregate multiple times with different\n", + "# metrics to compute.\n", "dp_result = dp_engine.aggregate(input, params, data_extractors)\n", "\n", "# Compute budget per each DP operation. \n", "budget_accountant.compute_budgets()\n", "\n", - "# Run computation.\n", + "# Here's where the lazy iterator initiates computations and gets transformed\n", + "# into actual results\n", "dp_result = list(dp_result)\n", "print(dp_result)" ] @@ -247,10 +241,9 @@ "#@markdown Below you can see the DP and non-DP results.\n", "\n", "dp_count = [0] * len(countries)\n", - "i = 0\n", - "for dp_count_per_country in dp_result:\n", + "for i, dp_count_per_country in enumerate(dp_result):\n", " dp_count[i] = dp_count_per_country[1][0]\n", - " i = i + 1\n", + "\n", "\n", "x = np.arange(len(countries))\n", "\n", @@ -272,15 +265,14 @@ "height": 297 }, "id": "sTkYZ0wSbo3h", - "outputId": "7d2701b4-1c9f-4232-8cc2-2c067c4526d9", - "cellView": "form" + "outputId": "82d59080-d00b-4c00-ff90-dde4838541d6" }, - "execution_count": 6, + "execution_count": 5, "outputs": [ { "output_type": "display_data", "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ]