Data latih deep learning sering berasal dari manusia: riwayat belanja, rekaman suara, hasil pemeriksaan. Setiap baris membawa identitas pemiliknya, dan model yang dilatih bisa mengingat bagian identitas tersebut — bahkan memuntahkannya kembali lewat teknik serangan. Perlindungan privasi karenanya bukan formalitas administratif melainkan bagian dari desain dataset. Chapter ini membahas prinsip dasarnya, menghitung k-anonymity pada tabel kecil, menerapkan derau Laplace untuk differential privacy, dan menutup dengan arsitektur yang memindahkan training ke pemilik data.

Tiga Prinsip Dasar #

  • Minimize — kumpulkan hanya kolom yang dibutuhkan tujuan model; setiap kolom tambahan adalah tanggung jawab tambahan.
  • Anonymize — lepaskan atau menyamarkan identifier sebelum data menyentuh lingkungan eksperimen.
  • Consent — pemilik data mengetahui untuk apa datanya dipakai dan menariknya kembali bila berubah pikiran.

Dua istilah sering tertukar dan membawa konsekuensi hukum berbeda. Anonymization mengubah data sehingga individu tidak dapat diidentifikasi lagi — statusnya lepas dari kewajiban regulasi banyak wilayah. Pseudonymization sekadar mengganti identifier langsung (nama menjadi kode P-042) tetapi identitas aslinya masih dapat dipulihkan lewat tabel peta terpisah — datanya tetap dianggap data pribadi. Regulasi rujukan di wilayah Eropa, GDPR, menetapkan pembedaan ini secara eksplisit di teks resminya .

k-anonymity: Privasi yang Dapat Dihitung #

Menghapus nama tidak cukup. Kombinasi kolom yang tampak tidak berbahaya — kota dan rentang usia — disebut quasi-identifier karena cukup untuk menyempitkan identitas. Tabel memenuhi k-anonymity bila setiap kombinasi quasi-identifier dimiliki minimal k baris: nilai k=1 berarti ada individu yang unik dan mudah ditebak, k=5 berarti setiap deskripsi setidaknya cocok untuk lima orang.

Berkas privasi_data.py menghitung k-anonymity tabel pelanggan fiktif, lalu menaikkannya lewat generalisasi bertahap, dan menutup dengan derau Laplace untuk differential privacy:

python
"""Privasi data: k-anonymity dan differential privacy (derau Laplace).

Bagian 1: tabel kecil berisi data pelanggan fiktif; kita hitung
k-anonymity untuk kombinasi quasi-identifier (kota + rentang usia).
Bagian 2: statistik rata-rata pendapatan dipublikasikan dengan dan tanpa
derau Laplace untuk beberapa nilai epsilon.
"""

import numpy as np

rng = np.random.default_rng(42)

# ---------- 1. Tabel data pelanggan fiktif ----------
nama = ["Budi", "Siti", "Andi", "Dewi", "Rina", "Tono",
        "Wati", "Joko"]
kota = np.array(["Bandung", "Bandung", "Bandung", "Surabaya",
                 "Surabaya", "Bandung", "Surabaya", "Bandung"])
usia = np.array([34, 36, 61, 63, 29, 35, 62, 33])
pendapatan = np.array([7.2, 6.8, 9.1, 8.9, 5.4, 7.0, 9.3, 6.6])

def rentang_usia(u):
    if u < 30:
        return "20-29"
    if u < 40:
        return "30-39"
    return "60+"


print("===== TABEL PELANGGAN (fiktif) =====")
for i in range(len(nama)):
    print(f"{nama[i]:5s} | {kota[i]:9s} | {usia[i]:3d} | "
          f"Rp{pendapatan[i]:.1f} jt")

# ---------- 2. k-anonymity: ukuran grup quasi-identifier ----------
qi = [(kota[i], rentang_usia(usia[i])) for i in range(len(nama))]
grup = {}
for i, kunci in enumerate(qi):
    grup.setdefault(kunci, []).append(nama[i])

print()
print("===== GRUP QUASI-IDENTIFIER (kota + rentang usia) =====")
for kunci, anggota in sorted(grup.items()):
    print(f"{kunci[0]:9s} {kunci[1]:6s} k={len(anggota)}  {anggota}")
k_min = min(len(v) for v in grup.values())
print(f"k-anonymity tabel: {k_min}")

