পাঠ ১৬ · ৫৭-এর মধ্যে · মডিউল ৪
Home / AI Courses / AI Ethics / প্রাইভেসি ও ডেটা এথিক্স

অ্যানোনিমাইজেশন, k-অ্যানোনিমিটি ও ডিফারেনশিয়াল প্রাইভেসি

Anonymization, k-anonymity & differential privacy
১৫ মিনিট পড়া কঠিন · Advanced Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • কেন সাধারণ "নাম-সরানো" অ্যানোনিমাইজেশন যথেষ্ট নয় — কুয়াসি-আইডেন্টিফায়ার ও রি-আইডেন্টিফিকেশন
  • k-অ্যানোনিমিটি — সংজ্ঞা, এবং একটি সত্যিকারের ইকুইভ্যালেন্স-ক্লাস চেকার
  • ডিফারেনশিয়াল প্রাইভেসি ও Laplace mechanism — epsilon প্যারামিটারের অর্থ
  • প্রকৃত গণনা দিয়ে দেখা — কেন একটি একক নয়েজি ড্র নির্ভরযোগ্য নয়, কিন্তু বহু ট্রায়ালের গড় unbiased, এবং কেন ছোট epsilon বড় ভ্যারিয়েন্স তৈরি করে

১ · অ্যানোনিমাইজেশন যথেষ্ট নয় কেন

একটি ডেটাসেট থেকে নাম ও ইমেইলের মতো সরাসরি identifier সরিয়ে ফেললেই সেটি "অ্যানোনিমাস" হয়ে যায় না। বাকি থাকা কলামগুলো — বয়স-গ্রুপ, জিপ কোডের প্রথম কয়েক ডিজিট, জেন্ডার — এককভাবে কাউকে শনাক্ত না করলেও, এদের সমন্বয়কুয়াসি-আইডেন্টিফায়ার (Quasi-identifier)এমন একটি অ্যাট্রিবিউট যা একা ব্যক্তিকে শনাক্ত করে না, কিন্তু অন্য কুয়াসি-আইডেন্টিফায়ারের সাথে মিলিয়ে বা একটি বাহ্যিক ডেটাসেটের সাথে ক্রস-রেফারেন্স করে ব্যক্তিকে শনাক্ত করা সম্ভব হতে পারে। (কুয়াসি-আইডেন্টিফায়ার) একটি বাহ্যিক পাবলিক ডেটাসেটের (যেমন ভোটার তালিকা) সাথে মিলিয়ে ব্যক্তিকে পুনরায় শনাক্ত করার জন্য যথেষ্ট হতে পারে। এই ঝুঁকি মোকাবেলার জন্য দুটি প্রতিষ্ঠিত টেকনিক এই পাঠে দেখানো হবে — k-অ্যানোনিমিটি (ডেটাসেট প্রকাশের আগে গ্রুপিং-ভিত্তিক সুরক্ষা) এবং ডিফারেনশিয়াল প্রাইভেসি (কোয়েরি-ফলাফলে গাণিতিক নয়েজ-ভিত্তিক সুরক্ষা)।

প্রাইভেসি-সুরক্ষার দুটি পথ k-অ্যানোনিমিটি Raw ডেটাসেট QI: age_group, zip3, gender একই QI-ভ্যালু → একই ক্লাসে গ্রুপ equivalence class সাইজ >= k পাস সাইজ < k ভায়োলেশন ফ্ল্যাগ ডিফারেনশিয়াল প্রাইভেসি প্রকৃত কোয়েরি ফলাফল true count + Laplace(0, b) নয়েজ b = sensitivity / epsilon প্রকাশিত noisy ফলাফল একক ড্র নয়েজি, বহু-ট্রায়াল গড় unbiased ছোট epsilon (বেশি প্রাইভেসি) → বড় b → বড় ভ্যারিয়েন্স (বেশি নয়েজ)
বাম: k-অ্যানোনিমিটি — ইকুইভ্যালেন্স-ক্লাসের সাইজ চেক করে পাবলিশের আগে গ্রুপ-ভিত্তিক সুরক্ষা। ডান: ডিফারেনশিয়াল প্রাইভেসি — কোয়েরি-ফলাফলে ক্যালিব্রেটেড র‍্যান্ডম নয়েজ যোগ করে গাণিতিক গ্যারান্টি।

