🧠 第十章 交通与智驾:构建安全高效出行解决方案
📄 一句话概括

300 辆车,每辆只取一个时刻的位置。 1000 米网格只有 16 个格子、最小 k 是 4;缩到 200 米,最小 k 就掉到 1。 50 米时 23% 的车单独占一格,10 米时 95%。 车牌那边更直白:保留后 5 位平均每号 0.07 辆,等于没脱敏;掩到 1 位又全撞在一起。

📝 本节和前面几节的关系

第九章讲的是政务和教育的数据。 这一章换到路上——交通数据最特殊的地方是:它天生带位置和时间。这两样加起来, 就是「谁在什么时候在哪」。

一、交通数据的敏感点在哪

行车记录、卡口过车、网约车轨迹、ETC 流水——这些表里通常没有姓名、没有身份证, 看起来「已经脱敏了」。 但里面有三样东西:车牌、坐标、时间戳。车牌是标识符(直接指向车主), 坐标加时间是准标识符——单看不敏感,合起来能定位一个人。 所以判断一批数据能不能对外,不能看「有没有姓名」, 要看「能不能把某一条记录固定到某一个人身上」。这个能力有个专门的词:可重识别性。 这一节就用两个实验把「可重识别」变成可检查的数。一个关于位置精度,一个关于车牌掩码位数。

二、位置本身就能定位一个人

Demo 里造了 300 辆车停在全城 40 个热点附近(4 个片区,片内间距约 150 米,每辆车定位噪声 30 米), 然后按不同精度把坐标量化成网格,数「每个格子里有几辆车」:

坐标精度 格数 单车格 最小 k 唯一比例
1000 米 16 0 4 0%
500 米 16 0 4 0%
200 米 36 5 1 2%
100 米 73 16 1 5%
50 米 145 68 1 23%
10 米 293 286 1 95%
1000 米网格下只有 16 个格子,最小 k 是 4——每辆车至少和另外 3 辆挤在一格,看起来匿名了。
缩到 200 米,最小 k 就掉到 1。意思是:已经有格子里只停了一辆车。
那个人的位置就暴露了——不需要所有人都被分出来。
到 50 米,23% 的车单独占一格;到 10 米,95%。而 10 米精度就是普通 GPS 的正常水平。

三、判据是最小 k,不是平均值

这张表最容易误读的地方是第四列和第五列的关系: 200 米时唯一比例只有 2%,看似「几乎没人被分出来」,但最小 k 已经是 1 了。 因为攻击者不需要打赢所有人,他只需要打中目标那一个。要查某辆车某天停在哪, 只要那辆车所在的格子是唯一的,剩下的 98% 与这次攻击无关。 所以隐私评估里,「平均值」几乎没有意义,「最坏情况」才是有意义的。k-匿名要求的是每一个 格子至少有 k 辆车,而不是「平均每格有 k 辆」。 这条判断可以直接转成合规口径: 「对外发布的坐标精度不得细于 X 米」——X 就是让最小 k 达到要求值的那个精度。 这是一句能写进合同的硬指标,比「做好脱敏」有用得多。

四、车牌掩码是个二选一的悬崖

另一个常见做法是「车牌掩掉几位」:只留省份和字母,后 5 位隐掉。 Demo 算了不同保留位数下,一个三百万辆车的城市里平均每个号牌对应多少辆车:

车牌保留 可枚举空间 平均同号车数
5 位 4543 万 0.07
4 位 134 万 2.24
3 位 3.9 万 76.33
2 位 1156 2595.16
1 位 34 88235.29
保留 5 位,平均每号 0.07 辆——几乎一号一车,等于没脱敏。
(这部分车牌的省市前缀本来就是公开信息。)
保留 1 位,平均 8.8 万辆车同号——彻底没法关联了,同一辆车的两次记录也连不起来。
中间没有安全区。保留 3 位是 76 辆,既不能定位个人(好),也没法做车辆级的统计(坏)。
所以工程上的正解不是掩码,是带盐哈希:同一辆车每次映射到同一个假名,但假名不可逆,
也不能靠「猜位数」反推。
掩码是给人看的(客服核对),哈希是给系统用的(关联分析)。这两个功能不该用同一个字段实现。

五、合规落地:三件事

① 最小必要。 分析「路段拥堵」根本不需要每辆车的轨迹,只需要每 5 分钟每段路的平均速度。 能只收聚合结果就不收明细——这是最省钱也最安全的做法。 ② 精度分级。 对外发布用粗网格(比如 1 公里),内部排查用细网格(比如 50 米), 两套数据分开存、分开授权。 别指望「一套数据加个开关」。 ③ 留审计。 谁在什么时候查了哪辆车的轨迹,全部落日志。 这一条在事故复盘时是唯一的依据,也是《个人信息保护法》落地检查里最先看的东西。 最后提醒一句:这三件事都不涉及模型。数据合不合规, 和模型准不准是两条独立的线——大部分交通 AI 项目卡住的地方,是第一条线。

六、动手 Demo:位置与车牌:网格缩到 200 米,最小 k 就掉到 1

造 300 辆车在 4 个片区、40 个热点附近的位置(定位噪声 30 米), 按 1000 到 10 米六档精度量化成网格,统计格数、只有一辆车的格子数、最小格内车数和唯一比例; 再算车牌保留 1 到 5 位时,三百万辆车的城市里平均每号对应几辆车。

