পাঠ ১০ · ৫৭-এর মধ্যে · মডিউল ৩
Home / AI Courses / AI Ethics / ফেয়ারনেস মেট্রিক্স

ফেয়ারনেস মেট্রিক্স — ডেমোগ্রাফিক প্যারিটি ও ইকুয়ালাইজড অডস

Fairness metrics: demographic parity & equalized odds
১১ মিনিট পড়া মধ্যম-কঠিন · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

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

  • প্রতি-গ্রুপ কনফিউশন ম্যাট্রিক্স (TP/FP/FN/TN) কী এবং কীভাবে তৈরি হয়
  • ডেমোগ্রাফিক প্যারিটির সংজ্ঞা ও ফর্মুলা
  • ইকুয়ালাইজড অডস (TPR ও FPR) এর সংজ্ঞা ও ফর্মুলা
  • ক্যালিব্রেশনের সংজ্ঞা ও ফর্মুলা
  • একটি সম্পূর্ণ, পুনর্ব্যবহারযোগ্য ফেয়ারনেস-মেট্রিক্স ক্যালকুলেটর সত্যিকারের ডেটার উপর রান করা

১ · কেন ফরমাল মেট্রিক্স দরকার

L01 ও L09-এর ডেমোতে আমরা "গ্রুপ A-এর সিলেকশন রেট গ্রুপ B-এর চেয়ে X পার্সেন্টেজ পয়েন্ট বেশি" — এভাবে একটি একক তুলনা দেখেছি। কিন্তু বাস্তব ফেয়ারনেস অডিটে শুধু "কতজনকে সিলেক্ট করা হলো" যথেষ্ট নয় — একটি মডেল একাধিকভাবে "অন্যায্য" হতে পারে, এবং এই ভিন্ন ভিন্ন ধরনের অন্যায্যতা একে অপর থেকে গাণিতিকভাবে আলাদা। তাই ফেয়ারনেস গবেষণায় কয়েকটি সুনির্দিষ্ট, ফরমালি সংজ্ঞায়িত মেট্রিক্স ব্যবহার করা হয় — যার প্রতিটি একটি প্রতি-গ্রুপ কনফিউশন ম্যাট্রিক্স থেকে গণনা করা হয়।

২ · কনফিউশন ম্যাট্রিক্স রিক্যাপ — প্রতি গ্রুপে

একটি বাইনারি প্রেডিকশন মডেলের (যেমন "high-risk" বনাম "low-risk", "সিলেক্ট" বনাম "রিজেক্ট") প্রতিটি সিদ্ধান্ত চারটি ভাগের একটিতে পড়ে — এবং আমরা এই চারটি সংখ্যা প্রতিটি গ্রুপের জন্য আলাদাভাবে গণনা করি:

প্রকৃত = পজিটিভ (আসলে outcome ঘটেছে) প্রকৃত = নেগেটিভ (আসলে outcome ঘটেনি) প্রেডিক্ট + প্রেডিক্ট − TP সঠিকভাবে পজিটিভ শনাক্ত FP ভুলভাবে পজিটিভ শনাক্ত FN ভুলভাবে নেগেটিভ শনাক্ত TN সঠিকভাবে নেগেটিভ শনাক্ত
প্রতিটি গ্রুপের জন্য আলাদা TP/FP/FN/TN গণনা করা হয় — গাঢ় বক্স দুটি (FP, FN) মডেলের ভুল প্রতিনিধিত্ব করে।

৩ · ডেমোগ্রাফিক প্যারিটি (Demographic Parity)

একটি গ্রুপের কতজনকে মডেল "পজিটিভ" (যেমন high-risk, অথবা সিলেক্টেড) হিসেবে প্রেডিক্ট করেছে, সেই হার — যদি এই হার সব গ্রুপে সমান হয়, ডেমোগ্রাফিক প্যারিটি সন্তুষ্ট হয়েছে বলা হয়:

$$P(\hat{Y}=1 \mid A=a) = \frac{TP_a + FP_a}{TP_a+FP_a+FN_a+TN_a}$$

এখানে $\hat{Y}=1$ মানে মডেল পজিটিভ প্রেডিক্ট করেছে, এবং $A=a$ মানে ব্যক্তিটি গ্রুপ $a$-এর সদস্য। L01 ও L09-এর ডেমোতে আমরা যা গণনা করেছিলাম (selection rate / high-premium rate), তা আসলে ডেমোগ্রাফিক প্যারিটিরই একটি উদাহরণ ছিল।

৪ · ইকুয়ালাইজড অডস (Equalized Odds)

