【敏感度,查询,裁剪代码实现】差分隐私代码实现系列(六)

本文详细讲解了差分隐私中的敏感性概念,如何计算不同类型的查询(如计数、求和、平均)的敏感度,以及距离度量在定义中的作用。重点介绍了裁剪技术,如何处理无限敏感度查询,以及在实践中如何通过实例演示来理解这些概念。
摘要由CSDN通过智能技术生成

写在前面的话

书上学来终觉浅,绝知此事要躬行

回顾

1、顺序组合给出的隐私成本的界限是一个上限,两个特定的差异隐私机制的实际隐私成本可能小于此,但永远不会比这个更大。

2、实际的隐私损失似乎略低于由顺序组合确定的上限 ϵ \epsilon ϵ

3、如果数据集中的每个参与者都向 X X X贡献了一行,则此行将恰好出现在块之一 x 1 , . . . , x k x_1, ..., x_k x1,...,xk中。这意味着 F F F只会"看到"这个参与者的数据一次,这意味着 ϵ \epsilon ϵ的隐私成本适合该个人。由于此属性适用于所有个人,因此每个人的隐私成本为 ϵ \epsilon ϵ

4、单个行不可能同时具有属性的两个值,因此以这种方式定义直方图中条柱可以保证它们不相交。

5、对于在构建列联表时考虑的任何一组数据属性,任何单个行都不可能同时具有多个值。因此,在这里使用并行组合也是安全的。

6、执行后处理,这可能会减少噪声或改善机制输出中的信号。

之前谈了一下差分隐私的属性,现在来聊一下差分隐私敏感度的问题~

敏感性(Sensitivity)

正如我们在对拉普拉斯机制进行讨论时所提到的,确保给定查询的差分隐私所需的噪声量取决于查询的敏感性。

粗略地说,函数的灵敏度反映了函数的输出在其输入更改时将更改的量

回想一下,拉普拉斯机制定义了一个机制 F ( x ) F(x) F(x),如下所示:

F ( x ) = f ( x ) + Lap ( s ϵ ) F(x) = f(x) + \textsf{Lap}(\frac{s}{\epsilon}) F(x)=f(x)+Lap(ϵs)
其中 f ( x ) f(x) f(x)是确定性函数(查询), ϵ \epsilon ϵ是隐私参数, s s s f f f的敏感度。

对于函数 f : D → R f : \mathcal{D} \rightarrow \mathbb{R} f:DR将数据集( D \mathcal{D} D)映射到实数, f f f的全局敏感度定义如下:

