অধ্যায় 2 · ন্যায্যতা ও ডেটা
টয় ডেটায় ন্যায্যতার মেট্রিক: Python-এ সিলেকশন রেট ও এরর রেট
- পৃষ্ঠা 5 / 22
- 16 মিনিট পড়া
এই টিউটোরিয়ালের প্রথম পাতাগুলোর রিস্ক রেজিস্টারে এমন সব দাবি আছে, যেমন "স্কোরটা কর্মবিরতিকে শাস্তি দেয়"। এই ধরনের দাবি পরীক্ষা করা যায়। এই পাতা দ্বিতীয় অধ্যায় ন্যায্যতা ও ডেটা-র শুরু: আপনি কাল্পনিক সিদ্ধান্তের একটা ছোট টেবিল বানাবেন এবং প্রতিটা গ্রুপের জন্য হিসাব করবেন কারা নির্বাচিত হচ্ছেন, কারা ভুলভাবে নির্বাচিত হচ্ছেন, আর কারা বাদ পড়ছেন। সঙ্গে শিখবেন এই সংখ্যাগুলো কী বলতে পারে না।
আপনার দরকার Python 3.12, শুধু স্ট্যান্ডার্ড লাইব্রেরি। ব্লকগুলো ক্রমে একটা সেশনে লিখুন; এগুলো ভেরিয়েবল ভাগ করে নেয়, আর প্রতিটা ব্লকের নিচের লেখাটা তার আসল আউটপুট।
সততার নিয়ম। ডেটাসেটটা কৃত্রিম এবং
Toy data:লেবেল দেওয়া; প্রতিটা মানুষ, গ্রুপ ও সংখ্যা কাল্পনিক। ফলাফল শুধু দেখায় একটা হিসাব কীভাবে কাজ করে। এগুলো কোনো বাস্তব সিস্টেম বা বাস্তব মানুষের দলের প্রমাণ নয়।
যা শিখবেন
- কোনো হিসাব করার আগে সিদ্ধান্ত, ফলাফল ও তুলনার গ্রুপ কীভাবে ঠিক করবেন, আর সুরক্ষিত বৈশিষ্ট্য ও প্রক্সি ভেরিয়েবলের জন্য কেন আলাদা পরীক্ষা লাগে।
- লেবেল, পূর্বাভাস ও পর্যবেক্ষিত ফলাফল কীভাবে আলাদা রাখবেন, এবং শুধু ফলাফল দেখলে কী হারিয়ে যায়।
- প্রতিটা গ্রুপের জন্য সিলেকশন রেট, ফলস-পজিটিভ ও ফলস-নেগেটিভ রেট, নির্ভুলতা, প্রিসিশন ও রিকল কীভাবে হিসাব করবেন।
- ডেমোগ্রাফিক প্যারিটি, ইকুয়াল অপরচুনিটি ও ইকুয়ালাইজড ওডসের পার্থক্য কীভাবে হিসাব করবেন, আর কেন একটা ফারাক রায় নয়।
- টেবিলের ওপর ন্যায্যতার মেট্রিক কী বলতে পারে আর কী পারে না।
সিদ্ধান্ত, ফলাফল ও গ্রুপ ঠিক করুন
আগে সিদ্ধান্ত, ফলাফল ও তুলনার গ্রুপ ঠিক করুন। একটা ন্যায্যতার মেট্রিক নির্দিষ্ট একটা সিদ্ধান্ত (টুল কী ঠিক করে), একটা ইতিবাচক ফলাফল (কোনটা সঠিক বা ভালো ফল) এবং তুলনার গ্রুপ (কার সঙ্গে কার তুলনা) সম্পর্কে একটা প্রশ্নের উত্তর দেয়। তিনটার যেকোনোটা বদলালে সংখ্যার অর্থ বদলে যায়।
কাল্পনিক পরিস্থিতি:
Feature: ShortlistHelper, the screening feature from page 1, tested on 40 past applicants.
Decision: shortlisted (1) or not (0). It matters because a person only reads shortlisted CVs.
Positive: "judged suitable in a later full review of every CV" (this is the label).
Groups: A and B, placeholders for any comparison attribute that fits your context.
Reference: group A, because it is larger. A convenience, not a ranking of the groups.
Question: do the tool's decisions and errors fall equally on both groups?এখানে দুটো বাছাই মানুষের সিদ্ধান্ত, তথ্য নয়। ইতিবাচক ফলাফল হলো পর্যালোচকদের বিচার। রেফারেন্স গ্রুপ শুধু হিসাবের সুবিধার জন্য: প্রতিটা পার্থক্য "গ্রুপ বিয়োগ রেফারেন্স", তাই চিহ্ন দেখে দিক বোঝা যায়। কে গ্রুপ ঠিক করবেন, আর বৈশিষ্ট্যটা আপনার কাছে রাখা যায় কি না, সেসব প্রশ্ন আপনার আইনি বা গোপনীয়তা-দায়িত্বপ্রাপ্ত ব্যক্তির জন্য; এই পাতা শুধু হিসাবটা দেখায়।
টয় ডেটাসেট বানান
গ্রুপ লেবেলসহ একটা ছোট কৃত্রিম ডেটাসেট বানান। টেবিলটা গণনা থেকে বানানো, তাই প্রতিটা সংখ্যা হাতে যাচাই করা যায়। প্রতিটা ঘর বলে: গ্রুপ, লেবেল, পূর্বাভাস, কতজন মানুষ, আর তাঁদের মধ্যে কতজনের কর্মবিরতি ছিল।
টয় ডেটা: ৪০ জন কাল্পনিক আবেদনকারী।
# Toy data: 40 invented past applicants. label = judged suitable in a later full review (1/0),
# pred = shortlisted by the tool (1/0). Group A and B are placeholders for any comparison groups.
CELLS = [ # (group, label, pred, how many people, how many of them had a career break)
("A", 1, 1, 9, 0), ("A", 1, 0, 3, 1), ("A", 0, 1, 3, 0), ("A", 0, 0, 9, 3),
("B", 1, 1, 3, 1), ("B", 1, 0, 3, 3), ("B", 0, 1, 1, 0), ("B", 0, 0, 9, 6),
]
def build(cells):
rows = []
for group, label, pred, n, breaks in cells:
for k in range(n):
rows.append({"group": group, "label": label, "pred": pred,
"career_break": "yes" if k < breaks else "no"})
return rows
ROWS = build(CELLS)
print(len(ROWS), "rows")
for g in sorted({r["group"] for r in ROWS}):
sub = [r for r in ROWS if r["group"] == g]
print(f"group {g}: {len(sub)} people, {sum(r['label'] for r in sub)} suitable, "
f"{sum(r['pred'] for r in sub)} shortlisted")
print(ROWS[0], ROWS[-1], sep="\n")40 rows
group A: 24 people, 12 suitable, 12 shortlisted
group B: 16 people, 6 suitable, 4 shortlisted
{'group': 'A', 'label': 1, 'pred': 1, 'career_break': 'no'}
{'group': 'B', 'label': 0, 'pred': 0, 'career_break': 'no'}গ্রুপ A-তে উপযুক্ত ১২ জন এবং শর্টলিস্ট ১২ জন। গ্রুপ B-তে উপযুক্ত ৬ জন এবং শর্টলিস্ট ৪ জন। আকারই এখানে অসমান, যা পরে গুরুত্বপূর্ণ হবে।
সুরক্ষিত বৈশিষ্ট্য ও প্রক্সি ভেরিয়েবল
সুরক্ষিত বৈশিষ্ট্য আর প্রক্সি ভেরিয়েবলের পার্থক্য করুন। সুরক্ষিত বৈশিষ্ট্য (protected attribute) হলো এমন বৈশিষ্ট্য, যা নৈতিক বা আইনি কারণে অন্যায্য আচরণের ভিত্তি হওয়া উচিত নয় বলে আপনি ঠিক করেছেন; কোনগুলো গণ্য হবে তা স্থান ও খাতের ওপর নির্ভর করে, তাই জিজ্ঞেস করে নিন। প্রক্সি ভেরিয়েবল হলো সাধারণ চেহারার এমন ইনপুট, যা ওই বৈশিষ্ট্য সম্পর্কে তথ্য বহন করে। গ্রুপ কলাম মুছে দিলেও প্রক্সি থেকে গেলে সমস্যা যায় না। পরীক্ষা করুন: প্রক্সি থেকে গ্রুপ ফিরে পাওয়া যায় কি না, আর প্রক্সির মান অনুযায়ী সিদ্ধান্ত আলাদা হয় কি না?
def count(rows, **match):
return sum(all(r[k] == v for k, v in match.items()) for r in rows)
for g in ("A", "B"):
print(f"group {g}: career break {count(ROWS, group=g, career_break='yes')} of {count(ROWS, group=g)}")
guess = sum((r["career_break"] == "yes") == (r["group"] == "B") for r in ROWS)
print("group recovered from career_break alone:", guess, "of", len(ROWS))
print("always guessing A would be right for:", count(ROWS, group="A"))
for v in ("yes", "no"):
n, chosen = count(ROWS, career_break=v), count(ROWS, career_break=v, pred=1)
print(f"career break {v:<3}: {n} people, {chosen} shortlisted, {count(ROWS, career_break=v, label=1)} suitable")group A: career break 4 of 24
group B: career break 10 of 16
group recovered from career_break alone: 30 of 40
always guessing A would be right for: 24
career break yes: 14 people, 1 shortlisted, 5 suitable
career break no : 26 people, 15 shortlisted, 13 suitableশুধু career_break দিয়ে ৪০ জনের মধ্যে ৩০ জনের গ্রুপ ঠিক ধরা যায়; সবসময় A অনুমান করলে ঠিক হয় ২৪ জনের। তাই প্রক্সিটা গ্রুপের তথ্য ফাঁস করে। আর কর্মবিরতি থাকা ১৪ জনের মধ্যে শর্টলিস্ট হয়েছেন ১ জন, বাকিদের ২৬ জনের মধ্যে ১৫ জন, যদিও ওই ১৪ জনের ৫ জন উপযুক্ত। এতে প্রমাণ হয় না যে টুল প্রক্সিটা ব্যবহার করে, বা প্রক্সিটা অন্যায্য। এটা শুধু বলে: খুঁজে দেখুন। আর কর্মবিরতি নিয়ে রেজিস্টারের ঝুঁকিটার পেছনে এখন একটা সংখ্যা আছে।
লেবেল, পূর্বাভাস ও পর্যবেক্ষিত ফলাফল
লেবেল, পূর্বাভাস ও পর্যবেক্ষিত ফলাফল আলাদা রাখুন। "সঠিক" শব্দটার পেছনে তিনটা আলাদা জিনিস লুকিয়ে থাকে।
label what we treat as correct "suitable" in a later review (a human judgement)
prediction what the tool said "shortlisted" or not
observed outcome what happened afterwards "hired and did well", known only for some peopleপ্রতিটা তার নিজের ধরনে ভুল হতে পারে। অতীতের নিয়োগ-সিদ্ধান্ত থেকে বানানো লেবেল সেই সিদ্ধান্তগুলোই পুনরাবৃত্তি করে, ন্যায্য হোক বা না হোক। পূর্বাভাস নির্ভর করে কারও বেছে নেওয়া থ্রেশহোল্ডের ওপর। পর্যবেক্ষিত ফলাফল থাকে শুধু নির্বাচিত মানুষদের, তাই কারা ভুলভাবে বাদ পড়ল তা এটা দেখাতে পারে না। প্রতিটা মেট্রিকের ভিত্তি হলো গ্রুপ-ভিত্তিক গণনা: ট্রু পজিটিভ (tp: উপযুক্ত ও শর্টলিস্ট), ফলস নেগেটিভ (fn: উপযুক্ত, শর্টলিস্ট নয়), ফলস পজিটিভ (fp: অনুপযুক্ত, শর্টলিস্ট) এবং ট্রু নেগেটিভ (tn)।
| রেট | গণনা থেকে সূত্র | কী জানতে চায় |
|---|---|---|
| সিলেকশন রেট | (tp + fp) / সবাই | টুল কতজনকে নির্বাচন করে? |
| ট্রু-পজিটিভ রেট (tpr, রিকল) | tp / (tp + fn) | উপযুক্তদের কতজন নির্বাচিত হন? |
| ফলস-নেগেটিভ রেট (fnr) | fn / (tp + fn) | উপযুক্তদের কতজন বাদ পড়েন? |
| ফলস-পজিটিভ রেট (fpr) | fp / (fp + tn) | অনুপযুক্তদের কতজন নির্বাচিত হন? |
| নির্ভুলতা (accuracy) | (tp + tn) / সবাই | সিদ্ধান্ত কতবার ঠিক হয়? |
| প্রিসিশন (precision) | tp / (tp + fp) | নির্বাচিতদের কতজন উপযুক্ত? |
এই ছোট সহায়ক ফাইলটা তৈরি করুন। পরের সব সূত্র একে ডাকে। রেটগুলো দুই দশমিক পর্যন্ত ছাপা হয়; ০.০১-এর কম পার্থক্য চোখে পড়ে না।
# file: fair.py
from collections import Counter
NAMES = {(1, 1): "tp", (1, 0): "fn", (0, 1): "fp", (0, 0): "tn"} # (label, pred)
def confusion(rows, group=None):
c = Counter(NAMES[r["label"], r["pred"]] for r in rows if group in (None, r["group"]))
return {k: c[k] for k in ("tp", "fn", "fp", "tn")}
def ratio(top, bottom):
return top / bottom if bottom else None # None means undefined, never 0
def rates(c):
n, pos, neg, chosen = sum(c.values()), c["tp"] + c["fn"], c["fp"] + c["tn"], c["tp"] + c["fp"]
return {"n": n, "selection": ratio(chosen, n), "tpr": ratio(c["tp"], pos), "fnr": ratio(c["fn"], pos),
"fpr": ratio(c["fp"], neg), "accuracy": ratio(c["tp"] + c["tn"], n),
"precision": ratio(c["tp"], chosen), "recall": ratio(c["tp"], pos)}
def by_group(rows):
stats = {g: rates(confusion(rows, g)) for g in sorted({r["group"] for r in rows})}
stats["all"] = rates(confusion(rows))
return stats
def fmt(x, signed=False):
return "n/a" if x is None else f"{x:+.2f}" if signed else f"{x:.2f}"
def show(stats, keys):
print(f"{'group':<7}" + "".join(f"{k:>11}" for k in keys))
for g, s in stats.items():
print(f"{g:<7}" + "".join(f"{s[k] if k == 'n' else fmt(s[k]):>11}" for k in keys))
def diff(stats, key, ref):
"""Each group minus the reference group; None when either side is undefined."""
return {g: None if None in (s[key], stats[ref][key]) else s[key] - stats[ref][key]
for g, s in stats.items() if g not in (ref, "all")}ratio-র দিকে লক্ষ্য করুন: কোনো রেটের ভাগ করার মতো কিছু না থাকলে উত্তর None, যা n/a হিসেবে দেখায়। যে গ্রুপে কোনো উপযুক্ত মানুষ নেই, তার ট্রু-পজিটিভ রেট অনির্ধারিত, শূন্য নয়।
from fair import confusion
for g in ("A", "B", None):
print(g or "all", confusion(ROWS, g))
shown = [r for r in ROWS if r["pred"] == 1]
print("outcome seen only for the shortlisted:", len(shown), "of", len(ROWS))
print("suitable people the tool missed, invisible to an outcomes-only audit:",
sum(r["label"] == 1 and r["pred"] == 0 for r in ROWS))A {'tp': 9, 'fn': 3, 'fp': 3, 'tn': 9}
B {'tp': 3, 'fn': 3, 'fp': 1, 'tn': 9}
all {'tp': 12, 'fn': 6, 'fp': 4, 'tn': 18}
outcome seen only for the shortlisted: 16 of 40
suitable people the tool missed, invisible to an outcomes-only audit: 6যে অডিট শুধু ফলাফল দেখে, সে ১৬ জনকে দেখবে এবং টুল যে ৬ জন উপযুক্ত মানুষকে বাদ দিয়েছে তাঁদের কখনো দেখবে না।
সিলেকশন রেট
গ্রুপ-পর্যায়ের সিলেকশন রেট হিসাব করুন। সিলেকশন রেট হলো গ্রুপের যে অংশকে টুল নির্বাচন করে। এটা লেবেল পুরোপুরি উপেক্ষা করে।
from fair import by_group, show
stats = by_group(ROWS)
show(stats, ["n", "selection"])group n selection
A 24 0.50
B 16 0.25
all 40 0.40গ্রুপ A নির্বাচিত হয় ০.৫০ হারে, গ্রুপ B ০.২৫ হারে। "all" সারির (০.৪০) গড়টা এই ফারাক লুকিয়ে রাখে।
ফলস-পজিটিভ ও ফলস-নেগেটিভ রেট
ফলস-পজিটিভ ও ফলস-নেগেটিভ রেট হিসাব করুন। ফলস-পজিটিভ রেট (fpr) হলো সত্যিই অনুপযুক্তদের যে অংশ শর্টলিস্ট হয়; ফলস-নেগেটিভ রেট (fnr) হলো সত্যিই উপযুক্তদের যে অংশ শর্টলিস্ট হয় না। কোন ভুলটা ক্ষতি করে তা সিদ্ধান্তের ওপর নির্ভর করে। এখানে ফলস নেগেটিভ মানে যোগ্য একজন মানুষকে কেউ পড়েই দেখল না, যা আবেদনকারীর ক্ষতি। ফলস পজিটিভে রিক্রুটারের কিছু সময় যায়। প্রতারণা শনাক্তের ক্ষেত্রে হতো উল্টোটা।
show(stats, ["fpr", "fnr"])group fpr fnr
A 0.25 0.25
B 0.10 0.50
all 0.18 0.33B-র যোগ্য আবেদনকারীরা A-র তুলনায় দ্বিগুণ হারে বাদ পড়েন (০.৫০ বনাম ০.২৫), অথচ B-র অনুপযুক্ত আবেদনকারীরা কম হারে শর্টলিস্ট হন (০.১০ বনাম ০.২৫)। দুই ধরনের ভুল দুই দিকে যায়, আর একটামাত্র "এরর রেট" দুটোই লুকিয়ে ফেলত।
নির্ভুলতা, প্রিসিশন ও রিকল
গ্রুপগুলোর মধ্যে নির্ভুলতা তুলনা করুন। নির্ভুলতা (accuracy) হলো সঠিক সিদ্ধান্তের অংশ।
show(stats, ["accuracy"])group accuracy
A 0.75
B 0.75
all 0.75দুই গ্রুপেরই স্কোর ০.৭৫, তবু আগের টেবিলগুলো দেখায় টুল তাদের সঙ্গে আলাদা আচরণ করে। নির্ভুলতা সমান মানে আচরণ সমান নয়: B-র অনেক ট্রু নেগেটিভ তার স্কোর বাড়িয়ে দেয়।
প্রতিটা গ্রুপের প্রিসিশন ও রিকল হিসাব করুন। প্রিসিশন হলো শর্টলিস্টদের মধ্যে উপযুক্তদের অংশ। রিকল হলো উপযুক্তদের মধ্যে শর্টলিস্টদের অংশ; এটা ট্রু-পজিটিভ রেটেরই আরেক নাম।
show(stats, ["precision", "recall"])group precision recall
A 0.75 0.75
B 0.75 0.50
all 0.75 0.67দুই গ্রুপেরই প্রিসিশন ০.৭৫, তাই শর্টলিস্ট পড়া রিক্রুটার দুই গ্রুপেই উপযুক্তদের একই অংশ দেখেন। রিকল আলাদা: B-র উপযুক্তদের অর্ধেক শর্টলিস্টে পৌঁছায়, A-র তিন-চতুর্থাংশ।
ন্যায্যতার তিনটা পার্থক্য
হার্ড্ট, প্রাইস ও শ্রেব্রো (Hardt, Price, Srebro, ২০১৬) আসল ফলাফলের ভিত্তিতে দুটো মানদণ্ড সংজ্ঞায়িত করেন। কথায়:
| মানদণ্ড | প্রশ্ন | কোডে |
|---|---|---|
| ডেমোগ্রাফিক প্যারিটি (স্ট্যাটিসটিক্যাল প্যারিটি) | আসল ফলাফল যা-ই হোক, প্রতিটা গ্রুপের একই অংশ নির্বাচিত হয় কি না? | selection-এর পার্থক্য |
| ইকুয়াল অপরচুনিটি | সত্যিই উপযুক্তরা প্রতিটা গ্রুপে নির্বাচিত হওয়ার একই সুযোগ পান কি না? | tpr-এর পার্থক্য |
| ইকুয়ালাইজড ওডস | উপযুক্তদের সুযোগ (tpr) এবং অনুপযুক্তদের ভুলভাবে নির্বাচিত হওয়ার সুযোগ (fpr), দুটোই সমান কি না? | tpr ও fpr-এর পার্থক্য |
ইকুয়াল অপরচুনিটি ইকুয়ালাইজড ওডসের একটা শিথিল রূপ, যাতে শুধু প্রথম অর্ধেক লাগে। সিলেকশন রেট তুলনা করে ডেমোগ্রাফিক-প্যারিটির পার্থক্য দেখুন, আর ওপরের রেটগুলো তুলনা করে ইকুয়াল-অপরচুনিটি ও ইকুয়ালাইজড-ওডসের পার্থক্য দেখুন। ইকুয়ালাইজড ওডসের জন্য এই পাতা দুটো ফারাকের বড়টা জানায়। টলারেন্স আপনার বাছাই, এবং তার একটা লিখিত কারণ লাগে।
from fair import diff, fmt
TOL = 0.05 # a tolerance is a choice; no value here is a standard
dp, tpr, fpr = (diff(stats, k, "A") for k in ("selection", "tpr", "fpr"))
for g in dp:
worst = max(abs(tpr[g]), abs(fpr[g]))
print(f"demographic parity difference ({g} - A): {fmt(dp[g], True)} within {TOL}: {abs(dp[g]) <= TOL}")
print(f"equal opportunity difference ({g} - A): {fmt(tpr[g], True)} within {TOL}: {abs(tpr[g]) <= TOL}")
print(f"false-positive-rate difference: {fmt(fpr[g], True)}")
print(f"equalised odds, largest gap: {fmt(worst)} within {TOL}: {worst <= TOL}")demographic parity difference (B - A): -0.25 within 0.05: False
equal opportunity difference (B - A): -0.25 within 0.05: False
false-positive-rate difference: -0.15
equalised odds, largest gap: 0.25 within 0.05: Falseতিনটাতেই ০.০৫ টলারেন্সের বিপরীতে ফারাক ০.২৫ বা তার বেশি। লক্ষ্য করুন, fpr-এর ফারাক (-০.১৫) গ্রুপ A-র অনুপযুক্ত আবেদনকারীদের সুবিধা দেয়, আর tpr-এর ফারাক B-র উপযুক্তদের অসুবিধায় ফেলে। একটা মেট্রিকে ফারাক শূন্য হতে পারে অথচ আরেকটায় বড় থাকে (মাঝারি অনুশীলনে তা দেখা যাবে)।
দলের কোন মানদণ্ড পছন্দ করা উচিত? যুক্তিসংগত মানুষ একমত হন না, আর সবচেয়ে শক্তিশালী যুক্তিগুলো এই:
| মানদণ্ড | পক্ষে সবচেয়ে শক্ত যুক্তি | বিপক্ষে সবচেয়ে শক্ত যুক্তি |
|---|---|---|
| ডেমোগ্রাফিক প্যারিটি | লেবেল লাগে না; লেবেল নিজেই সন্দেহজনক হলে কাজের; সুবিধায় সমান প্রবেশাধিকার | আসল ফলাফলের বাস্তব পার্থক্য উপেক্ষা করে; সমান হার মানে এক গ্রুপে কম উপযুক্তদের বেছে নেওয়া হতে পারে |
| ইকুয়াল অপরচুনিটি | যোগ্য মানুষ প্রতিটা গ্রুপে একই সুযোগ পান, যা বাদ পড়ার ক্ষতির সঙ্গে মেলে | নির্ভরযোগ্য লেবেল লাগে; ভুলভাবে নির্বাচিত অনুপযুক্তদের বিষয়ে কিছু বলে না |
| ইকুয়ালাইজড ওডস | দুই ধরনের মানুষের সঙ্গেই সমান আচরণ; দৈবক্রমে পূরণ করা কঠিন | আরও কড়া, নির্ভরযোগ্য লেবেল লাগে, নির্ভুলতার দাম দিতে হতে পারে বা অন্য লক্ষ্যের সঙ্গে সংঘাত হতে পারে |
বাছাই নির্ভর করে সিদ্ধান্তের ক্ষতি, লেবেলের মান এবং প্রেক্ষাপটের ওপর, আর বিভিন্ন খাত ও জায়গার দল আলাদা বাছাই করে। এই পাতা একটা বেছে নেয় না।
এই সংখ্যাগুলো যা বলতে পারে না
| প্রশ্ন | এই মেট্রিক উত্তর দেয় কি না? |
|---|---|
| টুলটা বাস্তবে ন্যায্য কি না? | না। এটা কাল্পনিক ডেটা। বাস্তব ডেটাও শুধু একটা ডেটাসেট ও একটা সিদ্ধান্ত-নিয়মের বর্ণনা দেয়। |
| পার্থক্যের কারণ টুল, ডেটা না লেবেল? | না। মেট্রিক ফারাক বর্ণনা করে; কারণ খুঁজতে ডেটার ইতিহাস আর প্রক্রিয়া দেখতে হয়। |
| লেবেল ঠিক কি না? | না। লেবেল পক্ষপাতদুষ্ট হলে প্রতিটা মেট্রিক সেই পক্ষপাত পায়। |
| ফারাকটা আসল, না কাকতালীয়? | একা নয়। B-তে উপযুক্ত ৬ জন: একটা সিদ্ধান্ত আলাদা হলে তার tpr প্রায় ০.১৭ নড়ে। |
| কোন মেট্রিক ব্যবহার করব? | না। এটা ক্ষতি নিয়ে বিচার, যা যুক্তি দিয়ে ঠিক করে লিখে রাখতে হয়। |
| আমরা কোনো নিয়ম মানছি কি না? | না। নিয়ম মানা নির্ভর করে নিয়ম, স্থান ও খাতের ওপর। |
তাই দায়িত্বশীল সিদ্ধান্ত-নোট পড়তে এমন হয়: "এই টেবিলে, এই সিদ্ধান্ত ও লেবেলের জন্য, গ্রুপ B-র উপযুক্ত আবেদনকারীরা ০.৫০ হারে শর্টলিস্ট হয়েছেন, A-র ০.৭৫-এর বিপরীতে; গ্রুপটা ছোট, লেবেল পর্যালোচনা হয়নি, এবং আমরা আরও পরীক্ষার প্রস্তাব দিচ্ছি।" এটা পড়তে "টুলটা পক্ষপাতদুষ্ট" বা "টুলটা ন্যায্য" হয় না।
কাজের জায়গায় এটা কোথায় দেখা যায়
বিশ্লেষকরা পাইলটের আগে এবং প্রতিটা পরিবর্তনের পর এমন গ্রুপ-টেবিল চালান, তারপর সেটা সিদ্ধান্তের দায়িত্বে থাকা মানুষদের কাছে নিয়ে যান। বাস্তব ডেটায় একই কোড চালালে গ্রুপ কলামের জন্য গোপনীয়তা-পর্যালোচনাও লাগবে।
সাধারণ ভুল
- গ্রুপ কলাম মুছে ভাবা যে সমস্যা মিটে গেছে। প্রক্সি একই তথ্য বহন করতে পারে। ওপরে দেখানো উপায়ে প্রক্সি পরীক্ষা করুন।
- নির্ভুলতাকে ন্যায্যতা ভাবা। সমান নির্ভুলতা B-র বাদ পড়ার হার দ্বিগুণ হওয়া লুকিয়েছিল। প্রতিটা গ্রুপের এরর রেট সবসময় দেখান।
- গ্রুপগুলোর গড় করে ফেলা। "all" সারি নির্বাচনের দ্বিগুণ ফারাক লুকিয়েছিল।
- অনির্ধারিত রেটকে শূন্য করে দেওয়া। যে গ্রুপে কোনো পজিটিভ নেই, তার tpr নেই।
n/aরাখুন এবং তুলনা করবেন না। - লেবেলকে সত্য ধরা। কে কীভাবে লেবেল বানিয়েছেন এবং তা কী বাদ দেয় তা বলুন।
নিজে চেষ্টা করুন
এই পাতার নেমস্পেস ব্যবহার করুন। অনুশীলনগুলো বিগিনার টিউটোরিয়ালের ন্যায্যতা ও তার ট্রেড-অফ: অন্তর্ভুক্তি, অ্যাক্সেসিবিলিটি ও ভাষা পাতার ফলস পজিটিভ ও ফলস নেগেটিভ আবার ছোঁয়।
- সহজ। গ্রুপ B-র (tp 3, fn 3, fp 1, tn 9) সিলেকশন রেট, fpr ও প্রিসিশন হাতে হিসাব করুন। তারপর টেবিলের সঙ্গে মিলিয়ে দেখুন।
- মাঝারি। গ্রুপ B এমনভাবে নতুন করে বানান যাতে তার ট্রু-পজিটিভ রেট A-র সমান (০.৭৫) হয় কিন্তু সে অনেক কম নির্বাচিত হয়। সিলেকশন, tpr ও fpr এবং দুই ফারাক ছাপুন। কোন মেট্রিক পূরণ হয়?
- কঠিন। ৩ জনের একটা গ্রুপ C যোগ করুন, কেউ উপযুক্ত নন, ১ জন শর্টলিস্ট। তার সারি ছাপুন। ব্যাখ্যা করুন tpr কেন
n/a, আর রিপোর্টে গ্রুপ C-কে নিয়ে কী করবেন।
উত্তর
সহজ। নির্বাচিত: ৩ + ১ = ১৬ জনের ৪ জন, অর্থাৎ ০.২৫। অনুপযুক্ত: ১ + ৯ = ১০ জন, যাঁদের ১ জন শর্টলিস্ট: fpr ০.১০। শর্টলিস্ট ৪ জন, যাঁদের ৩ জন উপযুক্ত: প্রিসিশন ০.৭৫। পাস চেকলিস্ট: তিনটা মানই টেবিলের সঙ্গে মেলে; প্রতিটার জন্য ঠিক হর নিয়েছেন (সবাই, অনুপযুক্তরা, শর্টলিস্টরা)। দুর্বল উত্তর ভুল গ্রুপ দিয়ে ভাগ করে।
মাঝারি। উপযুক্ত মানুষ: ৩ + ১ = ৪ জন, যাঁদের ৩ জন শর্টলিস্ট (tpr ০.৭৫); কোনো অনুপযুক্ত মানুষ শর্টলিস্ট নন।
alt = build([("A", 1, 1, 9, 0), ("A", 1, 0, 3, 1), ("A", 0, 1, 3, 0), ("A", 0, 0, 9, 3),
("B", 1, 1, 3, 1), ("B", 1, 0, 1, 1), ("B", 0, 0, 12, 7)])
s2 = by_group(alt)
show(s2, ["n", "selection", "tpr", "fpr"])
print("selection gap:", fmt(diff(s2, "selection", "A")["B"], True), "| tpr gap:", fmt(diff(s2, "tpr", "A")["B"], True))group n selection tpr fpr
A 24 0.50 0.75 0.25
B 16 0.19 0.75 0.00
all 40 0.38 0.75 0.12
selection gap: -0.31 | tpr gap: +0.00ইকুয়াল অপরচুনিটি পূরণ হয়েছে (ফারাক +০.০০), ডেমোগ্রাফিক প্যারিটি হয়নি (-০.৩১), আর fpr-এর ফারাক -০.২৫। পাস চেকলিস্ট: tpr ০.৭৫; কোন মেট্রিক টিকল আর কোনটা টিকল না তা জানিয়েছেন; ফলাফলকে ন্যায্য বা অন্যায্য বলেননি। দুর্বল উত্তর শুধু যে মেট্রিকটা পাস করে সেটাই জানায়।
কঠিন।
more = build([("A", 1, 1, 9, 0), ("A", 1, 0, 3, 1), ("A", 0, 1, 3, 0), ("A", 0, 0, 9, 3),
("C", 0, 1, 1, 0), ("C", 0, 0, 2, 1)])
s3 = by_group(more)
show(s3, ["n", "selection", "tpr", "fpr", "precision"])
print(diff(s3, "tpr", "A"))group n selection tpr fpr precision
A 24 0.50 0.75 0.25 0.75
C 3 0.33 n/a 0.33 0.00
all 27 0.48 0.75 0.27 0.69
{'C': None}কোনো উপযুক্ত মানুষ না থাকলে "উপযুক্তদের নির্বাচিত অংশ"-এর হর নেই, তাই tpr অনির্ধারিত এবং পার্থক্য None। পাস চেকলিস্ট: n/a রাখা হয়েছে, ০.০০ দিয়ে বদলানো হয়নি; গ্রুপ C-কে সংখ্যাসহ রিপোর্ট করা হয়েছে, tpr বা রিকলে তুলনা করা হয়নি; নোটে বলা আছে ৩ জনের গ্রুপ কোনো সিদ্ধান্তের জন্য খুব ছোট। ভালো উত্তর আরও ডেটা সংগ্রহের কথা বলে, বা কারণ লিখে গ্রুপ মেলানোর কথা বলে।
সারসংক্ষেপ
- আগে সিদ্ধান্ত, ইতিবাচক ফলাফল ও তুলনার গ্রুপ ঠিক করুন; প্রতিটা মেট্রিক এদের ওপর নির্ভর করে।
- সুরক্ষিত বৈশিষ্ট্যের পাশাপাশি প্রক্সি ভেরিয়েবলও পরীক্ষা করুন; কলাম মুছে ফেলাই যথেষ্ট নয়।
- লেবেল, পূর্বাভাস ও পর্যবেক্ষিত ফলাফল আলাদা রাখুন; ফলাফল থাকে শুধু নির্বাচিতদের।
- প্রতিটা গ্রুপের সিলেকশন, এরর, নির্ভুলতা, প্রিসিশন ও রিকল হিসাব করুন, আর অনির্ধারিত রেট
n/aহিসেবে জানান। - ডেমোগ্রাফিক প্যারিটি, ইকুয়াল অপরচুনিটি ও ইকুয়ালাইজড ওডস পরস্পরের সঙ্গে মিলতে নাও পারে; ফারাক দেখার কারণ, রায় নয়; আর টয় ডেটা বাস্তব জগৎ সম্পর্কে কিছুই প্রমাণ করে না।
এরপর: ন্যায্যতার লক্ষ্য তুলনা ও তার সীমা: ছোট স্যাম্পল ও পরস্পরবিরোধী মেট্রিক পাতায় দেখা যাবে এই মেট্রিকগুলো কেন পরস্পরবিরোধী হতে পারে, বেস রেট ও ছোট গ্রুপ ছবিটা কীভাবে বদলায়, এবং একই ডেটায় দুটো থ্রেশহোল্ড কীভাবে তুলনা করবেন।