২ · k-অ্যানোনিমিটি — সংজ্ঞা ও সত্যিকারের চেকার

একটি ডেটাসেট k-অ্যানোনিমাস বলা হয় যদি, কুয়াসি-আইডেন্টিফায়ার কলামগুলোর প্রতিটি সম্ভাব্য মান-সমন্বয় ("ইকুইভ্যালেন্স ক্লাস") এ অন্তত k জন সদস্য থাকে — অর্থাৎ যেকোনো একজনকে তার কুয়াসি-আইডেন্টিফায়ার দিয়ে খুঁজলে অন্তত k জনের একটি গ্রুপ পাওয়া যাবে, একজন নয়। আনুষ্ঠানিকভাবে:

$$ \forall \text{ equivalence class } C: \quad |C| \geq k $$

নিচের কোডে একটি সিন্থেটিক রোগী-ডেটাসেটে সত্যিই প্রতিটি ইকুইভ্যালেন্স ক্লাসের সাইজ গণনা করে, নির্দিষ্ট একটি k-এর জন্য কোন কোন নির্দিষ্ট সারি লঙ্ঘন করছে তা ফ্ল্যাগ করা হয়েছে।

Python
# কুয়াসি-আইডেন্টিফায়ার (QI): এককভাবে সরাসরি identify না করলেও একসাথে মিলিয়ে re-identification-এ ব্যবহারযোগ্য
patients = [
    {"id": 1, "age_group": "20-29", "zip3": "700", "gender": "F"},
    {"id": 2, "age_group": "20-29", "zip3": "700", "gender": "F"},
    {"id": 3, "age_group": "20-29", "zip3": "700", "gender": "F"},
    {"id": 4, "age_group": "30-39", "zip3": "700", "gender": "M"},
    {"id": 5, "age_group": "30-39", "zip3": "700", "gender": "M"},
    {"id": 6, "age_group": "40-49", "zip3": "701", "gender": "F"},
    {"id": 7, "age_group": "40-49", "zip3": "701", "gender": "M"},
    {"id": 8, "age_group": "20-29", "zip3": "702", "gender": "M"},
    {"id": 9, "age_group": "30-39", "zip3": "700", "gender": "M"},
    {"id": 10, "age_group": "50-59", "zip3": "703", "gender": "F"},
]

QI_COLUMNS = ["age_group", "zip3", "gender"]

def equivalence_classes(dataset, qi_cols):
    classes = {}
    for row in dataset:
        key = tuple(row[c] for c in qi_cols)
        classes.setdefault(key, []).append(row["id"])
    return classes

def check_k_anonymity(dataset, qi_cols, k):
    classes = equivalence_classes(dataset, qi_cols)
    violations = {key: ids for key, ids in classes.items() if len(ids) < k}
    return classes, violations

K = 3
classes, violations = check_k_anonymity(patients, QI_COLUMNS, K)

print(f"QI কলাম: {QI_COLUMNS}, k = {K}\n")
print("প্রতিটি equivalence class-এর সাইজ:")
for key, ids in sorted(classes.items(), key=lambda kv: -len(kv[1])):
    status = "OK" if len(ids) >= K else "VIOLATION"
    print(f"  {key} -> {len(ids)} জন (id: {ids})  [{status}]")

if violations:
    flagged_ids = sorted(i for ids in violations.values() for i in ids)
    print(f"\nk-অ্যানোনিমিটি (k={K}) ব্যর্থ -- {len(violations)}টি ক্লাসে সাইজ {K}-এর কম।")
    print(f"যেসব row-এর re-identification ঝুঁকি বেশি (id): {flagged_ids}")