ডেমোগ্রাফিক প্যারিটি শুধু "কতজনকে পজিটিভ বলা হলো" তা দেখে — এটি প্রকৃত ফলাফল (actual outcome) বিবেচনা করে না। ইকুয়ালাইজড অডস এক ধাপ গভীরে যায়: এটি দাবি করে যে প্রকৃতপক্ষে পজিটিভ এমন মানুষদের মধ্যে সঠিকভাবে শনাক্ত হওয়ার হার (True Positive Rate) এবং প্রকৃতপক্ষে নেগেটিভ এমন মানুষদের মধ্যে ভুলভাবে পজিটিভ বলার হার (False Positive Rate) — দুটোই সব গ্রুপে সমান হতে হবে:

$$TPR_a = \frac{TP_a}{TP_a+FN_a}, \qquad FPR_a = \frac{FP_a}{FP_a+TN_a}$$

এর মানে, শুধু "কতজন পজিটিভ পেল" নয়, বরং "প্রকৃতপক্ষে যারা positive/negative, তাদের সাথে মডেলের আচরণ একইরকম কি না" — এটি ইকুয়ালাইজড অডস মাপে।

৫ · ক্যালিব্রেশন (Calibration)

ক্যালিব্রেশন প্রশ্নটি উল্টো দিক থেকে জিজ্ঞাসা করে: যাদের মডেল "পজিটিভ" (high-risk) বলে প্রেডিক্ট করেছে, তাদের মধ্যে প্রকৃতপক্ষে কত শতাংশ সত্যিই পজিটিভ (outcome ঘটেছে)? এটি হলো predicted-positive-দের মধ্যে Positive Predictive Value (PPV):

$$P(Y=1 \mid \hat{Y}=1, A=a) = \frac{TP_a}{TP_a+FP_a}$$

যদি এই হার সব গ্রুপে সমান হয় — অর্থাৎ "high-risk" ট্যাগের প্রকৃত অর্থ প্রতিটি গ্রুপে একইরকম নির্ভরযোগ্য হয় — মডেলকে ক্যালিব্রেটেড বলা হয়। L11-এ আমরা দেখব একটি মডেল ক্যালিব্রেটেড হওয়া সত্ত্বেও ইকুয়ালাইজড অডস ভাঙতে পারে — এবং এটিই ২০১৬ সালের COMPAS/ProPublica বিতর্কের মূল কেন্দ্রবিন্দু।

৬ · সম্পূর্ণ ক্যালকুলেটর — সত্যিকারের ডেটার উপর

নিচের কোডে দুটি গ্রুপের জন্য সিন্থেটিক আবেদনকারীর ডেটা তৈরি করা হয়েছে — প্রকৃত ঋণ-খেলাপির (default) হার দুই গ্রুপেই প্রায় সমান (৩৫%) রাখা হয়েছে, কিন্তু মডেলের স্কোরে গ্রুপ A-এর জন্য একটি ইচ্ছাকৃত সিস্টেমেটিক বায়াস (bias_shift) যোগ করা হয়েছে — L09-এর মতোই একটি ফিচার-ভিত্তিক বায়াস কল্পনা করুন যা এই শিফটের পেছনে থাকতে পারে। এরপর একটি একক থ্রেশহোল্ডে প্রেডিকশন করে, প্রতি-গ্রুপ কনফিউশন ম্যাট্রিক্স বানিয়ে তিনটি মেট্রিক্স-ই সত্যিই গণনা করা হচ্ছে।

Python
import random
random.seed(3)

def generate_group(n, group, bias_shift):
    people = []
    for _ in range(n):
        actual = 1 if random.random() < 0.35 else 0  # প্রকৃত বেস রেট উভয় গ্রুপেই সমান (৩৫%)
        base_score = random.gauss(0.62, 0.15) if actual == 1 else random.gauss(0.38, 0.15)
        score = max(0.0, min(1.0, base_score + bias_shift))  # bias_shift: মডেল স্কোরে সিস্টেমেটিক শিফট
        people.append({"group": group, "actual": actual, "score": score})
    return people

group_a = generate_group(500, "A", bias_shift=0.10)   # গ্রুপ A-এর স্কোরে +0.10 সিস্টেমেটিক বায়াস
group_b = generate_group(500, "B", bias_shift=0.0)    # গ্রুপ B-এর স্কোরে কোনো বায়াস নেই

THRESHOLD = 0.5
def predict(p):
    return 1 if p["score"] >= THRESHOLD else 0

for p in group_a + group_b:
    p["predicted"] = predict(p)

def confusion_matrix(people):
    cm = {"TP": 0, "FP": 0, "FN": 0, "TN": 0}
    for p in people:
        if p["predicted"] == 1 and p["actual"] == 1: cm["TP"] += 1
        elif p["predicted"] == 1 and p["actual"] == 0: cm["FP"] += 1
        elif p["predicted"] == 0 and p["actual"] == 1: cm["FN"] += 1
        else: cm["TN"] += 1
    return cm