hub = pc[rg.integers(0, 4, nhub)] + rg.normal(0, 150.0, (nhub, 2))
pos = hub[rg.integers(0, nhub, ncar)] + rg.normal(0, 30.0, (ncar, 2))

for g in (1000.0, 500.0, 200.0, 100.0, 50.0, 10.0):
    a = np.floor(pos / g).astype(int)        # 量化成格子
    key = {}
    for i in range(ncar):
        k = (a[i, 0], a[i, 1])
        key[k] = key.get(k, 0) + 1
    uniq = sum(1 for v in key.values() if v == 1)
    # 最小 k = min(key.values())

实跑输出:

--------------------------------------------------------------------
位置与车牌:网格缩到 200 米,最小 k 就掉到 1
--------------------------------------------------------------------
  车辆数 × 热点数          300 × 40
  热点分布                 4 个片区,片内间距约 150 米
  每辆车定位噪声           30 米

  坐标精度   格数   单车格   最小 k   唯一比例
  -------------------------------------------
   1000 米     16        0        4         0%
    500 米     16        0        4         0%
    200 米     36        5        1         2%
    100 米     73       16        1         5%
     50 米    145       68        1        23%
     10 米    293      286        1        95%

  车牌保留   可枚举空间   平均同号车数
  -----------------------------------
      5 位     45435424           0.07
      4 位      1336336           2.24
      3 位        39304          76.33
      2 位         1156        2595.16
      1 位           34       88235.29

  表一只是一个时刻的位置,不是轨迹——**光是「车停在哪」就够危险了。**
  **1000 米网格只有 16 个格子、最小 k 是 4:**
  300 辆车挤在十几个格子里,**看起来匿名了。**
  但缩到 **200 米**,最小 k 已经掉到 1、单车格 5 个——
  **只要有一个格子里只有一辆车,那个人的位置就露了。**
  100 米时唯一比例 5%,50 米 23%,10 米 95%。
  **注意「唯一比例」低不代表安全**:攻击者不需要所有人都被分出来,他只需要目标那一个。
  **所以判据要看最小 k,不是看平均值或比例。**
  这就是空间数据的麻烦:**去掉车牌没用,位置本身就能定位一个人**——住宅区的格子,一格就是几户人家。
  表二另一个旋钮。后 5 位全保留,300 万辆车平均每号 0.07 辆——
  **几乎一号一车,等于没脱敏。**
  保留 4 位平均 2.24 辆;3 位 76.33 辆;1 位 88235.29 辆。
  **掩得越狠越安全,但也越没法把同一辆车的两次记录关联起来。**
  所以掩码是个二选一的悬崖:**要么泄露个体,要么丢掉关联。**
  工程上的正解是**带盐哈希**:同一辆车每次映射到同一个假名,
  但假名不可逆、也不随位数暴露规律。**掩码是给人看的,哈希是给系统用的。**

先看两个极端: 1000 米时 16 个格子、最小 k 是 4;10 米时 293 个格子、95% 的车单独一格。同一批数据, 只改一个精度参数,隐私性完全不同。 关键在中间那一行:200 米时最小 k 已经掉到 1,但唯一比例只有 2%。 如果只报「2%」,会得出「影响很小」的结论,这是错的。 表二的三行连起来看:0.07 → 2.24 → 76.33 → 2595 → 88235。每少保留一位,同号车数涨 30 倍以上。 它不是线性的,因为可枚举空间是 34 的幂。 要说明:这 300 个位置和车牌空间都是我造的, 但网格量化的算法、最小 k 的定义、34 的幂都是真的。换成真实的卡口数据, 表一的算法一行都不用改。 还有一点要澄清:这里用的是单个时刻的位置,不是轨迹。 轨迹只会更危险——连续多个点,连「哪栋楼」都能推出来。

30 秒实验

  1. 把定位噪声从 30 米加到 100 米,看 50 米精度那一档的唯一比例。 会明显下降——但最小 k 仍然是 1,因为总有个别点落单。
  2. 把热点从 40 个加到 200 个(城市更密),重跑。 1000 米网格的格数会涨,最小 k 会掉——网格够粗也救不了。
  3. 把城市车辆数从 300 万改成 30 万,看车牌表。 保留 4 位的平均同号车数从 2.24 掉到 0.22——车越少,掩码越不安全。

常见误区

  1. 「没有姓名身份证就算脱敏」。坐标加时间加车牌,三样就能定位到人,而且比姓名更准。
  2. 「唯一比例只有 2%,影响很小」。最小 k 已经是 1,攻击者只需要目标那一个。要按最坏情况判。
  3. 「车牌掩掉后 5 位就安全了」。 平均 8.8 万辆车同号,安全是安全了,但同一辆车的记录也关联不起来了。要用带盐哈希。
自测三问(点开对答案) 1. 交通数据里,为什么「没有姓名」不等于「已脱敏」? —— 车牌、坐标、时间戳合起来能唯一固定一条记录到某个人,可重识别性和有没有姓名无关。 2. 为什么评估隐私要看最小 k 而不是唯一比例? —— 攻击者只需要把目标那一个分出来。最小 k 是 1 就说明有人被分出来了,哪怕这个比例只有 2%。 3. 车牌掩码为什么没有安全的中间档? —— 保留位数多则几乎一号一车(泄露个体),位数少则大量重号(丢掉车辆级关联)。 中间档两头都做不到,只能用带盐哈希。

数据这一关守住,接下来是「模型在坏天气里还准不准」。下一节把「鲁棒」这个词拆成一组可测的数。

相关笔记