else:
    print(f"\nডেটাসেট k={K}-অ্যানোনিমিটি সন্তুষ্ট করে -- প্রতিটি ক্লাসে অন্তত {K} জন আছে।")

    
লক্ষ্য করুন — id 1-3 এবং id 4,5,9 নিজ নিজ ইকুইভ্যালেন্স ক্লাসে অন্তত ৩ জন থাকায় k=3 সন্তুষ্ট করে, কিন্তু id 6, 7, 8, 10 প্রত্যেকেই একক-সদস্যের (size-1) ক্লাসে আছে — এদের কুয়াসি-আইডেন্টিফায়ার-সমন্বয় ডেটাসেটে অনন্য (unique), তাই এদের re-identification ঝুঁকি সবচেয়ে বেশি। বাস্তবে এই ধরনের সারি সাধারণীকরণ (generalization, যেমন age_group আরও বিস্তৃত করা) বা suppression (সারি বাদ দেওয়া) দিয়ে ঠিক করা হয়।

৩ · ডিফারেনশিয়াল প্রাইভেসি — Laplace mechanism

k-অ্যানোনিমিটি পুরো ডেটাসেট প্রকাশের আগে প্রয়োগ হয়। কিন্তু অনেক সময় আমরা পুরো ডেটাসেট প্রকাশ না করে শুধু একটি কোয়েরির ফলাফল (যেমন "কতজনের একটি নির্দিষ্ট শর্ত আছে?") প্রকাশ করতে চাই। ডিফারেনশিয়াল প্রাইভেসিDifferential Privacyএকটি গাণিতিক গ্যারান্টি — একজন ব্যক্তি ডেটাসেটে থাকুক বা না-থাকুক, কোয়েরির ফলাফলের সম্ভাব্যতা-বিতরণ প্রায় একই থাকে, ফলে একক ব্যক্তির উপস্থিতি ফলাফল থেকে অনুমান করা কঠিন হয়ে যায়। এই ফলাফলে ইচ্ছাকৃতভাবে ক্যালিব্রেটেড র‍্যান্ডম নয়েজ যোগ করে — যত বেশি নয়েজ, তত বেশি প্রাইভেসি, কিন্তু তত কম নির্ভুলতা (একটি সরাসরি ট্রেডঅফ)। এই নয়েজের পরিমাণ নিয়ন্ত্রণ করে epsilon ($\epsilon$) প্যারামিটার — ছোট $\epsilon$ মানে বেশি প্রাইভেসি (বেশি নয়েজ), বড় $\epsilon$ মানে কম প্রাইভেসি (কম নয়েজ)।

সবচেয়ে সাধারণ পদ্ধতিগুলোর একটি হলো Laplace mechanism — একটি count/sum-জাতীয় কোয়েরির প্রকৃত ফলাফলে Laplace ডিস্ট্রিবিউশন থেকে নেওয়া নয়েজ যোগ করা হয়:

$$ \text{released} = \text{true value} + \text{Laplace}(0, b), \qquad b = \frac{\Delta f}{\epsilon} $$

এখানে $\Delta f$ হলো sensitivity — একজন ব্যক্তি ডেটাসেটে যোগ/বাদ দিলে কোয়েরির ফলাফল সর্বোচ্চ কতটা বদলাতে পারে (একটি সাধারণ count কোয়েরির জন্য এটি ১)। Python-এর random মডিউলে সরাসরি Laplace sampler নেই, তাই আমরা inverse-CDF sampling ব্যবহার করে নিজেরাই বাস্তবায়ন করবো — যদি $U \sim \text{Uniform}(0,1)$ হয়, তাহলে নিচের রাশিটি $\text{Laplace}(0, b)$ থেকে একটি বৈধ স্যাম্পল দেয়:

$$ x = -b \cdot \text{sign}(U - 0.5) \cdot \ln\left(1 - 2|U - 0.5|\right) $$

