200 条办事记录,159 条的「年龄 × 邮编 × 性别」组合是唯一的——等于实名。 把年龄改成 20 岁一档、邮编只留前两位:唯一组合归零,最小 k 从 1 涨到 4, 代价是组合数从 178 掉到 18。 差分隐私那边:ε=0.1 时对 120 的计数平均偏 9.8,ε=2.0 时只偏 0.5。
前八章都在做「怎么把模型训出来」。 从这一章开始换视角—— 行业场景里,能不能训、能不能用,往往不是技术决定的。政务和教育的第一道关,就是数据。
一、两条完全不同的路
路线一:匿名化(k-匿名)。 把「能定位到个人」的字段做粗,让每个人都藏在一群人里。 数据还在,只是变模糊了。 路线二:差分隐私。 原始数据不动,在统计结果上撒噪声。 对外发布的是「120 ± 随机量」而不是「120」。 这两条经常被当成替代关系,其实不是: k-匿名防的是「通过组合字段认出某个人」,差分隐私防的是「从统计结果反推某个人是否存在」。 攻击面不一样,所以两样都要。 还有第三条常被忽略的:访问控制。前两条是「数据出去了怎么办」,这一条是「不出去」。 在政务场景里,它的性价比最高——因为大部分泄露是内部越权查看。
二、k-匿名:把「能认出人」变成一个可检查的数
做法很简单:把「准标识符」(年龄、邮编、性别这类单看不敏感、组合起来能定位人的字段)分组, 要求每一组里至少有 k 个人。 Demo 造了 200 条记录做了一次体检:
| 口径 | 组合数 | 唯一组合 | 最小 k |
|---|---|---|---|
| 原始 | 178 | 159 | 1 |
| 泛化后 | 18 | 0 | 4 |
| 原始状态下 159 条的组合是唯一的,也就是说「知道这三项就能认人」。 | |||
| 这在人口少的区县里特别严重——邮编一细,几乎等于实名。 | |||
| 泛化之后唯一组合归零、最小 k 到 4。 | |||
| 但代价写在「组合数」那一列:从 178 掉到 18。数据变粗了—— | |||
| 「这个区 30 到 50 岁的人有多少」还答得出,「这个街道 37 岁的人有多少」就答不出了。 | |||
| 所以 k 的取值是业务和隐私的讨价还价,不是技术参数。k=3 是常见底线,k=5 到 10 用在敏感数据上。 | |||
| 先问「这张表要给谁看、要回答什么问题」,再定 k。 |
三、差分隐私:隐私预算花在哪
差分隐私的核心只是一个数:ε(epsilon),隐私预算。ε 越小越隐私,噪声越大; ε 越大越准,隐私越弱。它没有「安全值」,只有「你愿意付多少」。 Demo 对一个真实计数 120 加 Laplace 噪声,各跑 2000 次:
| ε | 噪声尺度 b | 平均绝对误差 | 相对误差 |
|---|---|---|---|
| 0.1 | 10.0 | 9.8 | 8.2% |
| 0.5 | 2.0 | 2.1 | 1.7% |
| 1.0 | 1.0 | 1.0 | 0.8% |
| 2.0 | 0.5 | 0.5 | 0.4% |
| ε=0.1 时平均偏 9.8——对 120 这个数来说,「大概一百二三」和「一百一」分不清, | |||
| 统计基本没用了。 | |||
| ε=2.0 时只偏 0.5,统计还能用,但隐私保护也弱了。 | |||
| 所以 ε 不是「越高越好」或「越低越好」,是「按用途配」。 | |||
| 工程上有个关键纪律:预算是要累加的。同一个数据集上做 10 次 ε=0.1 的查询, | |||
| 总的隐私损失接近 ε=1.0。所以「多查几次没关系」是错的——那是在花同一份预算。 |
四、落地:三步走
第一步,先分类。 把字段分成「标识符」(姓名、身份证,必须去掉)、「准标识符」(年龄、邮编, 要泛化)、「敏感属性」(病情、收入,要保护)、「普通属性」。这一步做不对,后面全白做。 第二步,定发布形态。 是给明细表(用 k-匿名),还是只给统计结果(用差分隐私), 还是只给模型接口(那就连数据都不出去,只出预测)。第三种在政务场景里最常用,也最省事。 第三步,留审计。 谁在什么时候查了什么,全部记下来。 这一条不能省:数据泄露案里,八成靠日志才查得出是谁。 最后提醒一句:k-匿名不是万能的。 它防不住「同质攻击」(一组里三个人都是同一种罕见病, k 再大也没用),也防不住「背景知识攻击」(我知道你住这个小区、这个年龄, 再对上外部信息就能定位)。所以它是一层,不是全部。
五、动手 Demo:k-匿名体检:200 条里 159 条唯一,泛化后一条不剩
造 200 条办事记录(年龄、邮编、性别、事项),按「年龄 × 邮编 × 性别」分组, 数出只有一个成员的分组(可重识别)和最小分组大小; 再做泛化(年龄 20 岁一档、邮编只留前两位)重算一遍。 另对「120」这个计数按四个 ε 各加 2000 次 Laplace 噪声,量平均误差。
def kmin(a, z, s):
seen = {}
for i in range(n):
key = (a[i], z[i], s[i])
seen[key] = seen.get(key, 0) + 1
uniq = sum(1 for v in seen.values() if v == 1)
return uniq, min(seen.values()), len(seen)
u1, k1, g1 = kmin(age, zc, sex) # 原始
u2, k2, g2 = kmin((age // 20) * 20, # 泛化
(zc // 10000) * 10000, sex)
v = 120 + rg.laplace(0.0, 1.0 / eps, 2000) # 差分隐私
实跑输出:
--------------------------------------------------------------------
k-匿名体检:200 条里 159 条唯一,泛化后一条不剩
--------------------------------------------------------------------
记录数 200 条
准标识符组合 年龄 × 邮编 × 性别
口径 组合数 唯一组合(可重识别) 最小 k
----------------------------------------------
原始 178 159 1
泛化后 18 0 4
**200 条记录里 159 条的组合是唯一的**——只要知道年龄、邮编、性别,就能把人认出来。
把年龄改成 20 岁一档、邮编只留前两位,再查:**唯一组合降到 0 个,最小 k 从 1 涨到 4。**
这就是 k-匿名:**要求每一组里至少有 k 个人,任何一个人都无法被单独认出来。**
注意代价:**组合数从 178 掉到 18**,数据变粗了。「这个区 30 到 50 岁的人有多少」还答得出,
「这个街道 37 岁的人有多少」就答不出了。
另一个思路是差分隐私。**它不删数据,只在统计结果上撒噪声:**
真实计数 120、敏感度 1,按 Laplace(1/ε) 加噪 2000 次:
ε 噪声尺度 b 平均绝对误差 相对误差
-----------------------------------------
0.1 10.0 9.8 8.2%
0.5 2.0 2.1 1.7%
1.0 1.0 1.0 0.8%
2.0 0.5 0.5 0.4%
**ε 越小越隐私,误差越大。** ε=0.1 时平均偏 9.8,对 120 这个数来说答案基本没用了;
ε=2.0 时误差只有 0.5,统计还能用。**这就是隐私预算的取舍,没有免费的一档。**
两者解决的不是同一个问题:k-匿名防的是「通过组合字段认出人」,
差分隐私防的是「从统计结果反推个体」。
要说明:k-匿名的代价是信息损失,
**而且它对「同质攻击」「背景知识攻击」都没防御力**——如果一组里三个人都是同一个罕见病患者,
k 再大也没用。
第一行结论:原始状态下 159/200 条的组合是唯一的。这个比例高得吓人, 但它就是真实情况——准标识符越多越细,唯一性涨得越快。 泛化那行:唯一组合 0,最小 k 从 1 涨到 4。 说明这 200 个人里,每一个人至少和另外 3 个人「长得一样」。 代价那一列别跳过:组合数从 178 掉到 18。数据从「每组一两个人」变成「每组十几个人」, 能回答的问题也跟着变粗。 差分隐私那段: ε 从 0.1 到 2.0,误差从 9.8 降到 0.5,正好 20 倍。这是 Laplace 分布的性质——误差与 1/ε 成正比, 不是巧合。 要说明:这 200 条记录是我用随机数造的,不是真数据。 但「唯一组合数」「最小 k」这两个指标的定义和算法是真的,换成任何一张真表都能直接跑。
30 秒实验
- 把记录数从 200 加到 2000,重跑。唯一组合的比例会涨——数据越多,越容易有人被单独分出来。
- 把年龄从 20 岁一档改成 5 岁一档,看最小 k 掉到多少。越细越不安全,这个方向要记住。
- 把 ε 从 0.1 一路加到 10.0,看平均误差能不能降到 0.1 以下。 能,但那时候噪声已经小到不构成保护了。
常见误区
- 「把姓名删了就叫匿名」。姓名只是标识符之一,年龄加邮编加性别就够定位了。
- 「ε 越小越安全,直接设 0.01」。设太小结果就没用了,业务会绕过系统去要原始数据,反而更危险。
- 「同一个人多查几次不受影响」。隐私预算会累加,十次小查询加起来等于一次大查询。
自测三问(点开对答案)
1. k-匿名防的是什么? —— 防「通过组合准标识符认出某个人」。它要求每一组至少 k 个人,任何个体都无法被单独分出来。 2. 差分隐私里的 ε 是什么意思? —— 隐私预算。ε 越小噪声越大、越隐私,ε 越大越准、保护越弱。它没有安全值,只有取舍。 3. 为什么两条路线不能互相替代? —— 攻击面不同:k-匿名防「组合字段定位个体」,差分隐私防「从统计结果反推个体是否存在」。隐私这条线守住了,接下来是「怎么把事做得更好」。 第一个手段是多模态——让模型同时看文字、图像和声音。
- ☐ (本节完,下一节 9.1.2 多模态融合)