{
  "source_file": "0930",
  "source_platform": "Dev.to",
  "author": "Bala Priya C",
  "title_listed": "PyDP: A Python Differential Privacy Library",
  "keywords": "",
  "domain": "机器学习",
  "content_type": "深度技术解析",
  "is_paid_flag": "否",
  "url": "https://dev.to/balapriya/pydp-a-python-differential-privacy-library-34ln",
  "publish_date": "2021-12-27",
  "corpus_stage": "",
  "notes": "",
  "id": "296fd1695a46",
  "collected_at": "2026-10-02T14:01:20",
  "title": "PyDP: A Python Differential Privacy Library - DEV Community",
  "body_markdown": "Outline\n1️⃣\nWhat does Differential Privacy try to address?\n2️⃣\nWhy doesn't anonymization suffice?\n3️⃣\nPyDP example walkthrough\nWhat does Differential Privacy try to address?\nDifferential privacy aims at addressing the paradox of\nlearning nothing about an individual while learning useful information about a population\n. In essence, it describes the following promise, made by a data holder, or curator, to a data subject:\n“You will not be affected, adversely or otherwise, by allowing your data to be used in any study or analysis, no matter what other studies, data sets, or information sources, are available.” – Cynthia Dwork in\nThe Algorithmic Foundations of Differential Privacy\n.\nDifferential Privacy ensures that\nany\nsequence of outputs, which are responses to queries is ‘\nessentially\n’ equally likely to occur, independent of the presence or absence of any individual’s record.\nConsider the illustration below, where the two databases\nDatabase#1\nand\nDatabase#2\ndiffer by only one record, say, your data. If the results obtained from querying the database under these two different settings, are almost the same or similarly distributed, then they essentially are indistinguishable to an adversary.\nIllustration of Differentially Private Database Mechanism (\nImage Source\n)\nMathematically,\nP\nr\n[\nM\n(\nd\n)\n∈\nS\n]\n≤\ne\nx\np\n(\nϵ\n)\nP\nr\n[\nM\n(\nd\n′\n)\n∈\nS\n]\nPr[M(d)∈S]≤exp(ϵ)Pr[M(d′)∈S]\nP\nr\n[\nM\n(\nd\n)\n∈\nS\n]\n≤\ne\nx\np\n(\nϵ\n)\nP\nr\n[\nM\n(\nd\n′\n)\n∈\nS\n]\nwhere,\nd\nand\nd’\nare two subsets of data that differ by a single training example.\nM(d)\nis the output of the training algorithm for the training subset\nd\nand\nM(d’)\nis the output of the training algorithm for the training subset\nd’\n.\nThe probabilities that these outputs belong to a specific set\nS\nunder both these conditions should be arbitrarily close. The above equation should hold for all subsets\nd\nand\nd’\n.\nSmaller the value of Ɛ, stronger the privacy guarantees.\nMembership Inference Attack (MIA)\nattempts at determining the presence of a record in a machine learning model’s training data by querying the model. From the discussion above, as the inclusion or exclusion of an individual’s data record cannot be inferred, differential privacy ensures protection against such attacks.\nDifferentially private database mechanisms can therefore, make confidential data widely available for accurate data analysis.\nWhy doesn't anonymization suffice?\nThe Netflix Prize was an open competition for the best\ncollaborative filtering algorithm\nfor movie recommendations.\nThe dataset released was anonymized, without the users or the films being identified except by numbers assigned for the contest. Such anonymized movie records were published by Netflix as training data for the competition.\nHowever, there were several users who could be identified by linkage with the Internet Movie Database (IMDb) which was non-anonymized and publicly available.\nResearchers Arvind Narayanan and Vitaly Shmatikov, at the University of Texas at Austin present their studies in their work\nRobust De-anonymization of Large Datasets (How to Break Anonymity of the Netflix Prize Dataset)\n.\nTherefore, such\nlinkage attacks\ncan be used to match\n“anonymized”\nrecords with non-anonymized records in a different dataset.\nDifferential privacy aims at neutralizing such linkage attacks.\nAs Differential Privacy is a property of the data access mechanism, it is unrelated to the presence or absence of auxiliary information available to the adversary.\nTherefore, access to the IMDb would no longer permit a linkage attack to someone whose history is in the Netflix training set than to someone not in the training set.\nDe-anonymization of users in the Netflix Prize contest (Image Credit: Arvind Narayanan)\nPyDP Example Walkthrough\nPyDP is OpenMined’s Python wrapper for Google’s Differential Privacy project. The library provides a set of ε-differentially private algorithms, which can be used to produce aggregate statistics over numeric datasets containing private or potentially sensitive information.\nInstalling PyDP\n!\npip\ninstall\npython\n-\ndp\n# installing PyDP\nEnter fullscreen mode\nExit fullscreen mode\nNecessary Imports\nimport\npydp\nas\ndp\n# by convention our package is to be imported as dp (dp for Differential Privacy!)\nfrom\npydp.algorithms.laplacian\nimport\nBoundedSum\n,\nBoundedMean\n,\nCount\n,\nMax\nimport\npandas\nas\npd\nimport\nstatistics\nimport\nnumpy\nas\nnp\nimport\nmatplotlib.pyplot\nas\nplt\nEnter fullscreen mode\nExit fullscreen mode\nFetch all the required data!\nThe dataset used here contains 5000 records, and is stored across 5 files, each file containing 1000 records.\nMore specifically, the dataset contains details such as the first and last names, email addresses of customers and the amount they spent on purchasing goods, and the state in the US they're from.\nLet's fetch all the records, read them into pandas DataFrames and take a look at the head of each of the DataFrames.\nurl1\n=\n'\nhttps://raw.githubusercontent.com/OpenMined/PyDP/dev/examples/Tutorial_4-Launch_demo/data/01.csv\n'\ndf1\n=\npd\n.\nread_csv\n(\nurl1\n,\nsep\n=\n\"\n,\n\"\n,\nengine\n=\n\"\npython\n\"\n)\nprint\n(\ndf1\n.\nhead\n())\nEnter fullscreen mode\nExit fullscreen mode\nurl2\n=\n'\nhttps://raw.githubusercontent.com/OpenMined/PyDP/dev/examples/Tutorial_4-Launch_demo/data/02.csv\n'\ndf2\n=\npd\n.\nread_csv\n(\nurl2\n,\nsep\n=\n\"\n,\n\"\n,\nengine\n=\n\"\npython\n\"\n)\nprint\n(\ndf2\n.\nhead\n())\nEnter fullscreen mode\nExit fullscreen mode\nurl3\n=\n'\nhttps://raw.githubusercontent.com/OpenMined/PyDP/dev/examples/Tutorial_4-Launch_demo/data/03.csv\n'\ndf3\n=\npd\n.\nread_csv\n(\nurl3\n,\nsep\n=\n\"\n,\n\"\n,\nengine\n=\n\"\npython\n\"\n)\ndf3\n.\nhead\n()\nEnter fullscreen mode\nExit fullscreen mode\nurl4\n=\n'\nhttps://raw.githubusercontent.com/OpenMined/PyDP/dev/examples/Tutorial_4-Launch_demo/data/04.csv\n'\ndf4\n=\npd\n.\nread_csv\n(\nurl4\n,\nsep\n=\n\"\n,\n\"\n,\nengine\n=\n\"\npython\n\"\n)\nprint\n(\ndf4\n.\nhead\n())\nEnter fullscreen mode\nExit fullscreen mode\nurl5\n=\n'\nhttps://raw.githubusercontent.com/OpenMined/PyDP/dev/examples/Tutorial_4-Launch_demo/data/05.csv\n'\ndf5\n=\npd\n.\nread_csv\n(\nurl5\n,\nsep\n=\n\"\n,\n\"\n,\nengine\n=\n\"\npython\n\"\n)\nprint\n(\ndf5\n.\nhead\n())\nEnter fullscreen mode\nExit fullscreen mode\nNow that we've fetched records from all the 5 files, let us concatenate all the DataFrames into a single large DataFrame and this constitutes our original dataset. Note that our dataset has 5000 rows(records) and 6 columns.\ncombined_df_temp\n=\n[\ndf1\n,\ndf2\n,\ndf3\n,\ndf4\n,\ndf5\n]\noriginal_dataset\n=\npd\n.\nconcat\n(\ncombined_df_temp\n)\nprint\n(\noriginal_dataset\n.\nshape\n)\n# Result\n# (5000,6)\nEnter fullscreen mode\nExit fullscreen mode\nCreating a Parallel Database\nLet us now create a parallel database that differs by only one record, say, Osbourne's record and name it redact_dataset. We then inspect the heads of both DataFrames to verify that Osbourne's record has been removed.\nredact_dataset\n=\noriginal_dataset\n.\ncopy\n()\nredact_dataset\n=\nredact_dataset\n[\n1\n:]\nprint\n(\noriginal_dataset\n.\nhead\n())\nprint\n(\nredact_dataset\n.\nhead\n())\nEnter fullscreen mode\nExit fullscreen mode\nAt this point, let us ask ourselves the following question.\nIs the amount of money we spend at our neighborhood store private or sensitive information? Well, it may not seem all that sensitive! But, what if the same information can be used to identify us?\nIn the example that we have, let us say we remove all personal information such as name and email address. Given that there's some access to the store's sales record, will the sales amount in itself not suffice to infer Osbourne's identity? Yes!\nAnd to do that, we sum up all entries in the\nsales_amount\ncolumn in our original dataset, and the\nredact_dataset\n. The difference between these two sums exactly gives us the amount that Osbourne spent, and is verified as shown in the code snippet below.\nThis is a simple example where membership inference was successful even after removal of personally identifiable information.\nsum_original_dataset\n=\nround\n(\nsum\n(\noriginal_dataset\n[\n'\nsales_amount\n'\n].\nto_list\n()),\n2\n)\nsum_redact_dataset\n=\nround\n(\nsum\n(\nredact_dataset\n[\n'\nsales_amount\n'\n].\nto_list\n()),\n2\n)\nsales_amount_Osbourne\n=\nround\n((\nsum_original_dataset\n-\nsum_redact_dataset\n),\n2\n)\nassert\nsales_amount_Osbourne\n==\noriginal_dataset\n.\niloc\n[\n0\n,\n4\n]\nEnter fullscreen mode\nExit fullscreen mode\nDifferentially Private Sum\nNow, we illustrate how\ndifferentially private sum\nin place of simple sum can help in\nrendering membership inference attacks unsuccessful\n.\nFor the example above, let's assume that the customers should spend a minimum of 5$ at the store and no more than 250$ for a particular purchase.\nWe then go ahead and compute differentially private sum on both original and the parallel dataset that differed by one record, as shown in the code snippets below.\ndp_sum_original_dataset\n=\nBoundedSum\n(\nepsilon\n=\n1.5\n,\nlower_bound\n=\n5\n,\nupper_bound\n=\n250\n,\ndtype\n=\n'\nfloat\n'\n)\ndp_sum_og\n=\ndp_sum_original_dataset\n.\nquick_result\n(\noriginal_dataset\n[\n'\nsales_amount\n'\n].\nto_list\n())\ndp_sum_og\n=\nround\n(\ndp_sum_og\n,\n2\n)\nprint\n(\ndp_sum_og\n)\n# Output dp_sum_og\n# 636723.61\ndp_redact_dataset\n=\nBoundedSum\n(\nepsilon\n=\n1.5\n,\nlower_bound\n=\n5\n,\nupper_bound\n=\n250\n,\ndtype\n=\n'\nfloat\n'\n)\ndp_redact_dataset\n.\nadd_entries\n(\nredact_dataset\n[\n'\nsales_amount\n'\n].\nto_list\n())\ndp_sum_redact\n=\nround\n(\ndp_redact_dataset\n.\nresult\n(),\n2\n)\nprint\n(\ndp_sum_redact\n)\n# Output dp_sum_redact\n# 636659.17\nEnter fullscreen mode\nExit fullscreen mode\nLet's proceed to summarize a few observations.\nNow that we've calculated the differentially private sum on the original and the second dataset, it's straightforward to verify that that the\ndifferentially private sums are not equal to sums under the non-differentially private setting\n.\nAlso, the difference is no longer equal to the amount that Osbourne spent indicating that membership attacks would now be unsuccessful, regardless of access to any other customer records.\nInterestingly, the differentially private sum values are still comparable and are not very different.\nWe've therefore succeeded in ensuring differential privacy in our simple example!\nprint\n(\nf\n\"\nSum of sales_value in the orignal dataset:\n{\nsum_original_dataset\n}\n\"\n)\nprint\n(\nf\n\"\nSum of sales_value in the orignal dataset with DP:\n{\ndp_sum_og\n}\n\"\n)\nassert\ndp_sum_og\n!=\nsum_original_dataset\n# Output\nSum\nof\nsales_value\nin\nthe\norignal\ndataset\n:\n636594.59\nSum\nof\nsales_value\nin\nthe\norignal\ndataset\nwith\nDP\n:\n636723.61\nprint\n(\nf\n\"\nSum of sales_value in the second dataset:\n{\nsum_redact_dataset\n}\n\"\n)\nprint\n(\nf\n\"\nSum of sales_value in the second dataset with DP:\n{\ndp_sum_redact\n}\n\"\n)\nassert\ndp_sum_redact\n!=\nsum_redact_dataset\n# Output\nSum\nof\nsales_value\nin\nthe\nsecond\ndataset\n:\n636562.65\nSum\nof\nsales_value\nin\nthe\nsecond\ndataset\nwith\nDP\n:\n636659.17\nprint\n(\nf\n\"\nDifference in Sum with DP:\n{\nround\n(\ndp_sum_og\n-\ndp_sum_redact\n,\n2\n)\n}\n\"\n)\nprint\n(\nf\n\"\nActual Difference in Sum:\n{\nsales_amount_Osbourne\n}\n\"\n)\nassert\nround\n(\ndp_sum_og\n-\ndp_sum_redact\n,\n2\n)\n!=\nsales_amount_Osbourne\n# Output\nDifference\nin\nsum\nusing\nDP\n:\n64.44\nActual\nValue\n:\n31.94\nEnter fullscreen mode\nExit fullscreen mode\nHope this introductory post helped in understanding the intuition behind differential privacy and protection against membership inference attacks. We shall look at a few more examples in subsequent blog posts.😊\nReferences\n[1] The Algorithmic Foundations of Differential Privacy by Cynthia Dwork.\n[2] PyDP Tutorial by Chinmay Shah at OpenMined Privacy Conference",
  "metadata": {
    "title": "PyDP: A Python Differential Privacy Library - DEV Community",
    "description": "Outline   1️⃣ What does Differential Privacy try to address? 2️⃣ Why doesn't anonymization... Tagged with python, tutorial, programming.",
    "keywords": "python, tutorial, programming, software, coding, development, engineering, inclusive, community",
    "author": null,
    "og:type": "article",
    "og:url": "https://dev.to/balapriya/pydp-a-python-differential-privacy-library-34ln",
    "og:title": "PyDP: A Python Differential Privacy Library",
    "og:description": "Outline   1️⃣ What does Differential Privacy try to address? 2️⃣ Why doesn't anonymization...",
    "og:site_name": "DEV Community",
    "og:image": "https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkask990x705nnbqohh95.jpg",
    "twitter:site": "@thepracticaldev",
    "twitter:creator": "@",
    "twitter:title": "PyDP: A Python Differential Privacy Library",
    "twitter:description": "Outline   1️⃣ What does Differential Privacy try to address? 2️⃣ Why doesn't anonymization...",
    "twitter:card": "summary_large_image",
    "twitter:widgets:new-embed-design": "on",
    "twitter:image:src": "https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkask990x705nnbqohh95.jpg"
  },
  "paywall": {
    "listed_paid": false,
    "detected": false,
    "marker": "",
    "public_only": false,
    "policy": "付费/会员内容只保留页面公开可见部分，不绕过付费墙"
  },
  "crawl": {
    "success": true,
    "status_code": 200,
    "error": ""
  },
  "code_blocks": [
    {
      "file": "attachments/296fd1695a46/code/body-000.txt",
      "chars": 41,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-001.txt",
      "chars": 265,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-002.txt",
      "chars": 175,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-003.txt",
      "chars": 175,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-004.txt",
      "chars": 167,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-005.txt",
      "chars": 175,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-006.txt",
      "chars": 175,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-007.txt",
      "chars": 143,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-008.txt",
      "chars": 137,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-009.txt",
      "chars": 296,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-010.txt",
      "chars": 557,
      "language": "text"
    },
    {
      "file": "attachments/296fd1695a46/code/body-011.txt",
      "chars": 897,
      "language": "text"
    }
  ],
  "images": [
    {
      "status": "ok",
      "url": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsg7q97kdm7wv601erl1i.jpg",
      "bytes": 59220,
      "reused": true,
      "local_path": "attachments/296fd1695a46/images/002.jpg",
      "src": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsg7q97kdm7wv601erl1i.jpg",
      "alt": " ",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsq7l8rotc04r5k0vpem.jpg",
      "bytes": 160658,
      "reused": true,
      "local_path": "attachments/296fd1695a46/images/003.jpg",
      "src": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsq7l8rotc04r5k0vpem.jpg",
      "alt": " ",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozr7zs2pjhejc17dllm4.jpg",
      "bytes": 89748,
      "reused": true,
      "local_path": "attachments/296fd1695a46/images/004.jpg",
      "src": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozr7zs2pjhejc17dllm4.jpg",
      "alt": " ",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqns91ihdlyyh6gjxr20.jpg",
      "bytes": 87928,
      "reused": true,
      "local_path": "attachments/296fd1695a46/images/005.jpg",
      "src": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqns91ihdlyyh6gjxr20.jpg",
      "alt": " ",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q65q3a9rbl4xs4tzvdy.jpg",
      "bytes": 82844,
      "reused": true,
      "local_path": "attachments/296fd1695a46/images/006.jpg",
      "src": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q65q3a9rbl4xs4tzvdy.jpg",
      "alt": " ",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm8fvbjzk9z8h9cwlsn00.jpg",
      "bytes": 85594,
      "reused": true,
      "local_path": "attachments/296fd1695a46/images/007.jpg",
      "src": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm8fvbjzk9z8h9cwlsn00.jpg",
      "alt": " ",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem91nefqovyos1h5i4lp.jpg",
      "bytes": 90324,
      "reused": true,
      "local_path": "attachments/296fd1695a46/images/008.jpg",
      "src": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem91nefqovyos1h5i4lp.jpg",
      "alt": " ",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcmrfdm81w3pxuegxs1g.jpg",
      "bytes": 92726,
      "reused": false,
      "local_path": "attachments/296fd1695a46/images/body-ba96a31eda6cffd6ffb0.jpg",
      "src": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcmrfdm81w3pxuegxs1g.jpg",
      "alt": " ",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zrzj5ohpslcjle7icjl.jpg",
      "bytes": 84188,
      "reused": true,
      "local_path": "attachments/296fd1695a46/images/009.jpg",
      "src": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zrzj5ohpslcjle7icjl.jpg",
      "alt": " ",
      "downloaded": true
    }
  ],
  "audio": [],
  "videos": [],
  "links": [
    {
      "href": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsg7q97kdm7wv601erl1i.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://github.com/chinmayshah99/pricon20/blob/master/ChinmayShah-Differential%20Privacy%20using%20PyDP.pdf",
      "label": "Image Source",
      "type": "a"
    },
    {
      "href": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsq7l8rotc04r5k0vpem.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozr7zs2pjhejc17dllm4.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqns91ihdlyyh6gjxr20.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q65q3a9rbl4xs4tzvdy.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm8fvbjzk9z8h9cwlsn00.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem91nefqovyos1h5i4lp.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcmrfdm81w3pxuegxs1g.jpg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zrzj5ohpslcjle7icjl.jpg",
      "label": "",
      "type": "a"
    }
  ],
  "repair_version": 2,
  "repaired_at": "2026-10-14T10:49:08Z",
  "source_url": "https://dev.to/balapriya/pydp-a-python-differential-privacy-library-34ln",
  "papers": [
    {
      "status": "ok",
      "url": "https://raw.githubusercontent.com/chinmayshah99/pricon20/master/ChinmayShah-Differential%20Privacy%20using%20PyDP.pdf",
      "bytes": 313237,
      "reused": false,
      "local_path": "papers/repair/e6730abca7b168f6dbe6.pdf"
    }
  ],
  "actual_video_files": [],
  "body_chars": 11355,
  "expected_body_images": 9,
  "discovery_status": "ok",
  "delivery_status": "ok",
  "missing_reason": "",
  "raw_html": "attachments/296fd1695a46/pages/source.html",
  "local_html": "attachments/296fd1695a46/pages/article.html",
  "body_base_path": "attachments/296fd1695a46/pages/",
  "body_markdown_path": "attachments/296fd1695a46/pages/article.md"
}