# baris Andi (Bandung, 60+) unik -> identitas mudah ditebak
print("baris dengan k=1:", [nama[i] for i in range(len(nama))
                             if len(grup[qi[i]]) == 1])

# ---------- 3. Generalisasi: naikkan k ----------
kota_gen = np.array(["Jawa", "Jawa", "Jawa", "Jawa",
                     "Jawa", "Jawa", "Jawa", "Jawa"])
qi_gen = [(kota_gen[i], rentang_usia(usia[i])) for i in range(len(nama))]
grup_gen = {}
for i, kunci in enumerate(qi_gen):
    grup_gen.setdefault(kunci, []).append(nama[i])
print()
print("===== GENERALISASI 1: KOTA -> 'Jawa' =====")
for kunci, anggota in sorted(grup_gen.items()):
    print(f"{kunci[0]:5s} {kunci[1]:6s} k={len(anggota)}  {anggota}")
print("k-anonymity tabel:", min(len(v) for v in grup_gen.values()),
      "(Rina masih unik)")

# generalisasi kedua: rentang usia diperlebar menjadi dua kelompok
def rentang_usia_lebar(u):
    return "<40" if u < 40 else "40+"


qi_gen2 = [("Jawa", rentang_usia_lebar(usia[i])) for i in range(len(nama))]
grup_gen2 = {}
for i, kunci in enumerate(qi_gen2):
    grup_gen2.setdefault(kunci, []).append(nama[i])
print()
print("===== GENERALISASI 2: + RENTANG USIA DIPERLEBAR =====")
for kunci, anggota in sorted(grup_gen2.items()):
    print(f"{kunci[0]:5s} {kunci[1]:4s} k={len(anggota)}  {anggota}")
print("k-anonymity tabel:", min(len(v) for v in grup_gen2.values()))

# ---------- 4. Differential privacy: derau Laplace pada rata-rata ----------
mean_asli = float(pendapatan.mean())
sensitivitas = 9.3 - 5.4  # rentang pendapatan = sensitivitas query maks

print()
print("===== RATA-RATA PENDAPATAN: ASLI vs PRIVAT =====")
print(f"nilai asli              : {mean_asli:.3f}")
for eps in [10.0, 1.0, 0.1]:
    skala = sensitivitas / eps
    derau = []
    for _ in range(3):
        u = rng.uniform(-0.5, 0.5)
        lap = -skala * np.sign(u) * np.log(1 - 2 * np.abs(u))
        derau.append(mean_asli + lap)
    rata2_privat = float(np.mean(derau))
    print(f"epsilon={eps:5.1f} (skala {skala:.2f}): "
          f"3 rilis privat {np.round(derau, 3).tolist()}")
    print(f"{'':23s}rata-rata rilis: {rata2_privat:.3f} "
          f"(galat {abs(rata2_privat - mean_asli):.3f})")
print()
print("epsilon kecil = privasi kuat = galat besar (trade-off).")

Output yang Dihasilkan:

text
===== TABEL PELANGGAN (fiktif) =====
Budi  | Bandung   |  34 | Rp7.2 jt
Siti  | Bandung   |  36 | Rp6.8 jt
Andi  | Bandung   |  61 | Rp9.1 jt
Dewi  | Surabaya  |  63 | Rp8.9 jt
Rina  | Surabaya  |  29 | Rp5.4 jt
Tono  | Bandung   |  35 | Rp7.0 jt
Wati  | Surabaya  |  62 | Rp9.3 jt
Joko  | Bandung   |  33 | Rp6.6 jt

===== GRUP QUASI-IDENTIFIER (kota + rentang usia) =====
Bandung   30-39  k=4  ['Budi', 'Siti', 'Tono', 'Joko']
Bandung   60+    k=1  ['Andi']
Surabaya  20-29  k=1  ['Rina']
Surabaya  60+    k=2  ['Dewi', 'Wati']
k-anonymity tabel: 1
baris dengan k=1: ['Andi', 'Rina']

===== GENERALISASI 1: KOTA -> 'Jawa' =====
Jawa  20-29  k=1  ['Rina']
Jawa  30-39  k=4  ['Budi', 'Siti', 'Tono', 'Joko']
Jawa  60+    k=3  ['Andi', 'Dewi', 'Wati']
k-anonymity tabel: 1 (Rina masih unik)

===== GENERALISASI 2: + RENTANG USIA DIPERLEBAR =====
Jawa  40+  k=3  ['Andi', 'Dewi', 'Wati']
Jawa  <40  k=5  ['Budi', 'Siti', 'Rina', 'Tono', 'Joko']
k-anonymity tabel: 3