cm_a = confusion_matrix(group_a)
cm_b = confusion_matrix(group_b)

def fairness_metrics(cm):
    TP, FP, FN, TN = cm["TP"], cm["FP"], cm["FN"], cm["TN"]
    total = TP + FP + FN + TN
    predicted_positive = TP + FP
    actual_positive = TP + FN
    actual_negative = FP + TN
    return {
        "demographic_parity": predicted_positive / total,
        "tpr": TP / actual_positive if actual_positive else 0,
        "fpr": FP / actual_negative if actual_negative else 0,
        "calibration_ppv": TP / predicted_positive if predicted_positive else 0,
    }

m_a = fairness_metrics(cm_a)
m_b = fairness_metrics(cm_b)

print("গ্রুপ A কনফিউশন ম্যাট্রিক্স:", cm_a)
print("গ্রুপ B কনফিউশন ম্যাট্রিক্স:", cm_b)
print()
print(f"ডেমোগ্রাফিক প্যারিটি (predicted-positive rate) -- A: {m_a['demographic_parity']*100:.1f}%,  B: {m_b['demographic_parity']*100:.1f}%")
print(f"True Positive Rate (TPR)                        -- A: {m_a['tpr']*100:.1f}%,  B: {m_b['tpr']*100:.1f}%")
print(f"False Positive Rate (FPR)                        -- A: {m_a['fpr']*100:.1f}%,  B: {m_b['fpr']*100:.1f}%")
print(f"ক্যালিব্রেশন (predicted-positive-দের মধ্যে প্রকৃত পজিটিভের হার) -- A: {m_a['calibration_ppv']*100:.1f}%,  B: {m_b['calibration_ppv']*100:.1f}%")

    
কোডটি রান করলে দেখা যায় দুই গ্রুপের প্রকৃত ডিফল্ট রেট প্রায় সমান (A ~৩৪.৪%, B ~৩২.২% — শুধু র‍্যান্ডম স্যাম্পলিং ভ্যারিয়েশন), অথচ bias_shift-এর কারণে ডেমোগ্রাফিক প্যারিটি (A ~৬৪%, B ~৪১%), TPR (A ~৯৪%, B ~৮১%), FPR (A ~৪৯%, B ~২২%), এবং ক্যালিব্রেশন (A ~৫০%, B ~৬৩%) — চারটি মেট্রিক্সই উল্লেখযোগ্যভাবে ভিন্ন। এটি দেখায় গ্যাপের উৎস প্রকৃত ঝুঁকিতে নয়, বরং মডেলের স্কোরিং প্রক্রিয়ায়।
মূল কথা · Key takeaway

একটি মডেল একইসাথে একাধিক ফেয়ারনেস মেট্রিক্সে "ব্যর্থ" হতে পারে, অথবা একটিতে পাস করে অন্যটিতে ফেল করতে পারে — এই তিনটি মেট্রিক্স ভিন্ন ভিন্ন প্রশ্নের উত্তর দেয় ("কতজনকে পজিটিভ বলা হলো?", "প্রকৃত পজিটিভ/নেগেটিভদের সাথে আচরণ কি সমান?", "পজিটিভ ট্যাগের অর্থ কি সব গ্রুপে সমান নির্ভরযোগ্য?")। L11-এ আমরা দেখব বাস্তব-বিশ্বের COMPAS বিতর্কে ঠিক এই তিনটি মেট্রিক্সের মধ্যে কীভাবে সংঘাত তৈরি হয়েছিল, এবং L13-এ দেখব কেন এই সংঘাত এড়ানো গাণিতিকভাবে প্রায়ই অসম্ভব।

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

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

প্র ০১ শুধু সামগ্রিক (overall) অ্যাকুরেসি দেখে কেন ফেয়ারনেস বিচার করা যথেষ্ট নয়? প্রতি-গ্রুপ মেট্রিক্স কেন দরকার?

একটি মডেল সামগ্রিকভাবে ৯০% অ্যাকুরেট হতে পারে, অথচ সেই ১০% ভুল প্রায় সবটাই একটি নির্দিষ্ট গ্রুপের উপর কেন্দ্রীভূত থাকতে পারে — সামগ্রিক সংখ্যা এই অসমতা সম্পূর্ণ লুকিয়ে ফেলে। প্রতি-গ্রুপ কনফিউশন ম্যাট্রিক্স ছাড়া এই ধরনের গ্যাপ ধরাই পড়বে না।

প্র ০২ ডেমোতে দুই গ্রুপের প্রকৃত ডিফল্ট রেট (base rate) প্রায় সমান, তবুও চারটি মেট্রিক্সই ভিন্ন — এটি গ্যাপের উৎস সম্পর্কে কী বলে?