G S ( f ) = max ⁡ x , x ′ : d ( x , x ′ ) < = 1 ∣ f ( x ) − f ( x ′ ) ∣ GS(f) = \max_{x, x': d(x,x') <= 1} |f(x) - f(x')| GS(f)=x,x:d(x,x)<=1maxf(x)f(x)
这里, d ( x , x ′ ) d(x, x') d(x,x)表示两个数据集 x x x x ′ x' x之间的距离,我们说如果两个数据集的距离为 1 或更小,则它们是相邻数据集。

如何定义这个距离对我们获得的隐私定义有很大的影响,稍后我们将详细讨论数据集上的距离指标。

全局敏感度的定义表明,对于任何两个相邻的数据集 x x x x ′ x' x f ( x ) f(x) f(x) f ( x ′ ) f(x') f(x)之间的差异最多为 G S ( f ) GS(f) GS(f)

这种敏感度度称为"全局",因为它独立于所查询的实际数据集(它适用于相邻 x x x x ′ x' x的任何选择)。

另一种灵敏度度量,称为局部灵敏度,将其中一个数据集固定为被查询的数据集;我们将在后面的部分中考虑此度量值。大家感兴趣可以去我的博客:全局敏感度,局部敏感度和平滑敏感度到底有什么区别?【差分隐私】看看。

后续,当我们说"敏感性"时,我们指的是全局敏感性。

距离(Distance)

前面描述的距离度量 d ( x , x ′ ) d(x,x') d(x,x)可以通过许多不同的方式定义。

直观地说,如果两个数据集的数据恰好在一个人的数据中不同,则两个数据集之间的距离应等于 1(即数据集是相邻数据集)。

这个想法在某些情况下很容易形式化(例如,在美国人口普查中,每个人都提交包含其数据的单个响应),但在其他上下文中(例如位置轨迹,社交网络和时间序列数据)极具挑战性。

包含行的数据集的常见正式定义是考虑两者之间不同的行数。

当每个人的数据都包含在一行中时,此定义通常有意义。

形式上,此距离定义被编码为两个数据集之间的对称差值:

d ( x , x ′ ) = ∣ x − x ′ ∪ x ′ − x ∣ d(x, x') = | x - x' \cup x' - x | d(x,x)=xxxx
这个特定的定义有几个有趣和重要的含义:

如果 x ′ x' x是通过添加一行从 x x x构造的,则 d ( x , x ′ ) = 1 d(x,x') = 1 d(x,x)=1

如果 x ′ x' x是通过删除一行从 x x x构造的,则 d ( x , x ′ ) = 1 d(x,x') = 1 d(x,x)=1

如果 x ′ x' x是通过修改一行从 x x x构造的,则 d ( x , x ′ ) = 2 d(x,x') = 2 d(x,x)=2

换句话说,添加或删除行会导致相邻的数据集;修改行会导致在距离为 2处生成数据集。

这种对距离的特殊定义导致了通常所说的无界差分隐私。

还可以使用许多其他定义,包括一个称为有界差分隐私的定义,其中修改数据集中的单个行确实会产生相邻的数据集。

现在,我们将坚持上面定义的对称差分的形式定义。我们将在后面的部分中讨论替代定义。

计算灵敏度(Calculating Sensitivity)

我们如何确定特定感兴趣函数的灵敏度?对于实数上的一些简单函数,答案是显而易见的。

f ( x ) = x f(x) = x f(x)=x的全局敏感度为 1,因为将 x x x变化 1 会将 f ( x ) f(x) f(x)更改为 1

f ( x ) = x + x f(x) = x+x f(x)=x+x的全局敏感度为 2,因为将 x x x变化 1 会将 f ( x ) f(x) f(x)更改为 2

f ( x ) = 5 ∗ x f(x) = 5*x f(x)=5x的全局灵敏度为 5,因为将 x x x变化 1 会将 f ( x ) f(x) f(x)更改为 5

f ( x ) = x ∗ x f(x) = x*x f(x)=xx的全局敏感度是无界的,因为 f ( x ) f(x) f(x)的变化取决于 x x x的值

对于将数据集映射到实数的函数,我们可以执行类似的分析。我们将考虑表示常见聚合数据库查询的函数:计数、总和平均值。

计算查询数(Counting Queries)

计数查询(COUNT在 SQL 中)计算数据集中满足特定属性的行数。

根据经验,计数查询的敏感度始终为 1。

这是因为向数据集添加行最多可以将查询的输出增加 1:新行具有所需的属性,计数增加 1,或者不增加,并且计数保持不变(删除行时计数可能会相应减少)。

"数据集中有多少人?

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')

adult = pd.read_csv("adult_with_pii.csv")
adult.shape[0]

在这里插入图片描述
“有多少人的教育状况超过 10 岁?”

adult[adult['Education-Num'] > 10].shape[0]

在这里插入图片描述
“有多少人的教育状况等于或低于 10 岁?”

adult[adult['Education-Num'] <= 10].shape[0]

在这里插入图片描述
“有多少人叫 Joe Near?”

adult[adult['Name'] == 'Joe Near'].shape[0]

在这里插入图片描述

求和查询(Summation Queries)

求和查询(SUM在 SQL 中)对数据集行的属性值求和。

“受教育程度超过 10 岁的人的年龄总和是多少?”

adult[adult['Education-Num'] > 10]['Age'].sum()

在这里插入图片描述
这些查询的敏感度并不像计数查询数那样简单。

向数据集添加新行将按新人的年龄增加示例查询的结果。

这意味着查询的敏感度取决于我们添加的行的内容。

我们想提出一个具体的数字来表示查询的敏感性。不幸的是,没有这样数字真正存在。

例如,我们可以声称灵敏度为125,但这样会揭露了,我们添加到数据库中的行对应于超过125岁的人,这将违反我们的声明。对于我们提出的任何数字,添加的行都可能违反我们的声明。

你可能会对这一点持怀疑态度。假设我们声称灵敏度是1000 - 我们不太可能找到一个1000岁的人来违反这一说法。在这个特定的领域 - 年龄 - 对于一个人的年龄有一个非常合理的上限。最年长的人活到122岁,所以125的上限似乎是合理的。

但这并不能证明没有人会活到126岁。在其他领域(例如收入),可能更难提出合理的上限。

根据经验,当被求和属性的值不存在下限和上限时,求和查询具有无限的敏感度。

当存在下限和上限时,求和查询的敏感度等于它们之间的差值。后面会介绍"裁剪"的技术,用于在不存在边界时强制执行边界,以便将具有无界敏感度的求和查询转换为具有有限敏感度的查询。

平均查询(Average Queries)

平均查询(AVG在 SQL 中)计算特定列中属性值的平均值。

"受教育程度超过 10 岁的人的平均年龄是多少?“

adult[adult['Education-Num'] > 10]['Age'].mean()

在这里插入图片描述
使用差分隐私回答平均查询的最简单方法是将其重新表述为两个查询:求和查询除以计数查询。对于上面的例子:

adult[adult['Education-Num'] > 10]['Age'].sum() / adult[adult['Education-Num'] > 10]['Age'].shape[0]

在这里插入图片描述
可以根据之前说的方法计算这两个查询的敏感度。从而可以计算每个答案的噪声答案(例如,使用拉普拉斯机制),并且可以对噪声答案进行划分以获得差分隐私均值。两个查询的总隐私成本可以通过顺序组合来计算。

裁剪(Clipping)

具有无限敏感度的查询无法使用拉普拉斯机制使用差分隐私直接回答。

幸运的是,我们通常可以通过称为裁剪的过程将这些查询转换为具有有限敏感性的等效查询。

裁剪的基本思想是对属性值强制实施上限和下限。

例如,125岁以上的年龄可以被"裁剪"到正好125岁。裁剪后,我们保证所有年龄段均为125岁或以下。

因此,对裁剪数据进行求和查询的敏感性等于裁剪中使用的上限和下限之差: u p p e r − l o w e r upper - lower upperlower

例如,以下查询的敏感度为 125:

adult['Age'].clip(lower=0, upper=125).sum()

在这里插入图片描述
执行裁剪的主要挑战是确定上限和下限。

对于年龄,这很简单,没有人的年龄小于0,可能没有人会超过125岁。

如前所述,在其他领域,这要困难得多。

此外,在裁剪中丢失的信息量与确保差分隐私所需的噪声量之间存在权衡。当上下裁剪边界靠得更近时,灵敏度较低,需要的噪声更小,以确保差分隐私。

但是,激进的剪切通常会从数据中删除大量信息。这种信息丢失往往会导致准确性的损失,这超过了灵敏度降低导致的噪声改善的程度。

根据经验,请尝试将剪切边界设置为包含 100% 的数据集,或尽可能接近。在某些领域(例如,图查询,我们稍后将研究)比其他领域更难。

通过查看数据来确定剪切边界,这一点看起来很有道理,但其实里面存在问题。例如,我们可以查看数据集中年龄的直方图,以确定适当的上限:

plt.hist(adult['Age'])
plt.xlabel('Age')
plt.ylabel('Number of Records');

在这里插入图片描述
从这个直方图中可以清楚地看出,这个特定数据集中没有人超过90,所以上限90就足够了。

但是,重要的是要注意,此方法不满足差分隐私。

如果我们通过查看数据来选择裁剪边界,则边界本身可能会揭示有关数据的某些信息。

通常,剪切边界是通过使用数据集的属性来决定的,该属性无需查看数据即可知道(例如,数据集包含的年龄可能介于 0 和 125 之间),或者通过执行差分隐私查询来评估剪切边界的不同选择。

要使用第二种方法,我们通常将下限设置为 0,然后慢慢增加上限,直到查询的输出停止更改(这意味着我们没有通过增加边界来包含任何新数据)。

例如,让我们尝试计算从 0 到 100 的剪切边界的年龄总和,对每个边界使用拉普拉斯机制来确保差分隐私:

def laplace_mech(v, sensitivity, epsilon):
    return v + np.random.laplace(loc=0, scale=sensitivity/epsilon)

epsilon_i = .01
plt.plot([laplace_mech(adult['Age'].clip(lower=0, upper=i).sum(), i, epsilon_i) for i in range(100)])
plt.xlabel('Clipping Bound for Age')
plt.ylabel('Total Sum');

在这里插入图片描述
按顺序组合构建此图的总隐私成本为 ϵ = 1 \epsilon = 1 ϵ=1,因为我们执行了 100 个查询,每个查询 ϵ i = 0.01 \epsilon_i = 0.01 ϵi=0.01。很明显,结果在upper = 80值附近趋于一致,因此这对于剪切边界来说是一个不错的选择。

我们可以对来自任何数值域的数据属性使用相同的方法,但它有助于提前了解数据的规模。

例如,尝试在0到100之间修剪年收入的值不会很好,我们甚至无法找到合理的上限。

当数据刻度未知时,可以很好地工作的一种改进是根据对数刻度测试上限。

xs = [2**i for i in range(15)]
plt.plot(xs, [laplace_mech(adult['Age'].clip(lower=0, upper=i).sum(), i, epsilon_i) for i in xs])
plt.xscale('log')
plt.xlabel('Clipping Bound for Age')
plt.ylabel('Total Sum');

在这里插入图片描述
这种方法允许我们使用少量查询测试大量可能的边界,但代价是确定完美边界的精度较低。

随着上限变得非常大,噪声将开始淹没信号。

请注意,对于最大的裁剪参数,总和会剧烈波动!关键是要寻找图形中相对平滑(意味着低噪声)且不增加(意味着裁剪边界足够)的区域。

在这里,这大致发生在 2 8 = 256 2^8 = 256 28=256处,这是我们之前推导的上限的合理近似值。

总结

1、函数的灵敏度反映了函数的输出在其输入更改时将更改的量。

2、这种敏感度度称为"全局",因为它独立于所查询的实际数据集(它适用于相邻 x x x x ′ x' x的任何选择)。

3、这个想法在某些情况下很容易形式化(例如,在美国人口普查中,每个人都提交包含其数据的单个响应),但在其他上下文中(例如位置轨迹,社交网络和时间序列数据)极具挑战性。

4、根据经验,当被求和属性的值不存在下限和上限时,求和查询具有无限的敏感度。

5、具有无限敏感度的查询无法使用拉普拉斯机制使用差分隐私直接回答。

6、裁剪的基本思想是对属性值强制实施上限和下限。

7、此外,在裁剪中丢失的信息量与确保差分隐私所需的噪声量之间存在权衡。当上下裁剪边界靠得更近时,灵敏度较低,需要的噪声更小,以确保差分隐私。但是,激进的剪切通常会从数据中删除大量信息。这种信息丢失往往会导致准确性的损失,这超过了灵敏度降低导致的噪声改善的程度。根据经验,请尝试将剪切边界设置为包含 100% 的数据集,或尽可能接近。在某些领域(例如,图查询,我们稍后将研究)比其他领域更难。

8、请注意,对于最大的裁剪参数,总和会剧烈波动!关键是要寻找图形中相对平滑(意味着低噪声)且不增加(意味着裁剪边界足够)的区域。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

粥粥粥少女的拧发条鸟

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值