একটি একক ড্র নয়েজি এবং অবিশ্বস্ত — তাই নিচের কোডে আমরা বহু ট্রায়াল (ভিন্ন ভিন্ন সিড দিয়ে) চালিয়ে গড় নেব, যা দেখাবে মেকানিজমটি expectation-এ unbiased (গড় প্রকৃত মানের কাছাকাছি), এবং তিনটি ভিন্ন epsilon-এর জন্য ভ্যারিয়েন্স তুলনা করে দেখাবো — ছোট epsilon সত্যিই বড় ভ্যারিয়েন্স তৈরি করে কি না।

Python
import random, math, statistics

TRUE_COUNT = 47   # ধরা যাক, ডেটাবেজে একটি নির্দিষ্ট শর্ত পূরণ করা রোগীর প্রকৃত সংখ্যা
SENSITIVITY = 1    # count query: একজন রোগী যোগ/বাদ দিলে ফলাফল সর্বোচ্চ ১ বদলাতে পারে

def sample_laplace(b, rng):
    # ইনভার্স-CDF sampling: U ~ Uniform(0,1) থেকে Laplace(0, b) স্যাম্পল
    u = rng.random()
    if u == 0.0:
        u = 1e-16  # rng.random() মাঝেমধ্যে ঠিক 0.0 দিতে পারে -- math.log(0) এড়াতে সীমানা থেকে সরানো হলো
    shift = u - 0.5
    if shift == 0:
        return 0.0
    sign = 1.0 if shift > 0 else -1.0
    return -b * sign * math.log(1 - 2 * abs(shift))

def run_trials(true_value, epsilon, sensitivity, n_trials):
    b = sensitivity / epsilon
    noisy_values = []
    for seed in range(n_trials):
        rng = random.Random(seed)   # প্রতিটি ট্রায়াল আলাদা সিড -- স্বাধীন ড্র
        noisy_values.append(true_value + sample_laplace(b, rng))
    return noisy_values

N_TRIALS = 5000
epsilons = [0.1, 0.5, 2.0]

print(f"প্রকৃত (noiseless) কাউন্ট: {TRUE_COUNT}\n")

results = {}
for eps in epsilons:
    trials = run_trials(TRUE_COUNT, eps, SENSITIVITY, N_TRIALS)
    results[eps] = trials
    single_draw = trials[0]
    mean_val = statistics.mean(trials)
    var_val = statistics.pvariance(trials)
    print(f"epsilon = {eps:>4}: single draw = {single_draw:8.2f} | "
          f"{N_TRIALS}-ট্রায়াল গড় = {mean_val:7.2f} | ভ্যারিয়েন্স = {var_val:8.2f}")

print()
var_small_eps = statistics.pvariance(results[0.1])
var_large_eps = statistics.pvariance(results[2.0])
print(f"epsilon=0.1 (বেশি প্রাইভেসি)-এর ভ্যারিয়েন্স, epsilon=2.0 (কম প্রাইভেসি)-এর তুলনায় "
      f"{var_small_eps / var_large_eps:.1f}x বেশি।")
print("প্রতিটি epsilon-এর single draw প্রকৃত মান থেকে বেশ দূরে থাকতে পারে,")
print("কিন্তু বহু-ট্রায়ালের গড় প্রতিবারই প্রকৃত কাউন্টের (৪৭) কাছাকাছি -- মেকানিজম unbiased।")

    
উপরের আউটপুটে দুটি জিনিস লক্ষ্য করুন। প্রথমত, প্রতিটি epsilon-এর "৫০০০-ট্রায়াল গড়" মান প্রকৃত কাউন্ট (৪৭)-এর অনেক কাছাকাছি — যদিও প্রতিটি একক single draw সেখান থেকে বেশ দূরে হতে পারে। এটাই দেখায় Laplace mechanism expectation-এ unbiased — গড়ে নয়েজ একে অপরকে কাটাকাটি করে ফেলে, কিন্তু কোনো একটি প্রকাশিত ফলাফল একাই নির্ভরযোগ্য নয় (এবং এটাই কাম্য — একটি একক প্রকাশিত সংখ্যা যদি নিখুঁতভাবে সঠিক হতো, তাহলে প্রাইভেসি-সুরক্ষা কার্যকরই হতো না)। দ্বিতীয়ত, ভ্যারিয়েন্সের কলামে epsilon=0.1-এর ভ্যারিয়েন্স epsilon=2.0-এর চেয়ে বহুগুণ বেশি — ছোট epsilon সরাসরি $b = \Delta f / \epsilon$ বড় করে দেয়, আর Laplace$(0,b)$-এর ভ্যারিয়েন্স হলো $2b^2$ — তাই ছোট epsilon গাণিতিকভাবেই বড় ভ্যারিয়েন্স বোঝায়, এবং উপরের কোড সেই সম্পর্কটি প্রকৃত সংখ্যা দিয়ে যাচাই করেছে।
মূল কথা · প্রাইভেসি-ইউটিলিটি ট্রেডঅফ