===== RATA-RATA PENDAPATAN: ASLI vs PRIVAT =====
nilai asli              : 7.537
epsilon= 10.0 (skala 0.39): 3 rilis privat [7.847, 7.487, 8.03]
                       rata-rata rilis: 7.788 (galat 0.250)
epsilon=  1.0 (skala 3.90): 3 rilis privat [9.496, 1.027, 19.319]
                       rata-rata rilis: 9.947 (galat 2.410)
epsilon=  0.1 (skala 39.00): 3 rilis privat [36.348, 40.646, -45.568]
                       rata-rata rilis: 10.475 (galat 2.938)

epsilon kecil = privasi kuat = galat besar (trade-off).

Contoh di atas diuji nyata dengan NumPy 2.1.3 pada mesin CPU dan selesai dalam waktu di bawah satu detik. Mari kita telaah kode di atas baris per baris:

  1. Baris 13-19 (tabel fiktif): delapan pelanggan dengan tiga kolom; nama dihapus pada dunia nyata, di sini sengaja dipertahankan agar pembaca dapat menelusuri siapa yang terungkap.
  2. Baris 21-27 (rentang usia): usia persis diubah menjadi rentang — generalisasi adalah alat utama menaikkan k, bukan penghapusan baris.
  3. Baris 34-49 (grup quasi-identifier): setiap kombinasi (kota, rentang usia) membentuk grup; k-anonymity tabel: 1 karena Andi (Bandung, 60+) dan Rina (Surabaya, 20-29) unik — satu deskripsi cukup untuk menunjuk satu orang.
  4. Baris 51-63 (generalisasi 1): kota diciutkan menjadi “Jawa”; k Andi naik ke 3 karena bergabung dengan dua warga Surabaya, tetapi Rina tetap unik — satu generalisasi belum tentu cukup.
  5. Baris 65-78 (generalisasi 2): rentang usia dilebarkan menjadi <40 dan 40+; tabel akhirnya mencapai k=3 — setiap deskripsi kini cocok untuk minimal tiga orang.
  6. Baris 80-102 (differential privacy): mekanisme Laplace menambahkan derau berskala sensitivitas/epsilon; sensitivitas dihitung dari rentang nilai query (9.3-5.4) — pengaruh maksimum satu orang terhadap rata-rata.
  7. Baris 94-102 (tiga epsilon): pada epsilon=10 derau kecil sehingga rilis tetap akurat; pada epsilon=0.1 skala derau 39.0 membuat hasilnya tidak bermakna — epsilon adalah tuas antara kegunaan statistik dan jaminan privasi.

Differential Privacy dalam Training #

Derau Laplace melindungi satu statistik. Untuk melindungi seluruh proses training, differential privacy dipindahkan ke dalam gradient: setiap kontribusi sampel dipotong (gradient clipping) lalu derau ditambahkan sebelum pembaruan bobot, sehingga model tidak dapat melacak satu individu secara presisi. Pustaka Opacus mengimplementasikan pola ini untuk PyTorch. Jaminannya berbentuk angka: budget epsilon total dibagikan ke seluruh epoch, dan angka tersebut dilaporkan bersama metrik model.

Federated Learning dan Ancaman Balik #

Dua arah pengembangan melengkapi kerangka ini. Federated learning membalik arah data: model dikirim ke pemilik data, training berjalan di perangkat masing-masing, dan hanya pembaruan bobot — bukan data mentah — yang dikirim kembali ke server; pola terdistribusinya dibahas di section Distributed dan Efficient Training . Di sisi sebaliknya, penyerang memakai model terlatih untuk mengekstraksi data latihnya: Model Inversion dan Data Leakage membongkar tekniknya, sementara Adversarial Examples menunjukkan input yang dirancang khusus dapat mengelabui model — pengingat bahwa perlindungan data dan keandalan model berjalan beriringan.

Privasi menutup section ini dengan pesan yang menjadi benang merah seluruh sembilan chapter: data bukan bahan mentah pasif, melainkan aset yang harus dicari sumbernya, dilabeli dengan terukur, dijaga keseimbangannya, dilindungi dari kebocoran, diberi identitas versi, diperluas secara sadar, dan pada akhirnya — dipertanggungjawabkan kepada manusia yang berada di balik setiap barisnya.