যেহেতু প্রকৃত ঝুঁকি (base rate) প্রায় সমান, গ্যাপটি প্রকৃত অন্তর্নিহিত পার্থক্য থেকে আসছে না — এটি সরাসরি মডেলের স্কোরিং প্রক্রিয়ায় যোগ করা bias_shift থেকে আসছে। এটি L09-এর ধারণাটিই আবার নিশ্চিত করে: গ্যাপ দেখেই বলা যায় না এটি "প্রকৃত ঝুঁকির পার্থক্য" নাকি "মডেলের বায়াস" — এজন্যই বেস রেট আলাদাভাবে পরীক্ষা করাটা জরুরি (L11-এ আরও গভীরে যাব)।

প্র ০৩ একটি মডেল কি ডেমোগ্রাফিক প্যারিটি সন্তুষ্ট করেও ইকুয়ালাইজড অডসে ব্যর্থ হতে পারে? ধারণাগতভাবে ব্যাখ্যা করুন।

হ্যাঁ। ডেমোগ্রাফিক প্যারিটি শুধু "কতজনকে পজিটিভ বলা হলো" (predicted-positive rate) সমান কি না তা দেখে — এটি প্রকৃত ফলাফল বিবেচনায় নেয় না। একটি মডেল দুই গ্রুপেই সমান সংখ্যক মানুষকে পজিটিভ বললেও, কোন নির্দিষ্ট ব্যক্তিদের ভুল করে পজিটিভ/নেগেটিভ বলছে তা গ্রুপভেদে ভিন্ন হতে পারে — অর্থাৎ TPR/FPR ভিন্ন হতে পারে, যদিও predicted-positive rate সমান। এই দুই মেট্রিক্স স্বাধীন প্রশ্নের উত্তর দেয়।

অনুশীলন

  1. চিন্তা করুন: উপরের কোড সেলে গ্রুপ A-এর bias_shift-কে 0.10 থেকে 0.0-এ পরিবর্তন করলে (অর্থাৎ দুই গ্রুপেই কোনো বায়াস না থাকলে) চারটি মেট্রিক্সের গ্যাপ কেমন হবে বলে আপনার ধারণা?

    যেহেতু দুই গ্রুপের প্রকৃত ডিফল্ট রেট ও স্কোর-জেনারেশন প্রক্রিয়া তখন সম্পূর্ণ অভিন্ন হয়ে যাবে, চারটি মেট্রিক্সের গ্যাপই শূন্যের কাছাকাছি চলে আসবে — শুধু র‍্যান্ডম স্যাম্পলিং-এর কারণে সামান্য ওঠানামা থাকতে পারে।

  2. পরীক্ষা করুন: উপরের কোড সেলে bias_shift=0.10-কে bias_shift=0.0-এ পরিবর্তন করে Run চেপে আপনার অনুমান যাচাই করুন।

    পরিবর্তনের পর গ্রুপ A ও B-এর ডেটা-জেনারেশন প্রক্রিয়া অভিন্ন হয়ে যায়, ফলে চারটি মেট্রিক্সই (ডেমোগ্রাফিক প্যারিটি, TPR, FPR, ক্যালিব্রেশন) দুই গ্রুপে প্রায় সমান হয়ে আসে — এটি নিশ্চিত করে যে গ্যাপের একমাত্র উৎস ছিল bias_shift, প্রকৃত ডেটা জেনারেশন প্রক্রিয়া নয়।

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

  • পরবর্তী পাঠ L11 কেস স্টাডি — COMPAS ও রিসিডিভিজম প্রেডিকশন — ২০১৬ সালের ProPublica তদন্ত ও এই পাঠের ক্যালকুলেটর দিয়ে সমান ক্যালিব্রেশন সত্ত্বেও ভিন্ন FPR/FNR-এর একটি সত্যিকারের কম্পিউটেড উদাহরণ।
  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ নৈতিক ফ্রেমওয়ার্ক, বায়াস-ফেয়ারনেস, প্রাইভেসি, ট্রান্সপারেন্সি, AI অ্যালাইনমেন্ট, জেনারেটিভ AI/LLM এথিক্স, সামাজিক প্রভাব, গভর্নেন্স ও রেগুলেশন, সেক্টর-স্পেসিফিক এথিক্স ও এক্সিস্টেনশিয়াল রিস্ক বিতর্ক।
  • Machine Learning কোর্স প্রাসঙ্গিক ফাউন্ডেশন মডেল ট্রেনিং, থ্রেশহোল্ড, স্কোরিং-এর কারিগরি বিস্তারিত এই কোর্সে কভার করা হয়েছে।
আগের পাঠ
বায়াস কোথা থেকে আসে — ডেটা, মডেল, ডিপ্লয়মেন্ট