k-অ্যানোনিমিটি ও ডিফারেনশিয়াল প্রাইভেসি দুটোই একই মৌলিক ট্রেডঅফের ভিন্ন সমাধান — বেশি প্রাইভেসি সুরক্ষা মানেই কম তথ্য-নির্ভুলতা (বড় k মানে বড় গ্রুপ, অর্থাৎ কম গ্র্যানুলার তথ্য; ছোট epsilon মানে বেশি নয়েজ, অর্থাৎ কম নির্ভুল ফলাফল)। কোনো একক "সঠিক" মান নেই — বাস্তব ব্যবহারে k এবং epsilon নির্বাচন করা একটি নীতিগত সিদ্ধান্ত, যা ডেটার সংবেদনশীলতা ও ব্যবহারের প্রেক্ষাপটের উপর নির্ভর করে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ একজন ডেভেলপার বলছেন, "আমরা k-অ্যানোনিমিটি প্রয়োগ করেছি, তাই আমাদের ডেটাসেট সম্পূর্ণ নিরাপদ।" এই দাবির একটি সীমাবদ্ধতা কী হতে পারে?

k-অ্যানোনিমিটি শুধু নিশ্চিত করে যে একজন ব্যক্তিকে তার কুয়াসি-আইডেন্টিফায়ার দিয়ে অন্তত k জনের মধ্যে আলাদা করা যাবে না — কিন্তু যদি সেই k জনের সবারই একই sensitive attribute-এর মান থাকে (যেমন সবার একই রোগ নির্ণয়), তাহলে ব্যক্তিকে ঠিক শনাক্ত করতে না পারলেও তার sensitive তথ্য অনুমান করা যায় (একে "homogeneity attack" বলা হয়)। এই সীমাবদ্ধতা মোকাবেলার জন্য l-diversity, t-closeness-এর মতো আরও শক্তিশালী সম্প্রসারণ তৈরি হয়েছে, যা এই কোর্সের পরিসরের বাইরে।

প্র ০২ উপরের ডিফারেনশিয়াল-প্রাইভেসি কোডে যদি N_TRIALS ৫০০০ থেকে কমিয়ে মাত্র ৫ করা হতো, তাহলে "গড়" মান সম্পর্কে সিদ্ধান্তে কী প্রভাব পড়তো?

মাত্র ৫টি ট্রায়ালের গড় প্রকৃত মান থেকে উল্লেখযোগ্যভাবে দূরে থাকতে পারতো, বিশেষত ছোট epsilon-এ (বড় ভ্যারিয়েন্স) — কারণ গড়ের স্ট্যান্ডার্ড এরর ট্রায়াল-সংখ্যার বর্গমূলের সাথে ব্যস্তানুপাতিক ($SE \propto 1/\sqrt{n}$)। এটাই কারণ কোডে "unbiased" দাবিটি বহু ট্রায়াল (৫০০০) দিয়ে যাচাই করা হয়েছে, মাত্র কয়েকটি দিয়ে নয়।

প্র ০৩ একটি প্রতিষ্ঠান খুব বড় epsilon (যেমন 50) ব্যবহার করে বলছে, "আমরা ডিফারেনশিয়াল প্রাইভেসি ব্যবহার করি।" এই দাবি টেকনিক্যালি সত্য হলেও কেন এটি বিভ্রান্তিকর হতে পারে?

