通过差分隐私获得更有用的结果
你已经决定用差分隐私(DP)来发布或分享一些统计数据。你跑通了第一个管道或查询,正兴奋着,结果……拿到手的却是一堆没用的东西。也许数据全消失了,也许统计数据看着完全不靠谱——噪声把有用信号全淹没了。别急着放弃!这种情况在第一次尝试差分隐私时太常见了。而且很可能,你只需要做些简单调整就能解决。
这篇文章里,我们会介绍五种基本策略,帮你提高匿名数据的实用性。这些远不是你能用的全部技巧,但作为起点已经很好了。而且,它们都不需要你牺牲任何隐私保证。
尽可能多地聚合数据,尽可能粗糙
DP 算法在更多数据上运行时效果更好。记住:它引入的噪声与单个个体的贡献成比例,跟输入数据的总量无关。所以,统计数据里包含的人越多,相对噪声就越小。个体贡献会"消失在人群中",加进去的不确定性也一样。
增加输入数据总量能提高实用性,但你未必能拿到更多数据。幸运的是,还有别的办法利用这个特性。关键在于,你生成的每个统计数据所基于的数据量。换句话说,数据切得越细碎,实用性就越差。如果可以的话,把数据分成更粗的分区。比如,算每周统计而不是每日统计;按国家聚合而不是按城市。你懂的。
另一个常见技巧是少用几个维度。假设你的查询要算按国家和语言分的访客数。你真的需要两个维度的组合吗?国家和语言的组合中有很多是很少见的,访客寥寥。与其如此,分别统计可能效果更好:每个统计数据里会有更多用户,噪声的整体影响也就更小。
最小化聚合的数量
DP 限制的是:通过一系列数据发布,你能了解到任何个体的信息总量。你每算一个统计数据,就会暴露数据中个体的一些信息。为了控制整体隐私开销,你必须设定一个隐私预算——也就是你所有计算的总 \(\varepsilon\) 和 \(\delta\) 开销。
每个统计数据都会消耗一部分隐私预算。所以,如果你有一个固定的隐私预算,又需要算更多统计数据,每个就只能分到更少。这意味着要加更多噪声。如何在保护多个统计数据的同时控制噪声量,是一个活跃的研究领域,文献中充满了各种技巧。但最好的方案往往最简单:少算几个统计数据。
好,这有点抽象。实际操作中怎么减少统计数据的数量?以下是一些常见策略:
- 砍指标。比如你在算页面浏览量和独立访客数……能不能只用其中一个?
- 砍维度。你真的需要按国家和按语言分别统计访客吗?只取其中一个是不是就够了?
- 砍时间段。你需要同时算过去一天、一周、一个月和一年的独立访客数吗?其中一两个是不是就够用了?
- 砍"滑动窗口"。什么叫滑动窗口?假设你每天都要算过去一周的访问次数。这样一来,每个数据点会贡献到七个独立的统计数据里……改成每周只算一次行不行?
不均匀地分割隐私预算
这个技巧跟上一条相关。假设你已经减少了聚合数量,但还是有好几个。这时候可以尝试不均匀地分配总隐私预算。假设总预算是 \(\varepsilon=1\),你有五个统计数据。不必每个都分 \(\varepsilon=0.2\)!你可以给其中一个分 \(\varepsilon=0.8\),其余四个各分 \(\varepsilon=0.05\)。
不均匀分配隐私预算,在两种常见情况下很有用:
- 你更在意某些统计数据的准确性。那就把更大比例的预算分给最重要的那些。
- 有些统计数据比其他更精细。比如你同时算每日和每周统计。平均来看,每周统计的数据量是每日的 7 倍,你可以给它 7 倍小的预算。这样一来,噪声对两者的相对影响大致相同。
设置激进的贡献界限
大多数 DP 算法都会限制每个个体对每个统计数据的贡献。比如统计每个网页的访问次数时,你需要限制:
- 每个人最多能贡献多少个不同页面;
- 每个人对每个页面最多能访问多少次。
这些界限该怎么选?设一个宽松的、能覆盖所有可能输入的界限看起来很诱人。但这通常对实用性不利:加的噪声幅度会随界限增大。两种误差来源之间存在取舍:
- 界限大——丢失的数据少,但噪声更多;
- 界限小——可能丢失更多数据,但噪声更少。
通常来说,降低整体噪声水平比保留少数异常值更划算。最佳截断点取决于数据分布:第 95 百分位数可能对某个数据集合适,另一个数据集则用第 98 百分位数更好。但在大多数场景下,当数据集中有一部分数据超出界限时,你反而能达到最佳实用性。
注意,有些系统不让你手动指定这些界限,而是通过辅助 DP 算法自动计算。但这个操作本身也要消耗隐私预算!这种情况下,如果你手动指定界限,就能省下那部分预算,得到噪声更少的结果。
使用公共分区
大多数 DP 管道会生成大量统计数据,按分区分组。分区就像直方图里的桶:在统计每个网页访问次数的例子中,每个页面就是一个分区。默认情况下,管道只发布数据集中部分分区的统计数据。通常会保留人多的分区,去掉人少的。但这个选择过程本身可能暴露个体信息,所以必须以 DP 方式完成——又要消耗一部分隐私预算,还要给统计数据加额外噪声。
如果你在运行查询之前就列出所有希望出现在输出中的分区,就可以跳过这一步。用非私有数据来做这件事的话,就不再需要以 DP 方式选择分区了。这样既能节省预算,又能返回更多分区。
有个缺点:你指定的所有分区都会出现在输出中,即使它们在数据集中几乎没有数据。这种情况下,结果可能会非常嘈杂。不过,如果你能提前列出想要的分区,这通常是个很实用的技巧。你可以在 Privacy on Beam codelab 中看看实际效果。注意,你不允许查看私有数据来构建公共分区列表!
更多聪明的想法
还有无数其他技巧能从 DP 管道中榨出更多实用性。大多数比本文列出的更复杂,有些也许是未来博客文章的主题!与此同时,这里再给三个更通用的建议:

浙公网安备 33010602011771号