এই পর্বে যা শিখবেন
- শুরু থেকেই ব্যাখ্যাযোগ্য model আর পরে জোড়া ব্যাখ্যার পার্থক্য, আর standardised coefficient-এর সীমা
- Held-out ডেটায় permutation importance নিজে লিখে
permutation_importance-এর সঙ্গে মেলানো, আর spread পড়া - Correlated feature-এ importance-এর ভাগাভাগি, grouped permutation আর drop-column importance
- PDP, ICE আর centred ICE নিজে বানিয়ে
partial_dependence-এর সঙ্গে মেলানো, আর interaction চেনা - PDP-র independence অনুমান কোথায় ভাঙে, ALE নিজে লেখা, আর surrogate tree-এর fidelity মাপা
এতদিন প্রশ্ন ছিল “model কতটা ভালো অনুমান করে?” এই মডিউলের প্রশ্ন আলাদা: model কীসের ওপর ভর করে, তার অনুমান কতটা নিশ্চিত, আর কার জন্য ন্যায্য। প্রথম পর্বে আমরা পুরো model-কে একসঙ্গে বুঝব। ভিত্তি তিনটি: AI-এর ভিত্তি কোর্সের পর্ব ৬৩-এ permutation importance-এর প্রথম পরিচয়, পর্ব ৩৩-এ impurity বনাম permutation importance আর high-cardinality পক্ষপাত (সেই demo এখানে আর দেখানো হবে না), আর পর্ব ৩৬-এ partial_dependence-এর প্রথম ব্যবহার। চারটি চালানো যায় এমন ব্লক পাতাতেই চলে (ব্রাউজারের Python, NumPy, pandas, scikit-learn আর matplotlib); প্রথমবার scikit-learn নামতে প্রায় দশ সেকেন্ড লাগে।
১ · Model বোঝার প্রশ্ন — global বনাম local, শুরু থেকে বনাম পরে
একজন অভিজ্ঞ ডাক্তার রোগ ধরেন, কিন্তু কীভাবে ধরেন তা সব সময় গুছিয়ে বলতে পারেন না। শিক্ষানবিশ দুইভাবে শিখতে পারেন। এক, অনেক রোগী দেখে বুঝে নেওয়া “জ্বর থাকলে তিনি সাধারণত কী করেন”: এটি পুরো আচরণের ছবি। দুই, একজন রোগীর ফাইল ধরে জিজ্ঞেস করা “এই রোগীকে এই ওষুধ কেন?” প্রথমটি global ব্যাখ্যা, দ্বিতীয়টি local. এই পর্ব প্রথমটির; পর্ব ৫৭ (একটি অনুমানের ব্যাখ্যা — SHAP আর LIME) দ্বিতীয়টির।
Interpretability মানে মানুষ model-এর আচরণ কতটা বুঝতে পারে। দুটি অক্ষে ভাবা কাজের। প্রথম অক্ষ: global ব্যাখ্যা (পুরো ডেটায় গড় আচরণ) বনাম local ব্যাখ্যা (একটি সারি)। দ্বিতীয় অক্ষ: model নিজেই পড়া যায় এমন, অর্থাৎ শুরু থেকেই ব্যাখ্যাযোগ্য (ছোট linear model, ছোট গাছ, GAM), নাকি একটি black box-এর ওপর পরে জোড়া post-hoc ব্যাখ্যা. AI-এর ভিত্তি কোর্সের পর্ব ৭২ explainability-কে দায়িত্বশীল AI-এর অংশ হিসেবে পরিচয় করিয়েছে; এখানে যন্ত্রগুলো গভীরে।
| প্রশ্ন | Global (পুরো model) | Local (একটি সারি) |
|---|---|---|
| কোন feature-এর ওপর নির্ভর? | Permutation importance, grouped বা drop-column (অংশ ৩–৪) | SHAP মান (পর্ব ৫৭) |
| Feature বদলালে অনুমান কোন দিকে? | PDP, ALE (অংশ ৫, ৭) | ICE রেখা (অংশ ৫), LIME (পর্ব ৫৭) |
| পুরো নিয়মটা পড়া যায়? | শুরু থেকে ব্যাখ্যাযোগ্য model, global surrogate (অংশ ৮) | Counterfactual (পর্ব ৫৭-এ টীকা) |
সব post-hoc পদ্ধতির একটি সাধারণ সীমা আছে: এরা model কী করে তা বর্ণনা করে, দুনিয়া কীভাবে চলে তা নয়। Model যদি ভুল কারণে ঠিক উত্তর দেয় (যেমন leakage-এর কলাম ধরে), importance সেই ভুল কারণকেই “গুরুত্বপূর্ণ” দেখাবে। Cynthia Rudin ২০১৯ সালে Nature Machine Intelligence-এ যুক্তি দেন, উচ্চ ঝুঁকির সিদ্ধান্তে black box ব্যাখ্যা করার চেয়ে শুরু থেকেই ব্যাখ্যাযোগ্য model বানানো ভালো, কারণ tabular ডেটায় দুই ধরনের model-এর accuracy প্রায়ই কাছাকাছি। সবাই এই অবস্থানের সঙ্গে পুরো একমত নন (ছবি, লেখা বা খুব জটিল সম্পর্কে ফাঁক বড় হতে পারে), তবে অংশ ৮-এ দেখবেন, এই পর্বের ডেটায় যুক্তিটি সংখ্যায় খাটে।
২ · বাজারঘরের ডেলিভারি-সময়ের ডেটা আর একটি black box
বাজারঘর জানতে চায় একটি অর্ডার কত মিনিটে পৌঁছাবে। নিচের module ৩,০০০টি কাল্পনিক ডেলিভারি বানায়। ছয়টি feature: দোকান থেকে বাড়ির সোজা দূরত্ব (distance_km), map app-এর আন্দাজি রাস্তার দূরত্ব (road_km), বৃষ্টি (rain), পণ্যের সংখ্যা (items), অর্ডারের ঘণ্টা (hour) আর কুপন (coupon). আসল নিয়ম simulation-এ জানা, তাই প্রতিটি ব্যাখ্যা যাচাই করা যাবে: সময় নির্ভর করে আসল পথের দৈর্ঘ্যের ওপর, বৃষ্টিতে প্রতি km ৭০% বেশি সময় (একটি interaction), প্রতিটি পণ্যে ১ মিনিট, বিকেল ৫টা থেকে রাত ৯টার আগ পর্যন্ত ভিড়ে ৭ মিনিট। কুপনের কোনো প্রভাব নেই। আসল পথ ডেটায় নেই; সোজা দূরত্ব আর app-এর আন্দাজ দুটিই তার অসম্পূর্ণ ছায়া, তাই দুটি খুব ঘনিষ্ঠ (r = ০.৯৮১)। রাস্তার দূরত্ব কখনো সোজা দূরত্বের চেয়ে কম হয় না; আসল ডেটায় অনুপাত ১.০৩ থেকে ১.৬-এর মধ্যে। এই তথ্য অংশ ৭-এ কাজে লাগবে।
# বাজারঘর (কাল্পনিক দোকান): ডেলিভারি কত মিনিটে, seeded ডেটা
import numpy as np
import pandas as pd
COLS = ["distance_km", "road_km", "rain", "items", "hour", "coupon"]
def deliveries(n=3000, seed=56):
rng = np.random.default_rng(seed)
distance = rng.uniform(0.5, 10.0, n) # সোজা দূরত্ব
route = distance * rng.uniform(1.15, 1.45, n) # আসল পথ (ডেটায় নেই)
road = route * rng.uniform(0.9, 1.1, n) # app-এর আন্দাজি রাস্তার দূরত্ব
rain = rng.binomial(1, 0.3, n)
items = rng.integers(1, 9, n)
hour = rng.integers(9, 23, n)
coupon = rng.binomial(1, 0.4, n) # সময়ে কোনো প্রভাব নেই
rush = ((hour >= 17) & (hour <= 20)).astype(int)
minutes = (12 + 2.4 * route * (1 + 0.7 * rain) + 1.0 * items
+ 7 * rush + rng.normal(0, 3, n)) # আসল নিয়ম: পথ × বৃষ্টি
X = pd.DataFrame({"distance_km": distance.round(2), "road_km": road.round(2),
"rain": rain, "items": items, "hour": hour, "coupon": coupon})
return X, minutes.round(1)
def split():
X, y = deliveries()
return X[:2000], X[2000:], y[:2000], y[2000:]Black box হিসেবে নেওয়া হলো পর্ব ৩৬-এর HistGradientBoostingRegressor, ২০০টি গাছ। প্রথম ২,০০০ সারিতে শেখানো, শেষ ১,০০০ সারি held-out test. সব ব্লকে একই ভাগ, একই seed.
৩ · Permutation importance — held-out ডেটায়, বারবার, ছড়ানোসহ
ধারণাটি Leo Breiman ২০০১ সালে random forest-এর প্রবন্ধে দেন, আর পরে এটি যেকোনো model-এ খাটানো হয়। শেখানো model স্থির রাখুন। Held-out ডেটায় একটি কলামের মানগুলো সারিগুলোর মধ্যে এলোমেলো করুন: কলামের বণ্টন একই থাকে, কিন্তু label-এর সঙ্গে সম্পর্ক ভেঙে যায়। এবার score কতটা খারাপ হলো, সেটিই permutation importance:
PIj = (১/R) ∑r=১R [ MAE(এলোমেলো j, বার r) − MAE(আসল) ]
এখানে j হলো কলাম, R হলো কতবার এলোমেলো করা হলো (n_repeats). প্রতিটি এলোমেলো করা একটি দৈব ঘটনা, তাই R বার করে গড় আর standard deviation দুটিই দেখতে হয়। MAE ব্যবহার করায় importance-এর একক মিনিট: “এই কলামের তথ্য হারালে গড় ভুল কত মিনিট বাড়ে”। নিচের stepper পাঁচটি সারিতে পুরো হিসাব করে।
| এখন যা হচ্ছে | |
| road কলাম | |
| অনুমান ŷ | |
| │y − ŷ│ | |
| MAE, importance |
- শুরু। আসল road দিয়ে অনুমান ১৬, ২২, ২৮, ৩৪, ৪০; প্রতিটিতে ভুল ১ মিনিট, MAE = ১.০. এটিই তুলনার ভিত্তি।
- এলোমেলো। শুধু road কলামের মানগুলো সারির মধ্যে অদলবদল: ৬, ২, ১০, ৪, ৮. আসল y আর অন্য কলাম যেমন ছিল তেমন। কলামে এখনো সেই পাঁচটি সংখ্যাই আছে, শুধু ভুল সারিতে।
- নতুন অনুমান। একই model, নতুন road: ২৮, ১৬, ৪০, ২২, ৩৪. প্রথম সারির আসল ১৭ মিনিট, অনুমান ২৮: ভুল ১১. পাঁচটি ভুলের যোগ ৪৫, MAE = ৯.০.
- Importance. ৯.০ − ১.০ = ৮.০ মিনিট। Model road-এর ওপর জোরালোভাবে নির্ভর করে; তথ্যটি হারালে গড় ভুল আট মিনিট বাড়ে।
- আবার। অন্য একটি ক্রম (৪, ২, ৮, ১০, ৬) দেয় MAE ৭.০, importance ৬.০. একই কলাম, একই model, শুধু দৈব ক্রম আলাদা, তবু সংখ্যা আলাদা।
- গড় আর ছড়ানো। দুই বারের গড় ৭.০, sd ১.০ (NumPy-র
np.std-এর মতো n দিয়ে ভাগ)। এই কারণেইn_repeats: একবারের সংখ্যা ভাগ্যের ওপর নির্ভর করে।
তিনটি সিদ্ধান্ত ফলকে বদলায়। (১) কোন ডেটায়: train ডেটায় মাপলে model যা মুখস্থ করেছে তাও “গুরুত্ব” পায়; held-out ডেটায় মাপলে শুধু যা নতুন ডেটায় কাজে লাগে। (২) কোন score: R², MAE বা log loss আলাদা ক্রম দিতে পারে; যে মাপে model-কে বিচার করেন, সেটিই নিন। (৩) কতবার: ছোট test সেটে spread বড়। প্রথম ব্লক নিজে লেখা কোড sklearn-এর সঙ্গে মেলায়, train বনাম test তুলনা করে, আর পরের অংশের জন্য correlated জোড়ার grouped আর drop-column সংখ্যাও ছাপে।
import numpy as np
import pandas as pd
from sklearn.ensemble import HistGradientBoostingRegressor as HGB
from sklearn.inspection import permutation_importance
from sklearn.metrics import mean_absolute_error as mae
from bazar_eta import split, COLS
Xtr, Xte, ytr, yte = split()
m = HGB(max_iter=200, random_state=0).fit(Xtr, ytr)
base = mae(yte, m.predict(Xte))
print(f"test MAE {base:.2f} min (train {mae(ytr, m.predict(Xtr)):.2f})")
def perm_imp(cols, n_repeats=10, seed=0): # নিজে লেখা, sklearn-এর বীজের নিয়মে
s = np.random.RandomState(seed).randint(2**31)
rs, idx, Xp = np.random.RandomState(s), np.arange(len(Xte)), Xte.copy()
d = []
for _ in range(n_repeats):
rs.shuffle(idx)
Xp[cols] = Xp[cols].to_numpy()[idx] # এক বা একাধিক কলাম একসঙ্গে এলোমেলো
d.append(mae(yte, m.predict(Xp)) - base)
return np.array(d)
mine = np.array([perm_imp([c]) for c in COLS])
kw = dict(scoring="neg_mean_absolute_error", n_repeats=10, random_state=0)
sk = permutation_importance(m, Xte, yte, **kw)
print("max |mine - sklearn| =", np.abs(mine - sk.importances).max())
tr = permutation_importance(m, Xtr, ytr, **kw).importances_mean
print(pd.DataFrame({"test mean": mine.mean(1), "test sd": mine.std(1),
"train mean": tr}, index=COLS).round(3))
g = perm_imp(["distance_km", "road_km"])
print(f"grouped distance+road: {g.mean():.3f} +/- {g.std():.3f}")
for cols in [["distance_km"], ["road_km"], ["distance_km", "road_km"]]:
r = HGB(max_iter=200, random_state=0).fit(Xtr.drop(columns=cols), ytr)
print("drop-column", cols, f"{mae(yte, r.predict(Xte.drop(columns=cols))) - base:.3f}")আসল আউটপুট (ব্রাউজারের Python):
test MAE 2.74 min (train 1.64)
max |mine - sklearn| = 0.0
test mean test sd train mean
distance_km 3.330 0.109 3.869
road_km 4.606 0.156 5.243
rain 3.997 0.227 4.162
items 0.955 0.049 1.586
hour 1.679 0.073 2.321
coupon -0.007 0.010 0.102
grouped distance+road: 9.616 +/- 0.248
drop-column ['distance_km'] 0.109
drop-column ['road_km'] 0.209
drop-column ['distance_km', 'road_km'] 6.900
মিল: নিজে লেখা ফাংশন আর permutation_importance-এর ১০ × ৬টি সংখ্যার সর্বোচ্চ পার্থক্য ০.০. হুবহু মিলের জন্য sklearn-এর একটি খুঁটিনাটি নকল করা হয়েছে: random_state থেকে একটি বীজ বানিয়ে প্রতিটি কলামে একই এলোমেলো ক্রমের ধারা চালানো হয়, আর প্রতিবার আগের এলোমেলো কলামটিকেই আবার এলোমেলো করা হয়। পড়া: test MAE ২.৭৪ মিনিট। road_km এলোমেলো করলে MAE গড়ে ৪.৬১ মিনিট বাড়ে, rain-এ ৪.০০, distance_km-এ ৩.৩৩. Spread ছোট (sd ০.০৫–০.২৩), কারণ ১,০০০ সারিতে একেকটি এলোমেলো ক্রমের প্রভাব গড়ে মিশে যায়। coupon-এর importance −০.০০৭ ± ০.০১০: শূন্যের সঙ্গে মেলে, ঠিক যেমন হওয়া উচিত। Train বনাম test: train-এ সব সংখ্যা বড়, কারণ সেখানে model-এর ভুল কম (১.৬৪) আর মুখস্থ করা খুঁটিনাটিও ভাঙে। সবচেয়ে শিক্ষণীয় coupon: train-এ ০.১০২, অর্থাৎ model train ডেটার noise-এ কুপন দিয়ে কিছু ভাগ করেছে, যা test-এ কোনো কাজে আসে না।
“Importance বেশি” মানে “কারণ” নয়। এখানে distance_km আসল নিয়মে নেই, অথচ importance ৩.৩৩, কারণ model আসল পথের খবর তার কাছ থেকেও নেয়। Permutation importance বলে “model কোন তথ্য ব্যবহার করে”; “সোজা দূরত্ব কমালে ডেলিভারি দ্রুত হবে” ধরনের দাবির জন্য পর্ব ৬৪ (Causal inference-এর পরিচয় — DAG, matching আর difference-in-differences)-এর মতো নকশা লাগে।
৪ · Correlated feature — importance ভাগ হয়, grouped permutation আর drop-column
প্রথম ব্লকের শেষ পাঁচ লাইন একটি ধাঁধা দেখায়। দুটি দূরত্ব-কলাম আলাদাভাবে ৩.৩৩ আর ৪.৬১, যোগ ৭.৯৪. কিন্তু দুটি একই এলোমেলো ক্রমে একসঙ্গে সরালে ৯.৬২, যোগের চেয়েও বেশি। আর একটিকে পুরো বাদ দিয়ে model আবার শেখালে (drop-column importance) ক্ষতি মাত্র ০.১০৯ আর ০.২০৯ মিনিট; দুটি বাদ দিলে ৬.৯০০.
একটি দোকানে দুজন হিসাবরক্ষক একই খাতা মিলিয়ে রাখেন। একজন ছুটিতে গেলে কাজ প্রায় আটকায় না, অন্যজন সামলে নেন: drop-column-এর চোখে দুজনেরই “গুরুত্ব” প্রায় শূন্য। কিন্তু দুজন একসঙ্গে ছুটিতে গেলে দোকান অচল। আর যদি একজনকে ছুটিতে না পাঠিয়ে তাঁর খাতায় এলোমেলো সংখ্যা লিখে দেন, অন্যজনের সঙ্গে গরমিল লেগে ভুল আরও বাড়ে: এটি permutation-এর অবস্থা।
তিনটি পদ্ধতি তিনটি আলাদা প্রশ্নের উত্তর দেয়। একক permutation: “এই শেখানো model এই কলামের ওপর কতটা ভর করে?” Model দুটি কলামেই কিছু ভর দিয়েছে, তাই দুটিই মাঝারি, কিন্তু এলোমেলো করার সময় তৈরি হয় এমন সারি যা বাস্তবে নেই (১ km সোজা দূরত্ব, ১২ km রাস্তা)। Giles Hooker, Lucas Mentch ও Siyu Zhou ২০২১ সালে দেখান, এমন extrapolation importance-কে ফুলিয়ে বা বিকৃত করতে পারে। Grouped permutation: “এই তথ্যের দল হারালে কত ক্ষতি?” দুটি কলাম একই ক্রমে সরালে তাদের পারস্পরিক সম্পর্ক অটুট থাকে, অসম্ভব জোড়া তৈরি হয় না। ঘনিষ্ঠ কলামগুলোকে দলে বাঁধার একটি সরল উপায় correlation-এর ভিত্তিতে hierarchical clustering. Drop-column: “এই কলাম ছাড়া নতুন model কতটা খারাপ?” এটি ডেটায় কলামটির অনন্য তথ্যের মাপ, শেখানো model-এর নয়। দাম চড়া: প্রতিটি কলামে (বা দলে) একবার পুরো training, আর ১০০টি feature-এ ১০০ বার; সৎ হতে হলে প্রতিবার একই hyperparameter আর cross-validation.
Correlated feature-এ “কোনটি বেশি গুরুত্বপূর্ণ?” প্রশ্নটি প্রায়ই ভুলভাবে করা। Model দুটির মধ্যে ভার কীভাবে ভাগ করবে তা seed, গাছের সংখ্যা বা ডেটার ছোট পরিবর্তনে বদলায়; একক importance-এর ক্রমও তাই বদলাতে পারে। স্থির উত্তর আসে দলের স্তরে: “দূরত্বের তথ্য মিলে ৯.৬ মিনিট”। পর্ব ৩৩-এ আলোচিত Strobl ও সহকর্মীদের (২০০৮) conditional permutation আরেকটি পথ: সঙ্গী feature-এর মান অনুযায়ী ছোট দলের ভেতরে এলোমেলো করা।
৫ · Partial dependence আর ICE — feature বদলালে অনুমান কোন দিকে
Importance বলে “কতটা”, কিন্তু দিক বা আকার বলে না। Jerome Friedman ২০০১ সালে gradient boosting-এর প্রবন্ধে partial dependence দেন। একটি feature S-কে একটি মান v-তে বসান, বাকি সব কলাম (C) প্রতিটি সারিতে যেমন আছে তেমন রেখে, তারপর অনুমানের গড়:
PDS(v) = (১/n) ∑i=১n f̂(v, xi,C)
অর্থাৎ “সব অর্ডারের রাস্তা যদি v km হতো, গড়ে কত মিনিট লাগত?” v বদলে আঁকা রেখাই PDP. গড় নেওয়ার আগের প্রতিটি সারির নিজের রেখাকে Alex Goldstein ও সহকর্মীরা ২০১৫ সালে নাম দেন ICE (individual conditional expectation): সারি i-এর জন্য v ↦ f̂(v, xi,C). PDP হলো ICE রেখাগুলোর গড়।
| এখন যা হচ্ছে | |
| নতুন সারি | |
| অনুমান (মিনিট) | |
| ফল |
- শুরু। চারটি সারি, দুটি শুকনো দিনের, দুটি বৃষ্টির। Model-এ বৃষ্টিতে প্রতি km অতিরিক্ত ১.৫ মিনিট: একটি interaction.
- বসানো। প্রতিটি সারির road মুছে ৬ বসানো হলো; rain সারির নিজেরটাই থাকে। এই চারটি কৃত্রিম সারি “যদি রাস্তা ৬ km হতো”-র ছবি।
- অনুমান। শুকনো সারিতে ১০ + ২·৬ = ২২; বৃষ্টির সারিতে আরও ১.৫·৬ = ৯, মোট ৩১. প্রতিটি সংখ্যা একটি ICE রেখার একটি বিন্দু।
- গড়। (২২ + ৩১ + ২২ + ৩১)/৪ = ২৬.৫. এটিই PD(৬), PDP-র একটি বিন্দু।
- আরেকটি বিন্দু। road = ২ বসালে শুকনোয় ১৪, বৃষ্টিতে ১৭; গড় PD(২) = ১৫.৫.
- যা গড়ে হারায়। PDP-র ঢাল (২৬.৫ − ১৫.৫)/৪ = ২.৭৫ মিনিট প্রতি km, কিন্তু কোনো সারির ঢাল ২.৭৫ নয়: শুকনো সারির ২, বৃষ্টির ৩.৫. গড় রেখা interaction লুকায়, ICE রেখা তা দেখায়।
ICE-এর রেখাগুলো প্রায়ই আলাদা উচ্চতায় শুরু হয় (একটি অর্ডারে ৮টি পণ্য, আরেকটিতে ১টি), তাই আকারের পার্থক্য চোখে পড়ে না। সমাধান centred ICE: প্রতিটি রেখা থেকে তার প্রথম বিন্দুর মান বাদ দেওয়া, যাতে সব রেখা শূন্য থেকে শুরু হয়। তখন রেখাগুলো ছড়িয়ে গেলে বোঝা যায়, feature-টির প্রভাব সারিভেদে আলাদা, অর্থাৎ অন্য কোনো feature-এর সঙ্গে interaction আছে। দ্বিতীয় ব্লক ৩০০টি test সারিতে ICE আর PDP নিজে বানায়, partial_dependence(method="brute", kind="both")-এর সঙ্গে মেলায়, আর বৃষ্টি অনুযায়ী রং করে দুটি ছবি আঁকে।
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import HistGradientBoostingRegressor as HGB
from sklearn.inspection import partial_dependence
from bazar_eta import split
Xtr, Xte, ytr, yte = split()
m = HGB(max_iter=200, random_state=0).fit(Xtr, ytr)
S = Xte[:300] # ৩০০টি test সারি
grid = np.arange(1.0, 15.0) # road_km = 1, 2, ..., 14
ice = np.empty((len(S), len(grid))) # প্রতিটি সারির নিজের রেখা
for j, v in enumerate(grid):
Z = S.copy()
Z["road_km"] = v # সব সারিতে একই মান বসানো
ice[:, j] = m.predict(Z)
pdp = ice.mean(axis=0) # PDP = ICE রেখাগুলোর গড়
sk = partial_dependence(m, S, ["road_km"], custom_values={"road_km": grid},
method="brute", kind="both")
print("max |PDP - sklearn| =", np.abs(pdp - sk["average"][0]).max())
print("max |ICE - sklearn| =", np.abs(ice - sk["individual"][0]).max())
print("PDP at 2, 6, 10, 14 km:", pdp[[1, 5, 9, 13]].round(1))
wet = S.rain.to_numpy() == 1
slope = (ice[:, 11] - ice[:, 1]) / 10 # 2 থেকে 12 km, মিনিট প্রতি km
print(f"ICE slope min/km dry {slope[~wet].mean():.2f} rain {slope[wet].mean():.2f}"
f" PDP {(pdp[11] - pdp[1]) / 10:.2f}")
cice = ice - ice[:, [0]] # centred ICE: 1 km-এ সবাই শূন্য
fig, ax = plt.subplots(1, 2, figsize=(8, 3.4), sharex=True)
for a, Y, t in [(ax[0], ice, "ICE and PDP"), (ax[1], cice, "centred ICE")]:
a.plot(grid, Y[~wet].T, color="tab:orange", alpha=0.15, lw=0.8)
a.plot(grid, Y[wet].T, color="tab:blue", alpha=0.15, lw=0.8)
a.set(title=t, xlabel="road_km (orange = dry, blue = rain)")
ax[0].plot(grid, pdp, color="black", lw=3, label="PDP")
ax[0].set_ylabel("predicted minutes"); ax[0].legend()
fig.subplots_adjust(wspace=0.25, bottom=0.16)আসল আউটপুট (ব্রাউজারের Python; ছবিটি ব্লকের নিচে আঁকা হয়):
max |PDP - sklearn| = 4.263256414560601e-14
max |ICE - sklearn| = 0.0
PDP at 2, 6, 10, 14 km: [30.4 38.1 43.3 47.1]
ICE slope min/km dry 1.33 rain 1.98 PDP 1.54
মিল: ICE হুবহু মেলে; PDP-তে ১০−১৪ মাপের পার্থক্য শুধু গড় নেওয়ার ক্রমে দশমিকের গোলমাল। method="brute" ঠিক এই “বসাও, অনুমান করো, গড় নাও” পথ। Gradient boosting-এ "recursion" নামে একটি দ্রুত পথও আছে, যা গাছের ভেতর থেকে হিসাব করে, কিন্তু সব ক্ষেত্রে একই সংখ্যা দেয় না (পর্ব ৩৬-এ এর একটি ফাঁদ দেখেছেন)। পড়া: PDP ২ km-এ ৩০.৪ মিনিট থেকে ১৪ km-এ ৪৭.১. ICE-এর ঢাল শুকনো সারিতে গড়ে ১.৩৩ মিনিট প্রতি km, বৃষ্টিতে ১.৯৮, অনুপাত প্রায় ১.৫; আর PDP-র ১.৫৪ এই দুইয়ের মিশ্রণ, কোনো দলের সত্য নয়। ছবির ডান অংশে centred ICE দুটি স্পষ্ট গুচ্ছে ভাগ হয়: নীল রেখা (বৃষ্টি) কমলার চেয়ে খাড়া। একটি সতর্কতা: আসল নিয়মে প্রতি km ২.৪ মিনিট (বৃষ্টিতে ৪.০৮), কিন্তু এখানে ঢাল অনেক কম। কারণ PDP road বদলায় অথচ distance_km স্থির রাখে, আর model দূরত্বের তথ্যের বড় অংশ distance_km-এ রেখেছে। “অন্য কলাম স্থির রেখে” কথাটি correlated feature-এ বাস্তবে অসম্ভব একটি পরিস্থিতি বর্ণনা করে; অংশ ৭ এই সমস্যা নিয়েই।
৬ · Interaction মাপা — 2-D PDP আর Friedman-এর H-statistic
ICE-এর ছড়ানো বলে “interaction আছে”, কিন্তু কার সঙ্গে, তা বলে না। একটি পথ দুটি feature একসঙ্গে বদলানো: 2-D partial dependence PDjk(vj, vk), যা PartialDependenceDisplay.from_estimator(m, X, [("road_km", "rain")]) একটি heatmap বা দুই রেখা হিসেবে আঁকে। Interaction না থাকলে 2-D তলটি দুটি 1-D রেখার যোগফল: PDjk = PDj + PDk (তিনটিই গড় শূন্যে কেন্দ্র করে)। স্টেপারের খেলনা model-এ রাস্তা ২ থেকে ৬ km হলে শুকনোয় ৮ মিনিট বাড়ে, বৃষ্টিতে ১৪; যোগফলের নিয়ম মানলে দুটিই সমান হতো।
Jerome Friedman আর Bogdan Popescu ২০০৮ সালে এই ফাঁককে একটি সংখ্যায় আনেন, H-statistic:
H২jk = ∑i [PDjk(xij, xik) − PDj(xij) − PDk(xik)]২ / ∑i PDjk(xij, xik)২
অর্থাৎ যৌথ প্রভাবের variance-এর কত ভাগ যোগফল দিয়ে ব্যাখ্যা হয় না। H = ০ মানে কোনো interaction নেই, ১-এর কাছে মানে প্রভাবের প্রায় সবটাই যৌথ। সীমা তিনটি। হিসাব দামি: প্রতিটি সারির বিন্দুতে PDjk লাগে, তাই n সারিতে প্রায় n২টি অনুমান; চর্চায় কয়েকশো সারির নমুনা নেওয়া হয়। সংখ্যাটি নমুনাভেদে ওঠানামা করে, আর কোনো সহজ “তাৎপর্যের” সীমা নেই। আর এটিও PD-র ওপর দাঁড়ানো, তাই correlated feature-এ PDP-র সব দুর্বলতা পায়। লেখার সময়ে scikit-learn-এ H-এর তৈরি ফাংশন নেই; R-এর কিছু package-এ আর কয়েকটি Python library-তে আছে, তবে নিজে লেখাও কঠিন নয়। পর্ব ৩৬-এর interaction_cst উল্টো দিক থেকে একই প্রশ্নে হাত দেয়: কোন feature-গুলো একসঙ্গে কাজ করতে পারবে, তা শেখার আগেই বেঁধে দেওয়া।
৭ · PDP যখন ভুল বলে — অসম্ভব সারি আর ALE
PDP-র সূত্রে একটি লুকানো অনুমান আছে: S-কে v-তে বসিয়ে বাকি কলাম অপরিবর্তিত রাখা যায়, অর্থাৎ S আর C স্বাধীন। road_km আর distance_km-এর মতো ঘনিষ্ঠ জোড়ায় এটি ভাঙে। নিচের ছবিতে ধূসর কীলকটি আসল ডেটার জায়গা: রাস্তা সোজা দূরত্বের ১.০৩ থেকে ১.৬ গুণ।
PDP অসম্ভব সারি বানায়, ALE ডেটার ভেতরে থাকে
ধূসর কীলক = যেখানে আসল অর্ডার আছে; ✕ = PDP-র বানানো অসম্ভব সারি
Daniel Apley আর Jingyu Zhu-র প্রবন্ধে (২০২০ সালে Journal of the Royal Statistical Society, Series B-তে প্রকাশিত; আগে preprint হিসেবে ছড়িয়েছিল) accumulated local effects (ALE) এর সমাধান। ধাপগুলো: feature-এর পরিসরকে quantile দিয়ে K খোপে ভাগ; প্রতিটি খোপে শুধু সেই খোপের সারি নিয়ে, তাদের feature-কে খোপের নিচের কিনারা zk−1 আর উপরের কিনারা zk-এ বসিয়ে অনুমানের পার্থক্যের গড়; তারপর খোপ থেকে খোপে যোগ করে চলা, আর শেষে গড় শূন্যে কেন্দ্র করা:
ALE(zk) = ∑m=১k (১/nm) ∑i ∈ খোপ m [ f̂(zm, xi,C) − f̂(zm−১, xi,C) ] − ধ্রুবক
এখানে nm হলো খোপ m-এর সারির সংখ্যা। PDP প্রশ্ন করে “সবাইকে v-তে নিলে?”; ALE প্রশ্ন করে “যারা আসলেই v-এর কাছে আছে, তাদের একটু বদলালে?” নিচের stepper একটি খেলনা model-এ পার্থক্যটি সংখ্যায় দেখায়।
| এখন যা হচ্ছে | |
| সারি | |
| অনুমান | |
| ফল |
- Model আর ডেটা। চারটি অর্ডার road = ১.৩ × distance রেখায়। Model-এর শাস্তির পদ −২·(road − ১.৩·distance)² ডেটার ওপর শূন্য, তাই সেখানে f = ১০ + ৩·road: প্রতি km ৩ মিনিট। কিন্তু রেখার বাইরে, যেখানে কোনো অর্ডার নেই, model দ্রুত নেমে যায়, যেমন অনেক নমনীয় model অচেনা জায়গায় করে।
- PDP, road = ১০. সবার রাস্তা ১০ km বসানো। ১ km দূরের অর্ডারের জন্য শাস্তি ২·(৮.৭)² = ১৫১.৩৮, অনুমান −১১১.৩৮ মিনিট। চারটির মধ্যে তিনটি সারি অসম্ভব (অনুপাত ১০, ৫ আর ২)। গড় PD(১০) = −৩১.৪৩.
- PDP, road = ৬.৫. একইভাবে গড় PD(৬.৫) = ০.৭৭. এখানেও (৫, ৬.৫) ছাড়া বাকি তিনটি সারি কীলকের বাইরে।
- PDP-র গল্প। রাস্তা ৬.৫ থেকে ১০ km হলে গড় সময় ০.৭৭ থেকে −৩১.৪৩: “লম্বা রাস্তায় দ্রুত পৌঁছায়”, আর ঋণাত্মক মিনিট। Model-এর আসল আচরণ ডেটার ওপর ঠিক উল্টো; PDP-র গল্প পুরোটা অসম্ভব সারির।
- ALE-এর এক খোপ। খোপ [৯.৯, ১০.৯]-এ আছে শুধু (৮, ১০.৪)। তার road-কে দুই কিনারায় বসানো: f(৮, ১০.৯) = ৪২.২, f(৮, ৯.৯) = ৩৯.২. পার্থক্য ৩.০, এক km-এ। দুটি কৃত্রিম সারিই রেখা থেকে মাত্র ০.৫ km দূরে।
- যোগ করে চলা। প্রতিটি খোপে একই হিসাব দেয় প্রতি km ৩. যোগ করলে ৬.৫ থেকে ১০.৪ km-এ ALE বাড়ে ৩ × ৩.৯ = ১১.৭, যা ডেটার ওপর model-এর আসল পরিবর্তন ৪১.২ − ২৯.৫-এর সমান।
খেলনা model-টি ইচ্ছা করে চরম। বাস্তবে কি এমন হয়? তৃতীয় ব্লক একই বাজারঘর ডেটায় দ্বিতীয় একটি black box শেখায়: standardise করে degree-4 polynomial feature, তারপর পর্ব ১৭-এর ridge. Test MAE প্রায় HGB-এর সমান। তারপর road_km-এর ALE নিজে লেখে (১০টি quantile খোপ), একই বিন্দুতে PDP-র সঙ্গে তুলনা করে, আর গুনে দেখে PDP-র প্রান্তের বিন্দুতে কত ভাগ সারি অসম্ভব।
import numpy as np
import matplotlib.pyplot as plt
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_absolute_error as mae
from bazar_eta import split
Xtr, Xte, ytr, yte = split()
m = make_pipeline(StandardScaler(), PolynomialFeatures(4), Ridge(1.0)).fit(Xtr, ytr)
print(f"degree-4 polynomial ridge: test MAE {mae(yte, m.predict(Xte)):.2f} min")
f, K = "road_km", 10
z = np.quantile(Xte[f], np.linspace(0, 1, K + 1)) # quantile সীমানা
b = np.clip(np.searchsorted(z, Xte[f], side="left") - 1, 0, K - 1)
lo, hi = Xte.copy(), Xte.copy()
lo[f], hi[f] = z[b], z[b + 1] # শুধু নিজের খোপের দুই কিনারা
d = m.predict(hi) - m.predict(lo) # স্থানীয় পরিবর্তন
n = np.bincount(b, minlength=K)
acc = np.r_[0, np.cumsum(np.bincount(b, weights=d, minlength=K) / n)]
ale = acc - np.sum((acc[:-1] + acc[1:]) / 2 * n) / n.sum() # গড় শূন্যে কেন্দ্র
pdp = np.array([m.predict(Xte.assign(**{f: v})).mean() for v in z])
pdp -= pdp.mean()
print("grid :", z.round(1))
print("ALE :", ale.round(1))
print("PDP :", pdp.round(1))
print("corr(distance, road) =", round(Xte.distance_km.corr(Xte.road_km), 3))
for v in [z[0], z[-1]]: # আসল ডেটায় road/distance 1.03 থেকে 1.6
r = v / Xte.distance_km
print(f"road = {v:.1f} km: {((r < 1.03) | (r > 1.6)).mean():.0%} rows impossible")
print("impossible row (distance 1 km, road 15 km) ->",
m.predict(Xte[:1].assign(distance_km=1.0, road_km=15.0)).round(1), "min")
fig, ax = plt.subplots(figsize=(6, 3.4))
ax.plot(z, ale, "o-", label="ALE (stays on the data)")
ax.plot(z, pdp, "s--", label="PDP (averages impossible rows)")
ax.set(xlabel="road_km", ylabel="centred effect (minutes)")
ax.legend(); fig.subplots_adjust(left=0.13, bottom=0.16)আসল আউটপুট (ব্রাউজারের Python; ছবিটি ব্লকের নিচে আঁকা হয়):
degree-4 polynomial ridge: test MAE 2.88 min
grid : [ 0.6 1.9 3.2 4.6 5.8 7.1 8.3 9.5 10.7 11.8 15.2]
ALE : [-13.5 -10.1 -6.7 -3.6 -0.8 1.4 3.4 4.9 6.5 8.1 7.3]
PDP : [-19.8 -8.5 -1.8 1.9 4.2 6. 7.8 9.2 9.8 8.8 -17.6]
corr(distance, road) = 0.981
road = 0.6 km: 99% rows impossible
road = 15.2 km: 95% rows impossible
impossible row (distance 1 km, road 15 km) -> [10.3] min
দুই গল্প: ALE প্রায় একটানা বাড়ে, −১৩.৫ থেকে ৮.১ (শেষ খোপে সামান্য নামা, ৭.৩, যেখানে সারি কম আর খোপ চওড়া)। PDP মাঝখানে ALE-এর কাছাকাছি, কিন্তু দুই প্রান্তে ভেঙে পড়ে: ১৫.২ km-এ −১৭.৬, অর্থাৎ PDP বলে “সবচেয়ে লম্বা রাস্তার অর্ডার ১.৯ km-এর অর্ডারের চেয়েও দ্রুত পৌঁছায়”। কারণ পরের দুই লাইনে: ঐ দুই বিন্দুতে ৯৯% আর ৯৫% সারি অসম্ভব জায়গায়, আর একটি অসম্ভব সারিতে (১ km সোজা, ১৫ km রাস্তা) model বলে ১০.৩ মিনিট। শিক্ষা: দুটি model test-এ প্রায় সমান (MAE ২.৮৮ বনাম ২.৭৪), কিন্তু ডেটার বাইরে সম্পূর্ণ আলাদা আচরণ করে; PDP সেই বাইরের আচরণকে ফল হিসেবে দেখায়। একই ব্লক HGB-তে চালালে PDP আর ALE অনেক কাছাকাছি থাকে, কারণ গাছ ডেটার বাইরে শেষ পাতার মানে আটকে থাকে; নিরাপত্তাটি model-এর ধরনের ওপর নির্ভর করে, পদ্ধতির ওপর নয়।
ALE-এরও সীমা আছে। খোপের সংখ্যা K বেছে নিতে হয় (কম খোপে খোপ চওড়া, বেশি খোপে প্রতিটিতে সারি কম আর রেখা কাঁপে)। ALE-এর মান “অন্য feature-এর সঙ্গে যৌথভাবে বদলানো”-র প্রভাব নয়, শুধু এই feature-এর স্থানীয় প্রভাবের যোগ; তাই correlated জোড়ার প্রতিটির ALE আলাদাভাবে ছোট দেখাতে পারে। আর বিভাগীয় (categorical) feature-এ খোপের ক্রম ঠিক করা সহজ নয়। লেখার সময়ে scikit-learn-এ ALE-এর তৈরি ফাংশন নেই; কয়েকটি আলাদা Python package-এ আছে, তবে উপরের মতো বিশ লাইনের কোড প্রায়ই যথেষ্ট।
৮ · শুরু থেকেই ব্যাখ্যাযোগ্য model আর global surrogate
দুটি পথ বাকি। প্রথমটি Rudin-এর পথ: black box-ই না বানানো। পর্ব ২৩-এ দেখেছেন linear model-এ interaction আর বানানো কলাম যোগ করা যায়। সব কলাম standardise করলে (standardised coefficient) সংখ্যাগুলো তুলনীয় হয়: “এক standard deviation বদলালে কত মিনিট”। কিন্তু দুটি সতর্কতা। Coefficient অন্য সব কলাম স্থির রেখে পড়া হয়, যা correlated কলামে আবার সেই অসম্ভব পরিস্থিতি। আর multicollinearity-তে coefficient অস্থির: r = ০.৯৮১ হলে variance inflation factor প্রায় ১/(১ − ০.৯৮১²) ≈ ২৭, অর্থাৎ ঐ দুটি coefficient-এর variance স্বাধীন কলামের তুলনায় প্রায় ২৭ গুণ।
দ্বিতীয় পথ: black box রেখে তার একটি পড়ার মতো নকল বানানো। Global surrogate হলো একটি ছোট, ব্যাখ্যাযোগ্য model (প্রায়ই পর্ব ৩২-এর ছোট decision tree), যা আসল label নয়, black box-এর অনুমান শেখে। এর মান মাপা হয় fidelity দিয়ে: held-out ডেটায় surrogate black box-কে কতটা নকল করে, যেমন black box-এর অনুমানের বিপরীতে R². চতুর্থ ব্লক দুটি পথ পাশাপাশি চালায়।
import numpy as np
import pandas as pd
from sklearn.ensemble import HistGradientBoostingRegressor as HGB
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.tree import DecisionTreeRegressor, export_text
from sklearn.metrics import r2_score, mean_absolute_error as mae
from bazar_eta import split, COLS
Xtr, Xte, ytr, yte = split()
# ক) শুরু থেকেই ব্যাখ্যাযোগ্য: দুটি বানানো কলামসহ standardised linear model
def aug(X):
return X.assign(road_x_rain=X.road_km * X.rain, rush=X.hour.between(17, 20) * 1)
for half in [slice(0, 1000), slice(1000, 2000)]: # train-এর দুই অর্ধেক
lin = make_pipeline(StandardScaler(), LinearRegression())
lin.fit(aug(Xtr[half]), ytr[half])
coef = pd.Series(lin[-1].coef_, index=aug(Xtr).columns).round(2)
print(coef[["distance_km", "road_km", "road_x_rain", "rush"]].to_dict(),
f"test MAE {mae(yte, lin.predict(aug(Xte))):.2f}")
# খ) post-hoc: black box-এর অনুমানের ওপর একটি ছোট গাছ (global surrogate)
m = HGB(max_iter=200, random_state=0).fit(Xtr, ytr)
print(f"black box test MAE {mae(yte, m.predict(Xte)):.2f}, R2 vs truth "
f"{r2_score(yte, m.predict(Xte)):.3f}")
bb_tr, bb_te = m.predict(Xtr), m.predict(Xte)
for depth in [1, 2, 3, 4, 6, 8]:
t = DecisionTreeRegressor(max_depth=depth, random_state=0).fit(Xtr, bb_tr)
print(f"depth {depth}: leaves {t.get_n_leaves():3d} fidelity R2 "
f"{r2_score(bb_te, t.predict(Xte)):.3f} R2 vs truth "
f"{r2_score(yte, t.predict(Xte)):.3f}")
t3 = DecisionTreeRegressor(max_depth=3, random_state=0).fit(Xtr, bb_tr)
print(export_text(t3, feature_names=COLS, decimals=1))আসল আউটপুট (ব্রাউজারের Python):
{'distance_km': 4.69, 'road_km': 3.49, 'road_x_rain': 6.26, 'rush': 3.08} test MAE 2.52
{'distance_km': 4.63, 'road_km': 3.83, 'road_x_rain': 6.07, 'rush': 3.22} test MAE 2.49
black box test MAE 2.74, R2 vs truth 0.930
depth 1: leaves 2 fidelity R2 0.503 R2 vs truth 0.477
depth 2: leaves 4 fidelity R2 0.760 R2 vs truth 0.721
depth 3: leaves 8 fidelity R2 0.855 R2 vs truth 0.806
depth 4: leaves 16 fidelity R2 0.893 R2 vs truth 0.838
depth 6: leaves 64 fidelity R2 0.956 R2 vs truth 0.900
depth 8: leaves 250 fidelity R2 0.974 R2 vs truth 0.917
|--- distance_km <= 5.3
| |--- road_km <= 3.9
| | |--- road_km <= 2.6
| | | |--- value: [23.6]
| | |--- road_km > 2.6
| | | |--- value: [28.2]
| |--- road_km > 3.9
| | |--- rain <= 0.5
| | | |--- value: [31.4]
| | |--- rain > 0.5
| | | |--- value: [40.4]
|--- distance_km > 5.3
| |--- rain <= 0.5
| | |--- distance_km <= 8.2
| | | |--- value: [39.5]
| | |--- distance_km > 8.2
| | | |--- value: [47.2]
| |--- rain > 0.5
| | |--- road_km <= 9.1
| | | |--- value: [51.4]
| | |--- road_km > 9.1
| | | |--- value: [63.9]
শুরু থেকেই ব্যাখ্যাযোগ্য: দুটি বানানো কলাম (road_x_rain আর সন্ধ্যার rush) নিয়ে একটি সাধারণ linear model-এর test MAE ২.৫২ আর ২.৪৯ মিনিট, black box-এর ২.৭৪-এর চেয়েও কম। এই ডেটায় আসল নিয়ম প্রায় linear আর interaction-টি জানা, তাই ফলটি অবাক করার মতো নয়; বাস্তবে এমন জ্ঞান ডোমেইন বিশেষজ্ঞ, EDA আর ICE-এর মতো যন্ত্র থেকে আসে। Train-এর দুই অর্ধেকে distance_km আর road_km-এর coefficient ৪.৬৯/৩.৪৯ বনাম ৪.৬৩/৩.৮৩: যোগফল (৮.১৮ বনাম ৮.৪৬) বেশি স্থির, ভাগাভাগি কম। Surrogate: গভীরতা ১-এর গাছ (দুটি পাতা) black box-এর মাত্র ৫০% নকল করে; গভীরতা ৩-এ আটটি পাতা, fidelity ০.৮৫৫; গভীরতা ৮-এ ০.৯৭৪, কিন্তু ২৫০টি পাতা আর কেউ পড়তে পারবে না। গভীরতা ৩-এর গাছটি পড়া যায়: প্রথম ভাগ দূরত্বে, তারপর রাস্তা আর বৃষ্টি; বৃষ্টির শাখায় লম্বা রাস্তায় ৬৩.৯ মিনিট। items আর hour এই ছোট গাছে নেই, যদিও black box তাদের ব্যবহার করে (importance ০.৯৬ আর ১.৬৮): surrogate-এর ১৪.৫% অব্যাখ্যাত অংশে তারা লুকিয়ে আছে।
Surrogate black box-এর ব্যাখ্যা, black box নয়। Fidelity ০.৮৫৫ মানে black box-এর আচরণের প্রায় ১৫% surrogate-এ নেই, আর সেই অংশ ঠিক কোথায় তা গাছ বলে না; কিছু এলাকায় নকল অনেক খারাপ হতে পারে। তাই fidelity সবসময় held-out ডেটায় মাপুন, এলাকা ধরে (যেমন বৃষ্টি বনাম শুকনো) আলাদাভাবেও দেখুন, আর surrogate-এর কোনো নিয়মকে “model এভাবে ভাবে” বলবেন না।
আরও গভীরে: Aaron Fisher, Cynthia Rudin আর Francesca Dominici ২০১৯ সালে JMLR-এ “model class reliance” প্রস্তাব করেন: প্রায় সমান ভালো সব model-এর মধ্যে একটি feature-এর importance-এর পরিসর। একই ডেটায় প্রায় সমান accuracy-র বহু ভিন্ন model থাকতে পারে, যাকে Breiman ২০০১ সালে “Rashomon effect” বলেছিলেন (Rashomon effect); তৃতীয় ব্লকের দুই model তার ছোট উদাহরণ। ব্যাখ্যাযোগ্য অথচ শক্তিশালী model-এর একটি আধুনিক উদাহরণ explainable boosting machine (EBM), যা প্রতিটি feature-এর জন্য আলাদা বাঁকা রেখা আর বাছাই করা কয়েকটি জোড়া-interaction শেখে; GAM-এর ধারণার বিস্তার। Surrogate tree-এর ধারণা অন্তত ১৯৯০-এর দশকের মাঝামাঝি থেকে আছে (যেমন Craven আর Shavlik-এর neural network থেকে গাছ বের করার কাজ)।
পরীক্ষা ও ইন্টারভিউতে: (১) Permutation importance train না test ডেটায়? Held-out ডেটায়; train-এ মুখস্থ করা noise-ও গুরুত্ব পায়। (২) দুটি correlated feature-এর importance দুটিই কম, মানে কী? তথ্যটি দুজনে ভাগ করে; grouped permutation বা দল ধরে drop-column দিয়ে দেখুন। (৩) PDP আর ICE-এর সম্পর্ক? PDP = ICE রেখাগুলোর গড়; ICE ছড়ালে interaction. (৪) PDP-র মূল অনুমান কী, আর ভাঙলে বিকল্প? Feature-টি বাকিদের থেকে স্বাধীন; ভাঙলে ALE. (৫) Surrogate-এর fidelity কী? Surrogate black box-এর অনুমান কতটা নকল করে, held-out ডেটায় R² বা accuracy.
৯ · AI-এর যুগে — ব্যাখ্যার কোড আর ব্যাখ্যার দাবি যাচাই
“আমার model-এর feature importance দেখাও” বললে AI assistant সাধারণত মিনিটে একটি সুন্দর bar chart দেয়। সমস্যা chart-এ নয়, তার নিচের সিদ্ধান্তগুলোতে: কোন ডেটায়, কোন score-এ, কতবার, আর correlated কলামের কী হলো। নিচের ভুলগুলো প্রায়ই চোখে পড়ে।
| AI প্রায়ই যা করে | কেন সমস্যা | কীভাবে ধরবেন |
|---|---|---|
Train ডেটায় permutation importance বা feature_importances_ দেখায় | মুখস্থ করা noise-ও গুরুত্ব পায় | Held-out ডেটা, n_repeats ≥ ৫, sd-সহ; একটি এলোমেলো কলাম তুলনার জন্য |
| Importance বা SHAP-কে কারণ হিসেবে লেখে (“দূরত্ব কমালে…”) | এগুলো model-এর নির্ভরতা, কার্যকারণ নয় | দাবিটি model নিয়ে না দুনিয়া নিয়ে, আলাদা করে লিখুন |
| Correlated কলামের একক importance-এর ক্রম ধরে কলাম বাদ দিতে বলে | ভাগাভাগির কারণে দুটিই কম দেখায় | Correlation দেখে দল বানান; grouped permutation বা drop-column |
| PDP দেখিয়ে “X বাড়লে y এভাবে বাড়ে” বলে | Correlated feature-এ PDP অসম্ভব সারির গড়; interaction লুকায় | ICE, centred ICE আর ALE পাশাপাশি; ডেটার ঘনত্ব (rug) দেখান |
| পুরোনো বা বানানো API লেখে | যেমন plot_partial_dependence (পুরোনো version-এ ছিল, এখন সরানো) বা অস্তিত্বহীন permutation_importance(..., features=) | নিজের version-এর docs; ছোট উদাহরণে চালিয়ে হাতে করা সংখ্যার সঙ্গে মেলান |
AI-কে কোডের সঙ্গে সিদ্ধান্ত আর যাচাইও চাইতে বলুন:
AI-এর দেওয়া ব্যাখ্যার কোড হাতে পেলে — যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১Black box ব্যাখ্যা করব, নাকি ব্যাখ্যাযোগ্য model বানাব? Rudin-এর যুক্তি আর তার সমালোচনা
২০১০-এর দশকের মাঝামাঝি থেকে ML-এর ব্যাখ্যা নিয়ে গবেষণা দ্রুত বাড়ে। LIME (২০১৬) আর SHAP (২০১৭)-এর মতো পদ্ধতি যেকোনো model-এর পাশে ব্যাখ্যা জুড়ে দেওয়ার প্রতিশ্রুতি দেয়, আর মার্কিন প্রতিরক্ষা গবেষণা সংস্থা DARPA ২০১৭ সালের দিকে “Explainable AI” নামে একটি বড় কর্মসূচি শুরু করে। প্রচলিত ধারণা দাঁড়ায়: আগে শক্তিশালী model, পরে তার পাশে ব্যাখ্যা।
Cynthia Rudin ২০১৯ সালে Nature Machine Intelligence-এ এই ধারণার বিরুদ্ধে লেখেন। তাঁর যুক্তিগুলো মোটামুটি এমন। প্রথম, post-hoc ব্যাখ্যা সংজ্ঞা অনুযায়ী আসল model-এর সঙ্গে পুরো মেলে না; মিললে ব্যাখ্যাটিই model হতো। দ্বিতীয়, ভুল ব্যাখ্যা আস্থা তৈরি করে যেখানে আস্থার কারণ নেই। তৃতীয়, tabular ডেটায় সুগঠিত feature থাকলে ব্যাখ্যাযোগ্য model আর জটিল model-এর accuracy-র ফাঁক প্রায়ই ছোট। তিনি বিশেষভাবে বিচার, ঋণ আর স্বাস্থ্যের মতো উচ্চ ঝুঁকির সিদ্ধান্তের কথা বলেন, যেখানে একজন মানুষের জীবন বদলে যায়।
সমালোচনাও আছে। ছবি, শব্দ বা লম্বা লেখার মতো ডেটায় ব্যাখ্যাযোগ্য model-এর accuracy অনেক পিছিয়ে থাকতে পারে। “ব্যাখ্যাযোগ্য” শব্দটিও আপেক্ষিক: ৪০টি feature-এর linear model বা ২০০ পাতার গাছ কাগজে স্বচ্ছ, কিন্তু মানুষের মাথায় নয়। আর ব্যাখ্যাযোগ্য model বানাতে বাড়তি ডোমেইন জ্ঞান আর সময় লাগে, যা সব দলের নেই।
এই পর্বের সংখ্যা Rudin-এর পক্ষে একটি ছোট উদাহরণ: দুটি বানানো কলামসহ linear model black box-এর চেয়ে কম MAE দেয়। কিন্তু মনে রাখুন, এখানে আসল নিয়ম আমরা নিজেরাই linear আকারে বানিয়েছি। বাস্তব সিদ্ধান্ত তাই প্রমাণনির্ভর: প্রথমে একটি শক্ত ব্যাখ্যাযোগ্য baseline, তারপর black box; ফাঁক ছোট হলে ব্যাখ্যাযোগ্যটি রাখা, বড় হলে কেন বড়, তা ICE আর ALE দিয়ে খুঁজে বের করে আবার ব্যাখ্যাযোগ্য model-এ ফিরিয়ে আনার চেষ্টা।
মূল উপলব্ধি: ব্যাখ্যা আর ব্যাখ্যাযোগ্যতা এক নয়; উচ্চ ঝুঁকির জায়গায় আগে দেখুন ব্যাখ্যাযোগ্য model যথেষ্ট কি না, আর black box রাখলে তার ব্যাখ্যাকে নকল হিসেবেই পড়ুন।
প্র ০২Breiman-এর random forest থেকে আজকের permutation importance: পদ্ধতিটি কীভাবে বদলেছে, আর কোন ফাঁদ নিয়ে বিতর্ক চলছে?
Leo Breiman ২০০১ সালে random forest-এর প্রবন্ধে একটি সরল কৌশল দেন: প্রতিটি গাছের out-of-bag সারিতে একটি feature এলোমেলো করে ভুল কত বাড়ে, তা দেখা। কৌশলটির শক্তি তার সরলতা: model-এর ভেতরে না ঢুকে শুধু অনুমান দিয়ে কাজ। পরে এটি যেকোনো model-এ খাটানো হয়, আর scikit-learn ০.২২ version (২০১৯) থেকে permutation_importance নামে যেকোনো estimator-এর জন্য দেয়।
বিতর্ক তিনটি দিকে। প্রথম, ২০০৭ আর ২০০৮ সালে Carolin Strobl ও সহকর্মীরা দেখান, impurity-ভিত্তিক importance বেশি মানের feature-এর দিকে ঝোঁকে (পর্ব ৩৩-এর ID কলামের demo), আর correlated feature-এ সাধারণ permutation অসম্ভব সারি বানায়। তাঁরা conditional permutation প্রস্তাব করেন: সঙ্গী feature-এর মান অনুযায়ী ছোট দলের ভেতরে এলোমেলো করা। দ্বিতীয়, ২০২১ সালে Giles Hooker, Lucas Mentch আর Siyu Zhou “permute-and-predict” পদ্ধতিগুলোর একটি বিস্তৃত সমালোচনা প্রকাশ করেন: এরা model-কে ডেটার বাইরে extrapolate করতে বাধ্য করে, আর তার ফল প্রায়ই বিভ্রান্তিকর। তাঁরা বিকল্প হিসেবে conditional permutation আর কলাম বাদ দিয়ে আবার শেখানোর (drop-column-এর মতো) পথের পক্ষে যুক্তি দেন। তৃতীয়, প্রশ্নটি দার্শনিকও: “এই শেখানো model কলামটি কতটা ব্যবহার করে” আর “ডেটায় কলামটির অনন্য তথ্য কতটা” দুটি আলাদা প্রশ্ন, আর পদ্ধতি বাছাই নির্ভর করে কোনটি জানতে চান তার ওপর।
এই পর্বের ব্লক তিনটি উত্তর পাশাপাশি দেখিয়েছে: একক permutation (৩.৩৩ আর ৪.৬১), grouped (৯.৬২) আর drop-column (০.১১ আর ০.২১; দুটি একসঙ্গে ৬.৯০)। কোনোটি “ভুল” নয়; প্রত্যেকটি ভিন্ন প্রশ্নের সঠিক উত্তর। ভুল হয় যখন একটির সংখ্যা দিয়ে আরেকটির প্রশ্নের উত্তর দেওয়া হয়, যেমন “permutation importance কম, তাই কলামটি ফেলে দিই”, অথচ একক importance কম হয়েছিল ভাগাভাগির কারণে।
চর্চায় একটি ভালো অভ্যাস: একটি পুরো এলোমেলো কলাম যোগ করা, আর যে feature সেই কলামের চেয়ে ভালো নয়, তাকে নিয়ে কোনো দাবি না করা। আরেকটি: cross-validation-এর প্রতিটি fold-এ importance মেপে fold-ভেদে ওঠানামা দেখা, কারণ n_repeats-এর sd শুধু এলোমেলো করার দৈবতা ধরে, model শেখানোর দৈবতা নয়।
মূল উপলব্ধি: Permutation importance একটি নির্দিষ্ট প্রশ্নের উত্তর দেয়; correlated feature-এ সেই প্রশ্নটি বিভ্রান্তিকর হতে পারে, তাই প্রশ্ন স্পষ্ট করে grouped, conditional বা drop-column বেছে নিন।
প্র ০৩Friedman-এর PDP থেকে Goldstein-এর ICE আর Apley-র ALE: প্রতিটি নতুন পদ্ধতি আগেরটির কোন দুর্বলতা সারাতে এসেছিল?
Jerome Friedman ২০০১ সালে Annals of Statistics-এ gradient boosting-এর প্রবন্ধে শুধু একটি algorithm দেননি, তার ফল পড়ার যন্ত্রও দিয়েছিলেন: relative importance আর partial dependence plot. যুক্তি ছিল সরল: একটি বা দুটি feature-এর ওপর model-এর “গড় নির্ভরতা” দেখতে বাকি feature-গুলোর ওপর গড় নেওয়া। তিনি নিজেই সতর্ক করেছিলেন যে প্রবল interaction বা correlation থাকলে এই গড় বিভ্রান্তিকর হতে পারে।
প্রথম দুর্বলতা: গড় interaction লুকায়। একটি feature-এর প্রভাব অর্ধেক সারিতে ধনাত্মক আর অর্ধেকে ঋণাত্মক হলে PDP প্রায় সমতল, যেন feature-টি অর্থহীন। Alex Goldstein, Adam Kapelner, Justin Bleich আর Emil Pitkin ২০১৫ সালে Journal of Computational and Graphical Statistics-এ ICE প্রস্তাব করেন: গড় না নিয়ে প্রতিটি সারির রেখা আঁকা, আর centred ICE দিয়ে আকারের পার্থক্য স্পষ্ট করা। এই পর্বে ICE দেখিয়েছে বৃষ্টি আর শুকনো দিনের ঢাল প্রায় দেড় গুণ আলাদা, যা PDP-র একক রেখা বলেনি।
দ্বিতীয় দুর্বলতা: independence অনুমান। ICE নিজেও PDP-র মতো প্রতিটি সারিকে পুরো পরিসরে টেনে নেয়, তাই অসম্ভব সারির সমস্যা ICE-তেও আছে। একটি সহজ বিকল্প ছিল “M-plot”: শুধু v-এর কাছের সারিগুলোর অনুমানের গড়, অর্থাৎ শর্তসাপেক্ষ গড়। কিন্তু তাতে correlated সঙ্গীর প্রভাবও মিশে যায়: রাস্তার M-plot-এ সোজা দূরত্বের প্রভাবও ঢুকে পড়ে। Daniel Apley আর Jingyu Zhu-র ALE (preprint ২০১৬-র দিকে, জার্নালে ২০২০) দুটির মাঝের পথ নেয়: শর্তসাপেক্ষ বণ্টন থেকে সারি নেয়, কিন্তু শুধু feature-টির ছোট বদলের প্রভাব মাপে, তাই সঙ্গীর প্রভাব বাদ পড়ে আর অসম্ভব সারিও তৈরি হয় না। বাড়তি সুবিধা: হিসাব দ্রুত, প্রতিটি সারিতে মাত্র দুটি অনুমান।
তবু কোনোটিই চূড়ান্ত নয়। ALE-এর খোপের সংখ্যা ফলকে প্রভাবিত করে, আর ALE-এর অর্থ (“স্থানীয় প্রভাবের যোগ”) ব্যবসার মানুষকে বোঝানো PDP-র চেয়ে কঠিন। চর্চায় তিনটি একসঙ্গে দেখা ভালো: PDP-র সঙ্গে ICE, আর correlated feature থাকলে ALE; তিনটি একমত হলে আস্থা বাড়ে, না হলে কারণ খোঁজা।
মূল উপলব্ধি: PDP গড় নেয় আর ডেটার বাইরে যায়; ICE গড়ের নিচে লুকানো ভিন্নতা দেখায়, ALE ডেটার ভেতরে থাকে; প্রতিটি যন্ত্রের অনুমান জেনে একসঙ্গে ব্যবহার করুন।
প্র ০৪ব্যাখ্যা কেন কার্যকারণের দাবি নয়? বাজারঘরের একটি সিদ্ধান্ত দিয়ে ভাবুন
ধরুন বাজারঘরের ব্যবস্থাপক importance chart দেখলেন: distance_km বড় গুরুত্বের। সিদ্ধান্ত নিলেন, দূরের অর্ডারে ডেলিভারি চার্জ বাড়বে। Simulation-এ জানা, সোজা দূরত্ব সময় ঠিক করে না, ঠিক করে আসল পথ। Model সোজা দূরত্ব ব্যবহার করে কারণ সেটি পথের একটি ভালো ছায়া। এখানে সিদ্ধান্তটি হয়তো তবু চলবে, কারণ ছায়াটি স্থির। কিন্তু যদি শহরে নতুন সেতু খোলে, সোজা দূরত্ব একই থাকবে অথচ পথ ছোট হবে: model-এর ভরসা ভাঙবে, আর ব্যাখ্যার ওপর দাঁড়ানো নীতিও।
সমস্যার মূল হলো, model শেখে সম্পর্ক, প্রক্রিয়া নয়। Permutation importance, PDP আর ALE সবই model-এর ওপর প্রশ্ন: “এই কলাম বদলালে model-এর অনুমান কী হয়?” কার্যকারণের প্রশ্ন আলাদা: “দুনিয়ায় এই জিনিস বদলালে ফল কী হয়?” দুটি এক হয় শুধু বিশেষ অবস্থায়: model আসল প্রক্রিয়ার কাছাকাছি, কোনো লুকানো confounder নেই, আর feature-টি সত্যিই বাইরে থেকে বদলানো যায়। Qingyuan Zhao আর Trevor Hastie ২০২১ সালে (Journal of Business & Economic Statistics) আলোচনা করেন, কোন শর্তে PDP-কে কার্যকারণের আলোয় পড়া যায়: মূলত যখন feature-গুলোর কার্যকারণ-কাঠামো জানা আর বাকি feature-গুলো সঠিক adjustment set; তাঁরা নিজেরাই বলেন, এ শর্তগুলো বাস্তবে প্রায়ই পূরণ হয় না।
একটি চেনা ফাঁদ: rain-এর বড় importance দেখে কেউ বলতে পারেন “বৃষ্টি ডেলিভারি ধীর করে”। এখানে তা সত্য, কারণ simulation-এ আমরা তাই লিখেছি। কিন্তু একই সংখ্যা আসত যদি বৃষ্টির দিনে কোনো কারণে শুধু দূরের এলাকার অর্ডার বেশি আসত। Importance এই দুই জগৎকে আলাদা করতে পারে না।
তাহলে ব্যাখ্যার কাজ কী? তিনটি সৎ ব্যবহার আছে। Debug: model অদ্ভুত কিছু ধরেছে কি না (leakage, ID কলাম, সময়ের ছাপ)। আস্থা যাচাই: ডোমেইন জ্ঞানের সঙ্গে দিক মেলে কি না। আর অনুমান তৈরি: “বৃষ্টি আর রাস্তার interaction আছে”, যা পরে পরীক্ষা বা পর্ব ৬২–৬৪-এর A/B test আর causal inference-এর মতো নকশায় যাচাই করা যায়।
মূল উপলব্ধি: ব্যাখ্যা model-এর আচরণ বর্ণনা করে; নীতির সিদ্ধান্ত নিতে চাইলে কার্যকারণের আলাদা প্রমাণ লাগে, আর ব্যাখ্যা সেই প্রমাণ খোঁজার সূচনা মাত্র।
প্র ০৫Rashomon effect: সমান ভালো দুটি model দুই রকম ব্যাখ্যা দিলে কোনটি বিশ্বাস করবেন?
Akira Kurosawa-র ১৯৫০ সালের ছবি “Rashomon”-এ একই ঘটনার চারটি ভিন্ন বর্ণনা আছে, সবগুলোই বিশ্বাসযোগ্য। Leo Breiman ২০০১ সালে Statistical Science-এ “Statistical Modeling: The Two Cultures” প্রবন্ধে এই নাম ধার করেন: একই ডেটায় প্রায় সমান ভুলের অনেক ভিন্ন model থাকে, যারা ভিন্ন feature-কে গুরুত্ব দেয়।
এই পর্বে তার একটি ছোট রূপ দেখেছেন। HGB আর degree-4 polynomial ridge-এর test MAE প্রায় সমান (২.৭৪ বনাম ২.৮৮), কিন্তু ডেটার বাইরে তাদের আচরণ সম্পূর্ণ আলাদা: polynomial model ১৫ km রাস্তার অর্ডারকে ১০.৩ মিনিটে পৌঁছে দেয়। আরও সূক্ষ্ম উদাহরণ: HGB-তে seed বা max_features বদলালে distance_km আর road_km-এর মধ্যে ভাগাভাগি বদলাতে পারে, অথচ accuracy প্রায় একই থাকে।
এর ফল গুরুতর। একজন বিশ্লেষক একটি model-এর importance দেখে বলেন “road বেশি গুরুত্বপূর্ণ”, আরেকজন সমান ভালো আরেকটি model দেখে বলেন “distance”. দুজনই নিজের model সম্পর্কে সঠিক, কিন্তু দুনিয়া সম্পর্কে কেউই কিছু প্রমাণ করেননি। Aaron Fisher, Cynthia Rudin আর Francesca Dominici ২০১৯ সালে এর জন্য “model class reliance” প্রস্তাব করেন: প্রায় সমান ভালো সব model-এর মধ্যে একটি feature-এর সর্বনিম্ন আর সর্বোচ্চ নির্ভরতা। পরিসরের নিম্নসীমা শূন্যের কাছে হলে কোনো ভালো model ঐ feature ছাড়াই চলতে পারে।
চর্চায় কয়েকটি সহজ অভ্যাস এই সমস্যা কমায়: কয়েকটি seed আর কয়েকটি model family-তে importance দেখা; correlated feature-কে দলে বিচার করা; আর ডেটার বাইরের আচরণ (অসম্ভব সারিতে অনুমান) আলাদাভাবে পরীক্ষা করা, কারণ সেখানেই সমান ভালো model-গুলো সবচেয়ে বেশি আলাদা হয়। Rudin-এর দলের আরেকটি পর্যবেক্ষণ আশাব্যঞ্জক: Rashomon set বড় হলে তার মধ্যে একটি সরল, ব্যাখ্যাযোগ্য model থাকার সম্ভাবনাও বেশি।
মূল উপলব্ধি: একটি model-এর ব্যাখ্যা সেই model-এর সত্য, ডেটার নয়; সমান ভালো model-গুলোর মধ্যে একমত হওয়া ব্যাখ্যাই বেশি বিশ্বাসযোগ্য।
অনুশীলন
হিসাবগুলো খাতায় করুন, তারপর উত্তর মেলান। চাইলে পাতার ব্লকগুলোতে সংখ্যা বদলে যাচাই করুন।
-
পূর্ণ numerical: Model ŷ = ৫ + ২·x1 + ৪·x2. চারটি test সারি (x1, x2, y): (১, ০, ৮), (২, ১, ১৩), (৩, ০, ১১), (৪, ১, ১৭). (ক) আসল MAE কত? (খ) x2 কলাম এলোমেলো করে নতুন ক্রম দাঁড়াল ১, ০, ১, ০ (আসল ছিল ০, ১, ০, ১)। এই একবারের permutation importance কত? (গ) x1-এর PD(৩) কত?
(ক) অনুমান: ৭, ১৩, ১১, ১৭; ভুল ১, ০, ০, ০; MAE = ০.২৫.
(খ) এলোমেলো x2 = ১, ০, ১, ০. নতুন অনুমান: ৫ + ২ + ৪ = ১১, ৫ + ৪ + ০ = ৯, ৫ + ৬ + ৪ = ১৫, ৫ + ৮ + ০ = ১৩. ভুল: |৮ − ১১| = ৩, |১৩ − ৯| = ৪, |১১ − ১৫| = ৪, |১৭ − ১৩| = ৪; MAE = ১৫/৪ = ৩.৭৫. Importance = ৩.৭৫ − ০.২৫ = ৩.৫০.
(গ) সব সারিতে x1 = ৩, x2 নিজের: ৫ + ৬ + ৪·(০, ১, ০, ১) = ১১, ১৫, ১১, ১৫; গড় PD(৩) = ১৩. Linear model-এ PDP-র ঢাল ঠিক coefficient ২; ICE রেখাগুলো সমান্তরাল, কারণ কোনো interaction নেই।
-
আউটপুট অনুমান: একটি দলের ডেটায়
temp_cআরtemp_f(একই তাপমাত্রা, সেলসিয়াস আর ফারেনহাইটে) দুটি কলাম আছে, আর আসল ফল শুধু তাপমাত্রার ওপর নির্ভর করে। একটি gradient boosting model শেখানো হলো। নিচের প্রতিটির ফল আন্দাজ করুন: (ক) দুটির একক permutation importance; (খ) দুটি একসঙ্গে grouped permutation; (গ)temp_f-এর drop-column importance; (ঘ)temp_c-এর PDP-তে অসম্ভব সারির ভাগ।(ক) দুটিই মাঝারি, আর ভাগাভাগি দৈব: গাছ কখনো একটিতে ভাগ করে, কখনো অন্যটিতে। দুটির যোগ grouped-এর চেয়ে কম বা বেশি হতে পারে; বেশি হলে কারণ অসম্ভব জোড়া (৩০°C, ৫০°F)-তে model-এর অদ্ভুত অনুমান। (খ) বড়: তাপমাত্রার পুরো তথ্য হারায়, আর জোড়া সম্পর্ক অটুট থাকে। (গ) প্রায় শূন্য:
temp_cএকই তথ্য পুরোটা বহন করে, নতুন model তা দিয়ে কাজ চালায়। (ঘ) প্রায় সব সারি: দুটি কলামের সম্পর্ক নিখুঁত, তাই নিজের মানের বাইরে যেকোনোtemp_cবসালেই জোড়াটি অসম্ভব। ALE এখানে খোপের ভেতরেও সামান্য অসম্ভব সারি বানায়, তবে খোপ ছোট হলে দূরত্ব ছোট। সবচেয়ে ভালো সমাধান সহজ: একটি কলাম বাদ দেওয়া। -
নকশা ও সমালোচনা: একটি রিপোর্টে লেখা: “আমাদের churn model-এর permutation importance (training ডেটায়, একবার এলোমেলো করে) অনুযায়ী
app_opens_last_weekসবচেয়ে গুরুত্বপূর্ণ। PDP দেখায় app খোলা বাড়লে churn কমে। তাই সবাইকে বেশি notification পাঠানো হবে।” অন্তত চারটি সমস্যা চিহ্নিত করুন আর একটি ভালো বিশ্লেষণ-পরিকল্পনা দিন।সমস্যা: (১) Training ডেটায় মাপা: মুখস্থ করা noise-ও গুরুত্ব পায়; held-out লাগে। (২) একবার এলোমেলো: spread অজানা;
n_repeatsআর sd লাগে। (৩)app_opensসম্ভবত অন্য সক্রিয়তার কলামের (অর্ডার, cart) সঙ্গে ঘনিষ্ঠ; একক importance আর PDP দুটিই বিভ্রান্ত হতে পারে। (৪) সবচেয়ে বড়: কার্যকারণের লাফ। সক্রিয় ক্রেতা app বেশি খোলেন আর কম চলে যান; notification দিয়ে app খোলানো সক্রিয়তা তৈরি করে না, উল্টো বিরক্ত করে churn বাড়াতেও পারে। (৫) PDP-র গড় ভিন্ন দলের উল্টো প্রভাব লুকাতে পারে।পরিকল্পনা: held-out ডেটায় MAE বা log loss-এ permutation importance,
n_repeats= ১০, একটি এলোমেলো কলামসহ; সক্রিয়তার কলামগুলো দলে বেঁধে grouped importance; ICE আর ALE দিয়ে দিক যাচাই; তারপর নীতির প্রশ্ন (“notification কি churn কমায়?”) একটি এলোমেলো A/B test-এ, যেমন পর্ব ৬২ (A/B test-এর পরিকল্পনা — power, sample size আর peeking-এর ফাঁদ)-এ আসবে। -
কোড: তৃতীয় ব্লকের ALE অংশকে একটি ফাংশন
ale(model, X, f, K)বানান, তারপর HGB model-এroad_km-এর ALE আর PDP তুলনা করুন। K = ৫, ১০ আর ২০-এ ALE কতটা বদলায়?def ale(model, X, f, K=10): z = np.quantile(X[f], np.linspace(0, 1, K + 1)) b = np.clip(np.searchsorted(z, X[f], side="left") - 1, 0, K - 1) lo, hi = X.copy(), X.copy() lo[f], hi[f] = z[b], z[b + 1] d = model.predict(hi) - model.predict(lo) n = np.bincount(b, minlength=K) acc = np.r_[0, np.cumsum(np.bincount(b, weights=d, minlength=K) / n)] return z, acc - np.sum((acc[:-1] + acc[1:]) / 2 * n) / n.sum()একটি local run-এ (একই ডেটা, একই HGB) যা পাওয়া গেল: ALE আর PDP-র আকার কাছাকাছি, কারণ গাছ ডেটার বাইরে শেষ পাতার মানে আটকে থাকে; পার্থক্য মূলত দুই প্রান্তে, যেখানে PDP একটু চ্যাপ্টা (K = ২০-এ শেষ বিন্দু ৮.২ বনাম ALE-এর ১১.০, প্রথম বিন্দু −৮.২ বনাম −৯.৯)। K বাড়লে ALE-এর খাঁজ বাড়ে: রেখাটি K = ৫-এ একবারও নামে না, K = ১০-এ একবার, K = ২০-এ চারবার, কারণ প্রতিটি খোপে মাত্র ৫০টি সারি থাকে আর গাছের ধাপগুলো খোপের কিনারায় ধরা পড়ে। Quantile খোপ বলে কোনো খোপ খালি হয় না; সমান-চওড়া খোপ নিলে প্রান্তের খোপে সারি কম পড়ত। এগুলো একটি ভাগের একটি run, তাই seed বদলে দেখে নিন।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি feature-এর ALE হাতে বানানোর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- Feature-এর পরিসরকে quantile দিয়ে K খোপে ভাগ করা
- প্রতিটি সারি কোন খোপে পড়ে, তা ঠিক করা
- প্রতিটি সারির feature খোপের দুই কিনারায় বসিয়ে দুটি অনুমান নেওয়া
- প্রতিটি খোপে অনুমানের পার্থক্যের গড় বের করা
- খোপ থেকে খোপে গড়গুলো যোগ করে চলা
- পুরো রেখাকে গড় শূন্যে কেন্দ্র করা
একটি model-এ test ডেটায় MAE ২.০. একটি কলাম তিনবার এলোমেলো করলে MAE হয় ৫.০, ৬.০ আর ৪.০. এই কলামের permutation importance-এর গড় আর sd (n দিয়ে ভাগ) কত?
- গড় ৫.০, sd ০.৮২
- গড় ৩.০, sd ০
- গড় ৩.০, sd প্রায় ০.৮২
- গড় ২.৫, sd প্রায় ০.৪১
দুটি feature-এর correlation ০.৯৮. প্রতিটির একক permutation importance ১.২ আর ১.৫, আর দুটির grouped permutation importance ৮.০. সবচেয়ে যুক্তিসংগত ব্যাখ্যা কোনটি?
- দুটি feature-ই প্রায় অপ্রয়োজনীয়
- তথ্যটি দুটির মধ্যে ভাগ হয়েছে; দল হিসেবে দুটি খুব গুরুত্বপূর্ণ
- হিসাবে ভুল আছে, কারণ grouped মান যোগফল ২.৭ হওয়া উচিত
- দ্বিতীয় feature প্রথমটির কারণ
Model f = ১০ + ২·x + ৩·x·z, যেখানে z হলো ০ বা ১. তিনটি সারির z = ০, ১, ১. x-এর partial dependence PD(২) কত?
- ১৪
- ২০
- ১৭
- ১৮
একটি feature-এর PDP প্রায় সমতল, কিন্তু centred ICE রেখাগুলোর অর্ধেক উপরে আর অর্ধেক নিচে ছড়িয়ে যায়। কোন সিদ্ধান্ত সবচেয়ে ঠিক?
- Feature-টির প্রভাব আছে, কিন্তু অন্য feature-এর সঙ্গে interaction-এ দুই দলে উল্টো
- Feature-টি model-এ অপ্রয়োজনীয়, বাদ দেওয়া যায়
- Centred ICE-এর হিসাবে ভুল আছে
- Feature-টি কারণ হিসেবে প্রমাণিত, শুধু দিক অজানা
ডেটায় রাস্তার দূরত্ব সবসময় সোজা দূরত্বের ১.০৩ থেকে ১.৬ গুণ। রাস্তার দূরত্বের PDP একটি নমনীয় model-এ লম্বা রাস্তায় হঠাৎ নেমে যায়, কিন্তু ALE বাড়তেই থাকে। কোন ব্যাখ্যা সবচেয়ে ঠিক?
- ALE-এর খোপ ভুল, PDP-ই সঠিক
- দুটি আলাদা model ব্যবহার হয়েছে বলে
- PDP অসম্ভব (সোজা দূরত্ব, রাস্তা) জোড়ার অনুমানের গড় নেয়, ALE ডেটার ভেতরে থাকে
- লম্বা রাস্তায় সত্যিই ডেলিভারি দ্রুত হয়
একটি black box-এর global surrogate গভীরতা ৩-এর decision tree. held-out ডেটায় black box-এর অনুমানের বিপরীতে surrogate-এর R² ০.৬০. সবচেয়ে ঠিক পড়া কোনটি?
- Surrogate আসল label-এর ৬০% ব্যাখ্যা করে, তাই black box-এর চেয়ে ভালো
- Surrogate black box-এর আচরণের বড় অংশ ধরে না; এর নিয়মকে black box-এর বর্ণনা ভাবা বিপজ্জনক
- গভীরতা বাড়ালে fidelity কমবে
- Surrogate দেখায় black box-এর ভুলগুলো কোথায়
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে।
মনে রাখুন
- Global বনাম local, শুরু থেকে বনাম পরে: ব্যাখ্যা model-এর আচরণের বর্ণনা, কার্যকারণ নয়; উচ্চ ঝুঁকিতে আগে ব্যাখ্যাযোগ্য model যথেষ্ট কি না দেখুন।
- Permutation importance: held-out ডেটায়, নিজের score-এ,
n_repeatsদিয়ে গড় আর sd; train ডেটায় noise-ও গুরুত্ব পায়। - Correlated feature: একক importance ভাগ হয় আর অসম্ভব সারি বানায়; grouped permutation দলের তথ্য মাপে, drop-column অনন্য তথ্য মাপে (দাম: বারবার training).
- PDP আর ICE: PD(v) = সব সারিতে v বসিয়ে অনুমানের গড়; PDP = ICE-এর গড়; centred ICE ছড়ালে interaction; H-statistic তা একটি সংখ্যায় আনে।
- ALE আর surrogate: ALE খোপের আসল সারির ছোট বদল যোগ করে, তাই ডেটার ভেতরে থাকে; surrogate tree-এর fidelity held-out ডেটায় মাপুন, গভীরতা বাড়লে fidelity বাড়ে আর পড়ার সুবিধা কমে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৫৭ · একটি অনুমানের ব্যাখ্যা — SHAP আর LIMEপরবর্তী পর্বShapley value, background-এর প্রশ্ন আর LIME-এর অস্থিরতা দিয়ে একটি অনুমানের ব্যাখ্যা।
- মেশিন লার্নিং · কোর্স হোম৭৭টি পর্ব১৪টি মডিউলের পুরো রোডম্যাপ; পর্ব ৫৭ এখান থেকে খুলবেন।
- পর্ব ৩৩ · Bagging আর random forest — variance কমানো আর OOB errorআগের ভিত্তিImpurity বনাম permutation importance আর high-cardinality পক্ষপাত।
- পর্ব ৩৬ · XGBoost, LightGBM আর CatBoost — পার্থক্য আর হাতে-কলমেআগের ভিত্তিMonotonic আর interaction constraint,
partial_dependence-এর প্রথম ব্যবহার। - পর্ব ২৩ · Linear model গভীরে — basis function, interaction আর regularization pathআগের ভিত্তিCoefficient পড়া, interaction আর GAM-এর ধারণা।
- AI-এর ভিত্তি · পর্ব ৬৩ · Feature engineering — scaling, encoding আর নতুন featureআগের ভিত্তিPermutation importance-এর প্রথম পরিচয়।
- AI-এর ভিত্তি · পর্ব ৭২ · দায়িত্বশীল AI-এর অভ্যাস — bias যাচাই, গোপনীয়তা আর নথিপত্রআগের ভিত্তিExplainability, model card আর দায়িত্বশীল ব্যবহারের প্রেক্ষাপট।
- Data Structures আর Algorithmপাশের ট্র্যাকH-statistic-এর n² খরচের মতো জটিলতার হিসাব।