$b = \Delta f / \epsilon$ সূত্র অনুযায়ী, খুব বড় epsilon মানে $b$ প্রায় শূন্যের কাছাকাছি — অর্থাৎ নয়েজ এত ছোট যে প্রকাশিত ফলাফল প্রায় প্রকৃত মানেরই সমান হয়ে যায়, ফলে প্রকৃত প্রাইভেসি-সুরক্ষা প্রায় নেই বললেই চলে। "ডিফারেনশিয়াল প্রাইভেসি ব্যবহার করি" বলাটা অর্থহীন যদি না epsilon-এর মানও প্রকাশ করা হয় — এটাই দেখায় কেন শুধু টেকনিকের নাম নয়, তার প্যারামিটারও গুরুত্বপূর্ণ।

অনুশীলন

  1. চিন্তা করুন: k-অ্যানোনিমিটি কোড সেলে K-কে 3 থেকে 2-এ কমালে কতগুলো ক্লাস "VIOLATION" হিসেবে ফ্ল্যাগ হবে বলে আপনার ধারণা?

    K=2 করলে ভায়োলেশনের সংখ্যা কমবে না বাড়বে না, বরং কমবে অথবা একই থাকবে — কারণ k কমানো মানে থ্রেশহোল্ড শিথিল করা। বর্তমান ডেটাসেটে সব ভায়োলেটিং ক্লাসের সাইজ ঠিক ১ (id 6, 7, 8, 10), যা এখনও K=2-এর চেয়ে কম, তাই সবগুলোই তখনও ভায়োলেশন থেকে যাবে — শুধু K=1 করলেই সব ভায়োলেশন অদৃশ্য হয়ে যেত।

  2. পরীক্ষা করুন: ডিফারেনশিয়াল-প্রাইভেসি কোড সেলে epsilons তালিকায় একটি নতুন মান 1.0 যোগ করে Run চেপে দেখুন এর ভ্যারিয়েন্স তালিকার অন্য তিনটি মানের মধ্যে কোথায় বসে।

    epsilon=1.0-এর ভ্যারিয়েন্স epsilon=0.5 ও epsilon=2.0-এর মাঝামাঝি বসা উচিত — কারণ ভ্যারিয়েন্স $2b^2 = 2(\text{sensitivity}/\epsilon)^2$ সূত্র অনুযায়ী epsilon বাড়ার সাথে সাথে মসৃণভাবে (তবে নন-লিনিয়ারভাবে, বর্গাকারে) কমতে থাকে। এটি নিশ্চিত করে যে সম্পর্কটি শুধু দুটি প্রান্তিক বিন্দুতে নয়, পুরো রেঞ্জ জুড়ে সত্য।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ নৈতিক ফ্রেমওয়ার্ক, বায়াস-ফেয়ারনেস, প্রাইভেসি, ট্রান্সপারেন্সি, AI অ্যালাইনমেন্ট, জেনারেটিভ AI/LLM এথিক্স, সামাজিক প্রভাব, গভর্নেন্স ও রেগুলেশন, সেক্টর-স্পেসিফিক এথিক্স ও এক্সিস্টেনশিয়াল রিস্ক বিতর্ক — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
  • Ethics in Computing & AI Safety কোর্স সহোদর কোর্স সাধারণ কম্পিউটিং এথিক্স, প্রফেশনাল এথিক্স ও সেফটি-ক্রিটিক্যাল কেস স্টাডির একটি বিস্তৃত সার্ভে — এই কোর্স সম্পূর্ণভাবে AI-তে ফোকাস করে গভীরে যায়।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, Machine Learning, Deep Learning, System Design, Cybersecurity, Cloud Computing & DevOps, এবং আরও অনেক কোর্স — সব এক জায়গায়।
আগের পাঠ
কনসেন্ট, ডেটা মিনিমাইজেশন ও পারপাস লিমিটেশন