এই পর্বে যা শিখবেন
- একটি অস্পষ্ট ব্যবসার প্রশ্নকে সাতটি স্পষ্ট সিদ্ধান্তে ভেঙে ML task লেখা
- Target-এর সংজ্ঞা, unit of prediction আর prediction time ঠিক করে label leakage এড়ানো
- ছয়টি loss-এর আকার, derivative আর কোনটি কোন পরিসংখ্যান (গড়, median, quantile, সম্ভাবনা) শেখায় তা প্রমাণসহ বোঝা
- Loss, metric আর business value আলাদা রেখে মেলানো, আর একই split-এ কয়েকটি baseline দাঁড় করানো
- প্রতিটি অর্ডারের নিজস্ব খরচ থেকে সিদ্ধান্তের নিয়ম বের করা, আর কখন ML একেবারেই লাগবে না তা চেনা
১ · প্রশ্ন থেকে task — সাতটি আংটার শিকল
AI-এর ভিত্তি কোর্সের পর্ব ৭৪-এ framing-এর মূল কথাগুলো দেখেছেন: “ফেরত” শব্দের পাঁচ রকম মানে, সিদ্ধান্তের খরচ আর baseline আগে। আর পর্ব ৫৫-এ Mitchell-এর T, E, P দিয়ে শেখার কাজ লিখেছেন। এই পর্বে দেখব প্রতিটি framing-সিদ্ধান্ত model-এর গণিত কীভাবে বদলায়।
একজন ভালো ডাক্তার রোগী “ভালো লাগছে না” বললেই ওষুধ লেখেন না। তিনি ঠিক করেন কী মাপবেন (জ্বর, রক্তচাপ), কার জন্য (এই রোগী, পুরো পরিবার নয়), কখন (খালি পেটে, খাওয়ার পরে নয়), আর কোন ভুল বেশি বিপজ্জনক (রোগ থাকতেও না ধরা)। ML framing ঠিক এই কাজ: অস্পষ্ট অভিযোগকে মাপা যায় এমন প্রশ্নে বদলানো।
বাজারঘর (এই কোর্সের কাল্পনিক অনলাইন দোকান) একটি প্রশ্ন নিয়ে এসেছে: “চেকআউটে ক্রেতাকে কত দিনে পণ্য পৌঁছাবে বলব?” নিচের stepper প্রশ্নটিকে সাত ধাপে ML task-এ বদলায়।
| ১ প্রশ্ন ও সিদ্ধান্ত | |
| ২ target | |
| ৩ unit | |
| ৪ prediction time | |
| ৫ feature | |
| ৬ loss | |
| ৭ metric |
- প্রশ্ন আর সিদ্ধান্ত। প্রশ্নটি একটি সিদ্ধান্তের সঙ্গে বাঁধা: চেকআউট পাতায় একটি সংখ্যা দেখানো। Model-এর আউটপুট সরাসরি ক্রেতার চোখে যাবে, তাই ভুলের দামও সরাসরি ক্রেতার আস্থায় পড়বে।
- Target ঠিক করা। “ডেলিভারির সময়” মানে কোথা থেকে কোথায়? অর্ডার দেওয়া থেকে, না নিশ্চিত হওয়া থেকে? Courier-এর তোলা থেকে, না গুদাম ছাড়া থেকে? এখানে বাছা হলো “অর্ডার নিশ্চিত থেকে ক্রেতার হাতে”, কারণ ক্রেতা এই সময়টিই অনুভব করেন। বাতিল অর্ডারের target নেই, তাই সেগুলো বাদ।
- Unit of prediction. প্রতিটি অনুমান একটি অর্ডারের জন্য। এক অর্ডার দুটি পার্সেলে ভাগ হলে target হবে শেষ পার্সেল পৌঁছানো পর্যন্ত। একই ক্রেতার অনেক অর্ডার থাকলে পরে group বা সময়ভিত্তিক ভাগ লাগবে।
- Prediction time. অনুমান হবে ক্রেতা বোতাম চাপার মুহূর্তে। তখনও courier পার্সেল তোলেনি, তাই “courier কখন তুলল” কলামটি feature হতে পারে না, যদিও ঐতিহাসিক টেবিলে সেটি সুন্দরভাবে বসে আছে।
- Feature. শুধু সেই মুহূর্তে জানা তথ্য: গন্তব্য জেলা, কোন courier, পার্সেলের ওজন, দিনের কোন ঘণ্টা, আর তখন গুদামে কতগুলো অর্ডার অপেক্ষায়। শেষটি train-এ বসাতে হবে ঠিক সেই ঐতিহাসিক মুহূর্তের মান দিয়ে।
- Loss. প্রতিশ্রুতি ভাঙা ক্রেতার কাছে বেশি খারাপ, একটু বেশি সময় বলা কম খারাপ। তাই গড় নয়, ৯০তম quantile শেখানো হবে pinball loss দিয়ে (অংশ ৪ আর ৫)। Squared loss নিলে model গড় শিখত, আর প্রায় অর্ধেক প্রতিশ্রুতি ভাঙত।
- Metric. দুটি সংখ্যা একসঙ্গে: কত ভাগ অর্ডার প্রতিশ্রুত সময়ের মধ্যে পৌঁছাল (লক্ষ্য প্রায় ৯০%), আর গড়ে কত ঘণ্টা প্রতিশ্রুতি দেওয়া হলো। একটি একা দেখলে ফাঁকি দেওয়া যায়: সবাইকে “১০ দিন” বললে প্রথমটি ১০০% হয়, কিন্তু কেউ কিনবেন না।
শিকলটিকে একটু আনুষ্ঠানিকভাবেও লেখা যায়। ধরুন প্রতিটি unit-এর জন্য prediction time-এ জানা তথ্য x, আর পরে জানা উত্তর y. Model একটি function f, যাকে বেছে নেওয়া হয় যাতে নিচের প্রত্যাশিত ক্ষতি সবচেয়ে কম হয়:
R(f) = E[ ℓ(Y, f(X)) ]
এখানে E মানে প্রত্যাশা বা দীর্ঘমেয়াদি গড়, আর ℓ হলো loss function, যা একটি অনুমানের ভুলের দাম মাপে। Unit আর prediction time ঠিক করে কোন সারির ওপর গড় হবে আর X-এ কী থাকবে; target ঠিক করে Y; loss ঠিক করে “ভালো অনুমান” মানে কী। Training ডেটার ওপর এই গড় কমানোর নাম empirical risk minimisation, যার তত্ত্ব পর্ব ০৩-এ (শেখার তত্ত্ব — ERM, generalisation gap, PAC আর VC-এর অন্তর্দৃষ্টি) আসবে।
২ · Target, unit আর prediction time — label কবে জানা যায়
Target হলো যে মান model অনুমান করবে, আর প্রতিটি ঐতিহাসিক সারিতে তার আসল মান হলো label. বাজারঘরের দ্বিতীয় প্রশ্ন ধরুন: “কোন ক্রেতা চলে যাচ্ছেন, যাতে তাঁকে একটি ছাড়ের কুপন পাঠানো যায়?” অনলাইন দোকানে “চলে যাওয়া” কেউ ঘোষণা দিয়ে করেন না। তাই churn-এর সংজ্ঞা নিজেকে লিখতে হয়: “cutoff তারিখের পরের ৬০ দিনে কোনো অর্ডার নেই।”
এই এক লাইনে তিনটি আলাদা সময় লুকিয়ে আছে, আর তিনটিকে গুলিয়ে ফেলাই সবচেয়ে সাধারণ framing-ভুল:
- Prediction time (cutoff): যে মুহূর্তে model-কে প্রশ্ন করা হবে। বাস্তবে এটি “প্রতি মাসের ১ তারিখ রাতে সব সক্রিয় ক্রেতার score”.
- Label window: cutoff-এর পরের যে সময়ে ঘটনা ঘটল কি না দেখে label বসে, এখানে ৬০ দিন। জানালা শেষ না হওয়া পর্যন্ত label অসম্পূর্ণ।
- ডেটা তোলার দিন: যেদিন টেবিলটি database থেকে বের করা হলো, সাধারণত দুটিরই অনেক পরে।
একজন ক্রেতার সময়রেখা: কোন তথ্য কোন সময়ের
Feature window, prediction time, label window and extraction date
ছবির লাল তীরটিই temporal leakage: feature-এর ভেতর label window-এর খবর ঢুকে গেছে। যে ক্রেতা চলে গেছেন, ডেটা তোলার দিনে তাঁর recency স্বাভাবিকভাবেই বড়, কারণ তিনি ৬০ দিন কেনেননি। Model তখন label-কেই আবার পড়ছে। AI-এর ভিত্তি কোর্সের পর্ব ৫৬-এ target leakage-এর মূল উদাহরণ (টাকা ফেরতের কলাম) দেখেছেন; সময়ের ফাঁস আরও চুপচাপ, কারণ কলামের নাম একদম নিরীহ।
Unit of prediction: কার জন্য অনুমান
Unit of prediction ঠিক করে টেবিলের একটি সারি কী। Churn-এ unit হতে পারে “ক্রেতা”, “ক্রেতা × মাস”, বা “ক্রেতা × cutoff”. প্রতি মাসে score দিলে একই ক্রেতা অনেক সারিতে আসবেন, আর এলোমেলো ভাগে তাঁর মার্চের সারি train-এ, এপ্রিলের সারি test-এ পড়বে। তখন test-এর মাপ আশাবাদী হয়, কারণ model ক্রেতাকে চেনে। Unit আরও ঠিক করে কারা তালিকায় আছেন: এক বছর আগে একবার কিনে হারিয়ে যাওয়া ক্রেতাকে “churn = ১” বলে রাখলে model সহজ উদাহরণে ভরে যায়। তাই এখানে unit: “cutoff-এর আগের ৯০ দিনে অন্তত একটি অর্ডার আছে এমন ক্রেতা”, কারণ কুপন তাঁদেরই যাবে।
Label-এর চারটি ফাঁদ
| ফাঁদ | বাজারঘরে কেমন দেখায় | প্রতিকার |
|---|---|---|
| অসম্পূর্ণ label | গত সপ্তাহের cutoff-এর ক্রেতাদের ৬০ দিনের জানালা শেষ হয়নি; অর্ডার নেই বলে সবাইকে churn দেখায় | যে cutoff-এর জানালা শেষ হয়নি, সেটি train থেকে বাদ |
| জানালা মিশে যাওয়া | Feature-এর “গত ৯০ দিনের অর্ডার” গোনা হয়েছে ডেটা তোলার দিন থেকে, cutoff থেকে নয় | প্রতিটি feature-এর জন্য “কোন তারিখ পর্যন্ত” লিখে রাখা; point-in-time হিসাব |
| বাছাই করা label | ভুয়া অর্ডারের label আছে শুধু যেগুলো যাচাই-ফোন পেয়েছে; বাকিগুলোর সত্য কেউ জানে না | অল্প কিছু এলোমেলো অর্ডারে যাচাই চালু রাখা, যাতে নিরপেক্ষ label জমে |
| Proxy target | “সন্তুষ্টি” মাপা কঠিন বলে “অভিযোগ করেননি” label; চুপচাপ অসন্তুষ্ট ক্রেতা সন্তুষ্ট দেখায় | Proxy আর আসল লক্ষ্যের ফাঁক লিখে রাখা, ছোট নমুনায় আসল লক্ষ্য মেপে তুলনা |
এই তালিকার সঙ্গে আরেকটি বাস্তবতা যোগ করুন: label delay. ৬০ দিনের জানালা মানে আজকের score ঠিক ছিল কি না জানা যাবে দুই মাস পরে; ছোট জানালা দ্রুত কিন্তু সাময়িক বিরতিকেও churn বলে। এটি ব্যবসায়িক সিদ্ধান্ত। Label কোথা থেকে আসে, কতটা নির্ভুল আর কীভাবে তার মান মাপা যায়, সেটি পর্ব ০৫-এর (Label আর ডেটার মান — annotation, noise, agreement আর data versioning) বিষয়।
৩ · Point-in-time feature — ফাঁস হওয়া label-এর একটি পরীক্ষা
কথাটি সংখ্যায় দেখা যাক। নিচের কোড ৩০০০ জন কাল্পনিক ক্রেতা বানায়। প্রতিজনের কেনার একটি নিজস্ব হার আছে, আর একটি এলোমেলো দিনের পরে তিনি আর কেনেন না। Cutoff দিন ২৭০, label window ৬০ দিন, ডেটা তোলা হয়েছে দিন ৩৬৫-এ। দুই সেট feature দিয়ে দুটি logistic regression train হয়:
- সৎ: cutoff পর্যন্ত অর্ডারের সংখ্যা আর cutoff-এর দিনে recency, অর্থাৎ point-in-time feature.
- ফাঁস: একই দুটি কলাম, কিন্তু ডেটা তোলার দিনে হিসাব করা।
তৃতীয় লাইনটি সবচেয়ে গুরুত্বপূর্ণ: ফাঁস-model-কে deploy করলে বাস্তবে সে কী পায়? Deploy-এর দিনে “ডেটা তোলার দিন” আর cutoff একই দিন, তাই তার কলামে তখন সৎ মানগুলোই আসে। এই ব্লক প্রথমবার scikit-learn আনে, তাই পাতায় প্রথম চালাতে প্রায় ১০ সেকেন্ড লাগতে পারে।
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
rng = np.random.default_rng(7)
CUT, WIN, EXTRACT = 270, 60, 365 # দিন: prediction time, label window, ডেটা তোলার দিন
rows = []
for _ in range(3000): # ৩০০০ জন কাল্পনিক ক্রেতা
rate = rng.gamma(2.0, 0.03) # দিনে গড় অর্ডার
leave = rng.exponential(400) # এই দিনের পরে আর কেনেন না
t = np.sort(rng.uniform(0, EXTRACT, rng.poisson(rate * EXTRACT)))
t = t[t < leave]
seen = t[t <= CUT] # cutoff-এর দিনে যা জানা
if not np.any(seen > CUT - 90): # unit: আগের ৯০ দিনে সক্রিয় ক্রেতা
continue
churn = int(not np.any((t > CUT) & (t <= CUT + WIN)))
rows.append([seen.size, CUT - seen.max(), # সৎ: cutoff-এর দিনে মাপা
t.size, EXTRACT - t.max(), # ফাঁস: ডেটা তোলার দিনে মাপা
churn])
a = np.array(rows, dtype=float)
d, y = np.log1p(a[:, :4]), a[:, 4] # feature-এ log(1 + x)
print("active customers:", len(d), "| churn rate:", round(y.mean(), 3))
tr, te = train_test_split(np.arange(len(d)), test_size=0.3, random_state=42, stratify=y)
def run(name, train_cols, score_cols):
m = LogisticRegression().fit(d[tr][:, train_cols], y[tr])
p = m.predict_proba(d[te][:, score_cols])[:, 1]
print(f"{name:26s} AUC {roc_auc_score(y[te], p):.3f} | mean p {p.mean():.3f}"
f" | flagged p>0.5: {(p > 0.5).mean():.0%}")
run("honest model, offline test", [0, 1], [0, 1])
run("leaky model, offline test", [2, 3], [2, 3])
run("leaky model, scored live", [2, 3], [0, 1])
print("actual churn in test:", round(y[te].mean(), 3))আসল আউটপুট (ব্রাউজারের Python, scikit-learn 1.8.0):
active customers: 1696 | churn rate: 0.271
honest model, offline test AUC 0.805 | mean p 0.272 | flagged p>0.5: 18%
leaky model, offline test AUC 0.951 | mean p 0.289 | flagged p>0.5: 28%
leaky model, scored live AUC 0.801 | mean p 0.166 | flagged p>0.5: 10%
actual churn in test: 0.271
খাতায় ফাঁস-model অসাধারণ: AUC ০.৯৫১, সৎ model-এর ০.৮০৫-এর অনেক ওপরে। কিন্তু deploy-এর দিনে সে পায় cutoff-এর মান, আর AUC নেমে আসে ০.৮০১-এ, সৎ model-এর সমান বা একটু নিচে। তার গড় সম্ভাবনা ০.১৬৬, অথচ আসল churn ০.২৭১, আর ০.৫-এর ওপরে পড়ে মাত্র ১০% ক্রেতা। সে শিখেছিল “বড় recency মানেই churn”, কিন্তু cutoff-এ recency অত বড় হয় না; তাই সম্ভাবনা ভুল মাপের। সৎ model-এর গড় ০.২৭২ আসল হারের সঙ্গে মেলে। এই সংখ্যাগুলো একটি seed-এর একটি স্থানীয় run, সাধারণ ফল নয়।
প্রতিকারটি তাই কোনো নতুন algorithm নয়, সময় মেলানো: প্রতিটি feature-কে তার unit-এর prediction time পর্যন্ত জানা তথ্য দিয়েই হিসাব করা। pandas-এ এর জন্য আছে merge_asof, যা প্রতিটি সারির সঙ্গে “এই তারিখ বা তার আগের সর্বশেষ মান” জোড়ে (AI-এর ভিত্তি কোর্সের পর্ব ২৫)। SQL-এ একই কাজ হয় তারিখের শর্তসহ join আর window function দিয়ে (DBMS ও SQL কোর্সের Window function পর্ব)। বড় দলে এই কাজের জন্য feature store থাকে, যার মূল প্রতিশ্রুতিই “point-in-time correct join”.
সৎ feature থাকলেও এলোমেলো ভাগ বিপদ বাড়ায়। বাস্তবে অনেক cutoff-এর সারি থাকে; train-এ পরের মাসের আর test-এ আগের মাসের সারি পড়লে model ভবিষ্যৎ দেখে ফেলে। নিয়ম: train-এর সব cutoff test-এর সব cutoff-এর আগে, আর মাঝে অন্তত একটি label window-এর ফাঁক, যাতে train-এর label test-এর সময়ে ঢুকে না পড়ে (time-based split). এর পূর্ণ রূপ, backtesting, পর্ব ৫২-এ (ML দিয়ে forecasting — lag feature, backtesting আর অনেক series একসঙ্গে) আসবে।
৪ · Loss একটি পছন্দ — ছয়টি loss-এর আকার আর ঢাল
AI-এর ভিত্তি কোর্সে দুটি loss দেখেছেন: linear regression-এ বর্গের গড় (পর্ব ৫৮) আর logistic regression-এ log loss (পর্ব ৫৯)। দুটিই প্রথা হিসেবে আসে, কিন্তু loss আসলে একটি পছন্দ: কোন ভুলকে কতটা খারাপ ধরবেন, সেটি এখানে সংখ্যায় লেখা হয়। চায়ের দোকানে দুধ কম পড়লে খদ্দের ফেরত যান, বেশি থাকলে একটু নষ্ট হয়; দুই ভুলের দাম সমান নয়।
Regression-এ ভুলকে লেখা হয় residual দিয়ে: r = y − ŷ, যেখানে y আসল মান আর ŷ অনুমান। Classification-এ y ∈ {−1, +1} ধরে model একটি score s দেয়, আর margin m = y · s. m ধনাত্মক মানে দিক ঠিক, যত বড় তত আত্মবিশ্বাসী।
| Loss | সূত্র | Derivative | যা শাস্তি দেয় |
|---|---|---|---|
| Squared (MSE-এর ভিত্তি) | r² | dℓ/dr = 2r | বড় ভুল খুব বেশি; একটি outlier পুরো fit টেনে নেয় |
| Absolute (MAE-এর ভিত্তি) | |r| | sign(r); r = 0-তে সংজ্ঞায়িত নয় | সব ভুল সমান হারে; outlier-এর টান সীমিত |
| Huber (δ) | |r| ≤ δ হলে r²/2, নইলে δ(|r| − δ/2) | r, তবে ±δ-তে কাটা | ছোট ভুলে squared, বড় ভুলে absolute |
| Pinball (τ) | r ≥ 0 হলে τr, নইলে (τ − 1)r | τ বা τ − 1 | কম বলা আর বেশি বলাকে অসমান দামে |
| Log loss | log(1 + e−m) | −1 / (1 + em) | ভুল দিকে আত্মবিশ্বাস খুব বেশি; ঠিক দিকেও একটু |
| Hinge | max(0, 1 − m) | m < 1 হলে −1, নইলে 0 | শুধু margin ১-এর কম হলে; বাকিদের উপেক্ষা |
Pinball-এ τ (tau) ০ থেকে ১-এর একটি সংখ্যা। τ = ০.৯ মানে কম বলার (r > 0, আসল মান অনুমানের চেয়ে বড়) প্রতি ঘণ্টায় দাম ০.৯, বেশি বলার প্রতি ঘণ্টায় দাম ০.১: কম বলা নয় গুণ খারাপ। τ = ০.৫ হলে pinball হুবহু absolute loss-এর অর্ধেক। Absolute আর pinball-এর r = 0-তে একক ঢাল নেই; সেখানে একটি পরিসরের যেকোনো ঢাল বৈধ, যাকে বলে subgradient. Hinge-এর m = 1-এও একই ব্যাপার। সব কটি loss-ই convex, তাই minimum খোঁজা সহজ; কেন এটি এত গুরুত্বপূর্ণ, পর্ব ১২ (Convexity — কেন কিছু loss সহজ আর কিছু কঠিন) দেখাবে।
নিচের ব্লক ছয়টি loss আঁকে, তুলনার জন্য ০-১ loss-ও (ভুল দিক হলে ১, নইলে ০), আর কয়েকটি বিন্দুতে সংখ্যাগতভাবে derivative বের করে। Derivative বের করা হয়েছে central difference দিয়ে: (f(x + h) − f(x − h)) / 2h, h খুব ছোট। Log loss-কে base 2-এ লেখা হয়েছে, যাতে m = 0-তে মান ঠিক ১ হয় আর ০-১ loss-এর সঙ্গে পাশাপাশি তুলনা সহজ হয়।
import numpy as np
import matplotlib.pyplot as plt
def huber(r, d=1.0):
return np.where(np.abs(r) <= d, 0.5 * r**2, d * (np.abs(r) - 0.5 * d))
def pinball(r, tau): # r = y - prediction
return np.where(r >= 0, tau * r, (tau - 1) * r)
reg = {"squared": lambda r: r**2, "absolute": np.abs, "Huber (delta=1)": huber,
"pinball tau=0.1": lambda r: pinball(r, 0.1),
"pinball tau=0.9": lambda r: pinball(r, 0.9)}
cls = {"log loss (base 2)": lambda m: np.log2(1 + np.exp(-m)),
"hinge": lambda m: np.maximum(0, 1 - m),
"0-1": lambda m: (m <= 0).astype(float)}
def deriv(f, x, h=1e-6): # central difference
return (f(x + h) - f(x - h)) / (2 * h)
pts = np.array([-2.0, -0.5, 0.5, 2.0])
print("d loss / d r at r =", pts)
for name, f in reg.items():
print(f"{name:17s}", np.round(deriv(f, pts), 3))
mpts = np.array([-1.0, 0.5, 2.0])
print("d loss / d m at m =", mpts)
for name in ["log loss (base 2)", "hinge"]:
print(f"{name:17s}", np.round(deriv(cls[name], mpts), 3))
r = np.linspace(-3, 3, 601)
fig, (a1, a2) = plt.subplots(1, 2, figsize=(9, 3.6))
for name, f in reg.items():
a1.plot(r, f(r), label=name)
a1.set(xlabel="residual r = y - prediction", ylabel="loss", ylim=(0, 4), title="Regression losses")
for name, f in cls.items():
a2.plot(r, f(r), label=name, ls=":" if name == "0-1" else "-")
a2.set(xlabel="margin m = y * score (y in {-1, +1})", ylim=(0, 4), title="Classification losses")
a1.legend(fontsize=8); a2.legend(fontsize=8); fig.subplots_adjust(wspace=0.3, bottom=0.17)
plt.show()আসল আউটপুট (ব্রাউজারের Python, matplotlib 3.10.8; ছবিটি কোডের নিচে আঁকা হয়):
d loss / d r at r = [-2. -0.5 0.5 2. ]
squared [-4. -1. 1. 4.]
absolute [-1. -1. 1. 1.]
Huber (delta=1) [-1. -0.5 0.5 1. ]
pinball tau=0.1 [-0.9 -0.9 0.1 0.1]
pinball tau=0.9 [-0.1 -0.1 0.9 0.9]
d loss / d m at m = [-1. 0.5 2. ]
log loss (base 2) [-1.055 -0.545 -0.172]
hinge [-1. -1. 0.]
Squared-এর ঢাল 2r: ভুল যত বড়, টান তত বেশি। Absolute-এর ঢাল সবসময় ±1, Huber ছোট ভুলে squared-এর অর্ধেকের মতো (r) আর বড় ভুলে ±1-এ কাটা। Pinball τ = ০.৯-এ কম বলার (r > 0) ঢাল ০.৯, বেশি বলার মাত্র −০.১: নয় গুণ অসমান টান, τ = ০.১-এ ঠিক উল্টো। Log loss-এর ঢাল −1/(ln 2 · (1 + em)); m = ২-এও −০.১৭২, অর্থাৎ ঠিক দিকেও একটু ঠেলে। Hinge m = ২-এ শূন্য: margin ১ পেরোলে আর পাত্তা দেয় না। ডান ছবিতে খেয়াল করুন, দুটি loss-ই ০-১ সিঁড়ির ওপরে বা সমান।
এই loss-গুলোর প্রতিটির পেছনে একটি আলাদা প্রশ্ন ছিল। Peter Huber ১৯৬৪ সালে Annals of Mathematical Statistics-এ “Robust Estimation of a Location Parameter” প্রবন্ধে দেখান, কিছু দূষিত মান থাকলেও কাজ চালানোর মতো অবস্থানের মাপ পেতে বর্গ আর পরম মানের মিশ্রণ ভালো। Roger Koenker আর Gilbert Bassett ১৯৭৮ সালে Econometrica-য় “Regression Quantiles” প্রবন্ধে pinball ধাঁচের loss দিয়ে শুধু গড় নয়, যেকোনো quantile-এর regression প্রস্তাব করেন। আর hinge loss জনপ্রিয় হয় Corinna Cortes ও Vladimir Vapnik-এর ১৯৯৫ সালের soft-margin support vector machine-এর সঙ্গে, যা পর্ব ২৮-এ (Soft margin — hinge loss, C আর dual problem) বিস্তারিত আসবে।
৫ · কোন constant কোন loss-এর উত্তর — mean, median আর quantile
একটি loss কী শেখায়, সেটি বোঝার সবচেয়ে পরিষ্কার পরীক্ষা: কোনো feature না দিয়ে, সব অর্ডারের জন্য একটিই সংখ্যা c বলতে হলে কোন c সবচেয়ে কম মোট loss দেয়? পাঁচটি অর্ডারের ডেলিভারি দিন ধরুন: ১, ২, ২, ৩, ৭। গড় ৩, median ২। নিচের stepper প্রতিটি loss-এ c = ২ আর c = ৩-এর মোট loss পাশাপাশি দেখায়।
| ডেটা y (দিন) | |
| squared | |
| absolute | |
| pinball τ = 0.7 | |
| Huber δ = 1 |
- ডেটা আর প্রশ্ন। পাঁচটি ডেলিভারি: ১, ২, ২, ৩, ৭ দিন। ডান দিকে লম্বা লেজ, ঠিক বাস্তবের মতো: বেশিরভাগ দ্রুত, একটি খুব দেরি। প্রার্থী দুটি: median ২ আর গড় ৩।
- Squared. c = ২: (1 + 0 + 0 + 1 + 25) = ২৭। c = ৩: (4 + 1 + 1 + 0 + 16) = ২২। গড় জেতে। কারণ মোট loss-এর derivative −2∑(yᵢ − c) শূন্য হয় ঠিক তখন, যখন c = সবগুলোর গড়।
- Absolute. c = ২: 1 + 0 + 0 + 1 + 5 = ৭। c = ৩: 2 + 1 + 1 + 0 + 4 = ৮। এবার median জেতে। c একটু বাড়ালে c-এর নিচের প্রতিটি বিন্দুর loss বাড়ে, ওপরের প্রতিটির কমে; লাভ-ক্ষতি সমান হয় যখন দুই পাশে সমান সংখ্যক বিন্দু।
- Pinball, τ = ০.৭. নিচের বিন্দুর ভুলে দাম ০.৩, ওপরের বিন্দুর ভুলে ০.৭। c = ২: ০.৩ × ১ + ০.৭ × (১ + ৫) = ৪.৫। c = ৩: ০.৩ × (২ + ১ + ১) + ০.৭ × ৪ = ৪.০। সেরা c = ৩, যেখানে মোটামুটি ৭০% বিন্দু c-এর সমান বা নিচে: ৭০% quantile.
- Huber, δ = ১. c = ২-এ ৫.৫, c = ৩-এ ৬.০। আসল minimum দুটির মাঝে: derivative-এর শর্ত −1 + 2(2 − c) + (3 − c) + 1 = 0 থেকে c = ৭/৩ ≈ ২.৩৩। কাছের বিন্দুগুলো গড়ের মতো টানে, দূরের ৭ টানে মাত্র ±১ শক্তিতে।
- Outlier এলো: ৭ হয়ে গেল ১৭। গড় লাফিয়ে ৫ (squared-এ c = ৫-এ মোট ১৮২, c = ৩-এর ২০২-এর চেয়ে কম)। Median ২ আর ৭০% quantile ৩ একটুও নড়ল না, Huber-ও ২.৩৩-এ স্থির, কারণ দূরের বিন্দুর টান ±১-এ আটকানো। একটি ভুল এন্ট্রি গড়কে টেনে নেয়, median-কে নয়।
প্রমাণ, তিন লাইনে
n টি মান y₁ … yₙ আর একটি constant c ধরুন। প্রতিটি loss-এর মোট L(c)-এর derivative শূন্য (বা subgradient-এ শূন্য অন্তর্ভুক্ত) করলে:
- Squared: L′(c) = −2 ∑(yᵢ − c) = 0 ⇒ c = (1/n) ∑yᵢ, অর্থাৎ গড়।
- Absolute: L′(c) = #(yᵢ < c) − #(yᵢ > c). শূন্য হয় যখন c-এর দুই পাশে সমান সংখ্যক বিন্দু: median.
- Pinball (τ): L′(c) = (1 − τ) · #(yᵢ < c) − τ · #(yᵢ > c). শূন্য হয় যখন c-এর নিচে মোটামুটি τ ভাগ বিন্দু: τ-quantile. τn পূর্ণসংখ্যা হলে minimum একটি বিন্দু না হয়ে দুটি পাশাপাশি মানের মাঝের পুরো অংশ হতে পারে; তাই নিচের কোডে n = ৪০১ নেওয়া হয়েছে।
Feature যোগ করলে কথাটি প্রতিটি x-এর জন্য আলাদাভাবে খাটে: squared loss দিয়ে train করা model শেখে E[Y | x], অর্থাৎ ওই ধরনের অর্ডারের গড়; absolute loss শেখে শর্তসাপেক্ষ median, আর pinball loss শর্তসাপেক্ষ quantile. তাই loss বাছাই মানে আসলে ঠিক করা, model কোন পরিসংখ্যানের অনুমান দেবে। নিচের ব্লক ৪০১টি কাল্পনিক ডেলিভারির ঘণ্টা বানায় (skewed, lognormal), তিনটি loss-এর মোট মান SciPy দিয়ে সংখ্যাগতভাবে সর্বনিম্ন করে, আর ফলকে NumPy-র গড়, median আর quantile-এর সঙ্গে মেলায়।
import numpy as np
from scipy.optimize import minimize_scalar
rng = np.random.default_rng(42)
# বাজারঘরের ৪০১টি কাল্পনিক ডেলিভারির সময় (ঘণ্টা): বেশিরভাগ দ্রুত, কিছু খুব দেরি
hours = np.round(rng.lognormal(mean=3.3, sigma=0.55, size=401), 1)
print("min, max:", hours.min(), hours.max(), "| skew: mean > median?", hours.mean() > np.median(hours))
def pinball(c, tau):
r = hours - c
return np.mean(np.where(r >= 0, tau * r, (tau - 1) * r))
losses = {
"squared": lambda c: np.mean((hours - c) ** 2),
"absolute": lambda c: np.mean(np.abs(hours - c)),
"pinball 0.9": lambda c: pinball(c, 0.9),
}
best = {k: minimize_scalar(f, bounds=(0, 200), method="bounded",
options={"xatol": 1e-6}).x for k, f in losses.items()}
check = {"squared": hours.mean(), "absolute": np.median(hours),
"pinball 0.9": np.quantile(hours, 0.9, method="inverted_cdf")}
print(f"{'loss':12s} {'best c':>8s} {'numpy':>8s}")
for k in losses:
print(f"{k:12s} {best[k]:8.2f} {check[k]:8.2f} ({'mean' if k == 'squared' else 'median' if k == 'absolute' else 'quantile 0.9'})")
# প্রতিশ্রুতি হিসেবে কোনটি কেমন? c ঘণ্টার মধ্যে কত ভাগ ডেলিভারি পৌঁছায়
for k, c in best.items():
print(f"promise {c:5.1f} h ({k:11s}) -> on time {np.mean(hours <= c):.0%}")আসল আউটপুট (ব্রাউজারের Python, NumPy 2.4.6, SciPy 1.18.0):
min, max: 6.6 134.6 | skew: mean > median? True
loss best c numpy
squared 31.07 31.07 (mean)
absolute 27.30 27.30 (median)
pinball 0.9 53.10 53.10 (quantile 0.9)
promise 31.1 h (squared ) -> on time 61%
promise 27.3 h (absolute ) -> on time 50%
promise 53.1 h (pinball 0.9) -> on time 90%
তিনটি loss-এর সংখ্যাগত minimum NumPy-র গড়, median আর ৯০% quantile-এর সঙ্গে দুই দশমিক পর্যন্ত হুবহু মেলে। ডান-হেলানো ডেটায় গড় (৩১.১) median-এর (২৭.৩) চেয়ে বড়। প্রতিশ্রুতি হিসেবে গড় বললে মাত্র ৬১% ডেলিভারি সময়ে পৌঁছায়, median বললে ৫০%; pinball τ = ০.৯ ঠিক ৯০% দেয়, কিন্তু দাম হলো দীর্ঘতর প্রতিশ্রুতি, ৫৩.১ ঘণ্টা। কোনটি “সঠিক”, তা গণিত নয়, ব্যবসার লক্ষ্য ঠিক করে।
Classification-এ একই প্রশ্ন: log loss বনাম hinge
একই চিন্তা classification-এও খাটে। ধরুন একটি ধরনের অর্ডারে ভুয়া হওয়ার আসল সম্ভাবনা p. সেই অর্ডারগুলোর জন্য একটি score বলতে হলে log loss-এর সেরা উত্তর এমন score, যার sigmoid ঠিক p; অর্থাৎ log loss সম্ভাবনা শেখায়। এমন loss-কে বলে proper scoring rule: সৎভাবে আসল সম্ভাবনা বললেই প্রত্যাশিত loss সবচেয়ে কম। Hinge-এর সেরা উত্তর আলাদা: p > ০.৫ হলে +1, নইলে −1, মাঝে কিছু নয় (Yi Lin, ২০০২)। তাই SVM-এর score থেকে সরাসরি সম্ভাবনা পাওয়া যায় না, আলাদা calibration লাগে (পর্ব ২৬, Probability calibration — Platt, isotonic আর reliability diagram). যেখানে পরে খরচ দিয়ে threshold বসাবেন (অংশ ৭), সেখানে সম্ভাবনা দরকার, আর তাই log loss-এর মতো proper loss স্বাভাবিক পছন্দ।
scikit-learn-এ এই পছন্দগুলো কোথায়: HistGradientBoostingRegressor(loss="quantile", quantile=0.9) বা loss="absolute_error"; GradientBoostingRegressor(loss="huber"); linear model-এ QuantileRegressor(quantile=0.9) আর HuberRegressor; classification-এ SGDClassifier(loss="hinge") বা loss="log_loss". মূল্যায়নে mean_pinball_loss(y, pred, alpha=0.9). নামগুলো লেখার সময়ে ডেস্কটপের scikit-learn 1.9.1-এ যাচাই করা; নতুন version-এ নিজের version-এর docs দেখে নিন। Robust আর quantile regression-এর পূর্ণ রূপ পর্ব ২৪-এ (Robust আর quantile regression — outlier আর অনুমানের পরিসর)।
৬ · Loss, metric আর ব্যবসার মূল্য — তিনটি আলাদা জিনিস
Loss, metric আর ব্যবসার মূল্য: তিনটি শব্দ প্রায়ই একে অপরের জায়গায় বলা হয়, কিন্তু তাদের কাজ আলাদা। ক্রিকেটে নেটের অনুশীলন (loss), স্কোরকার্ডের strike rate (metric) আর ম্যাচ জেতা (আসল লক্ষ্য) সম্পর্কিত, কিন্তু এক নয়।
| স্তর | কে ব্যবহার করে | কী গুণ লাগে | ডেলিভারির উদাহরণ |
|---|---|---|---|
| Loss | Optimizer, training-এর সময় | প্রতি সারিতে হিসাবযোগ্য, মসৃণ বা অন্তত convex, দ্রুত | pinball, τ = ০.৯ |
| Offline metric | আপনি, model তুলনার সময় | বোঝা যায়, তুলনা করা যায়, সিদ্ধান্তের সঙ্গে সম্পর্কিত | প্রতিশ্রুতি রক্ষার হার, গড় প্রতিশ্রুত ঘণ্টা |
| Business metric | দোকানের মালিক | টাকায় বা ক্রেতার আচরণে মাপা | চেকআউট সম্পন্নের হার, “কোথায় আমার পার্সেল” কল |
কেন সরাসরি metric দিয়েই train করি না? কারণ সবচেয়ে স্বাভাবিক classification metric, ভুলের সংখ্যা বা ০-১ loss, সিঁড়ির মতো: প্রায় সবখানে ঢাল শূন্য, gradient কোনো দিক দেখায় না, আর linear classifier-এর জন্যও তাকে ঠিক ঠিক সর্বনিম্ন করা সাধারণভাবে NP-hard. তাই train করা হয় একটি surrogate loss দিয়ে: log loss বা hinge, যা ০-১-এর ওপরে থাকা একটি convex রেখা (অংশ ৪-এর ডান ছবি)। Peter Bartlett, Michael Jordan আর Jon McAuliffe ২০০৬ সালে Journal of the American Statistical Association-এ দেখান, কোন শর্তে এমন surrogate কমালে ০-১ ঝুঁকিও কমে (“classification-calibrated” loss). log loss আর hinge দুটিই সেই শর্ত মানে।
দ্বিতীয় নিয়ম আরও ব্যবহারিক: loss আর metric একই পরিসংখ্যান চাইলে ভালো। Tilmann Gneiting ২০১১ সালে JASA-তে “Making and Evaluating Point Forecasts” প্রবন্ধে এই কথাটি জোর দিয়ে বলেন: কোনো point forecast চাইলে আগে বলতে হবে, সেটি গড়, median না কোনো quantile; কারণ MAE দিয়ে মাপলে median-ই সেরা উত্তর, RMSE দিয়ে মাপলে গড়। Model squared loss-এ train করে MAE-তে বিচার করলে skewed ডেটায় অকারণে হারবে। ডেলিভারির বেলায় metric যেহেতু “৯০% প্রতিশ্রুতি রক্ষা”, loss হলো pinball τ = ০.৯; দুটি একই quantile চায়।
Metric লক্ষ্য হয়ে গেলে: শুধু রক্ষার হার পুরস্কৃত করলে model সবাইকে বেশি সময় বলবে। এটি Goodhart-এর নিয়ম-এর চেনা রূপ। প্রতিকার: পরস্পরবিরোধী অন্তত দুটি metric একসঙ্গে, আর একটি guardrail metric (যেমন অভিযোগের হার) যা খারাপ হলে কোনো উন্নতিই গ্রহণযোগ্য নয়। Offline metric ভালো হলেই business metric ভালো হবে এমন নিশ্চয়তা নেই; সেটি জানার নির্ভরযোগ্য পথ A/B test, যার নকশা আর বিশ্লেষণ পর্ব ৬২ আর ৬৩-এ আসবে।
৭ · Baseline আর খরচ দেখে সিদ্ধান্ত
AI-এর ভিত্তি কোর্সের পর্ব ৫-এ baseline-এর তালিকা আর পর্ব ৬০-এ খরচ থেকে threshold t* = CFP / (CFP + CFN) দেখেছেন। এখানে দুটি ধাপ এগোব: baseline-কে একটি মই হিসেবে সাজানো, যার প্রতিটি ধাপ একই split আর একই metric-এ মাপা; আর খরচ যখন প্রতিটি অর্ডারে আলাদা, তখন সিদ্ধান্তের নিয়ম।
Baseline-এর মই
বাজারঘর প্রতিদিন রাতে পরের দিনের অর্ডার সংখ্যা অনুমান করে, যাতে প্যাকিং কর্মী ঠিক করা যায়। হাতে দুই সপ্তাহের ডেটা (শনি থেকে শুক্র)। প্রথম সপ্তাহ: ৫২, ৪৮, ৫০, ৪৭, ৫৫, ৭০, ৮৮। দ্বিতীয় সপ্তাহ test. Metric: MAE, অর্থাৎ গড়ে কত অর্ডারের ভুল। কোনো model বানানোর আগে চারটি baseline একই test সপ্তাহে মাপা হলো।
| নাম | |
| MAE |
- মঞ্চ। Test সপ্তাহের আসল সংখ্যা ওপরে। শুক্রবার সবচেয়ে বেশি অর্ডার: সাপ্তাহিক ছন্দ। প্রতিটি baseline একই নিয়ম মানে: অনুমান আগের রাতে, তখন জানা তথ্য দিয়ে।
- গড়। প্রথম সপ্তাহের গড় ৫৮.৬ সব দিনে। ছুটির দিনের চূড়া ধরতে পারে না: শুক্রবারে ভুল ৩২.৪। MAE ১১.৩৯, এটি regression-এর majority-class baseline-এর সমতুল্য।
- Naive: আগের দিনের মান। এখানে গড়ের চেয়েও খারাপ (১১.৫৭)। শনিবারে আগের শুক্রবারের ৮৮ বলা হলো, আসল ৫৪: ভুল ৩৪। ছন্দ থাকলে আগের দিন ভুল তুলনা।
- Seasonal naive: সাত দিন আগের মান। সাপ্তাহিক ছন্দ পুরোটাই ধরে, MAE মাত্র ২.৫৭। এটি এখন মানদণ্ড: যেকোনো model-কে একে হারাতে হবে, নইলে model-এর খরচ আর ঝুঁকি নেওয়ার কারণ নেই।
- এখনকার নিয়ম। ব্যবস্থাপক বলেন “গত সপ্তাহ + ১০%”. MAE ৩.৭১, seasonal naive-এর চেয়ে খারাপ, কারণ এই দুই সপ্তাহে বৃদ্ধি ১০%-এর অনেক কম ছিল। বর্তমান নিয়ম সবসময় একটি baseline, কারণ model-কে তার জায়গাই নিতে হবে।
- সিদ্ধান্ত। মানদণ্ড ২.৫৭। একটি model ২.৪-এ নামলে লাভ দিনে মোটে ০.১৭টি অর্ডার, যা হয়তো রক্ষণাবেক্ষণের খরচের যোগ্য নয়। আর মাত্র এক সপ্তাহের test-এ এমন ছোট পার্থক্য সহজেই কাকতালীয়; কয়েক সপ্তাহের backtest আর অনিশ্চয়তার মাপ লাগবে (পর্ব ০৪ আর পর্ব ২২)।
মইয়ের সাধারণ রূপ: (১) ডেটা না দেখা baseline: classification-এ সবচেয়ে বেশি দেখা শ্রেণি, regression-এ গড় বা median (scikit-learn-এর DummyClassifier আর DummyRegressor); (২) ক্ষেত্রের সরল কৌশল: seasonal naive, “সবচেয়ে জনপ্রিয় আগে”, এখনকার হাতে-লেখা নিয়ম; (৩) একটি সরল model: logistic বা linear regression, কয়েকটি স্পষ্ট feature নিয়ে; (৪) তারপরই জটিল model. প্রতিটি ধাপ একই split, একই prediction time আর একই metric-এ, নইলে তুলনা অর্থহীন।
প্রতিটি অর্ডারের নিজস্ব খরচ
এবার বাজারঘরের ভুয়া অর্ডার (fraud). সন্দেহজনক অর্ডারে পাঠানোর আগে একজন কর্মী ফোন করেন; একটি ফোনের খরচ ধরা যাক ৳৪০ (কর্মীর সময়, কিছু দেরি)। ভুয়া অর্ডার ছাড় পেলে ক্ষতি হয় পণ্যের দাম আর আসা-যাওয়ার ৳১২০। অর্থাৎ ভুলের দাম অর্ডারভেদে আলাদা: ৳৫০০-এর অর্ডারে ৳৬২০, ৳৫০০০-এর অর্ডারে ৳৫১২০। একে বলে example-dependent cost, আর তখন একটি cost matrix যথেষ্ট নয়।
Model যদি অর্ডারটির ভুয়া হওয়ার calibrated সম্ভাবনা p দেয়, তাহলে expected cost তুলনা করেই সিদ্ধান্ত: ফোন করলে খরচ ৪০ (ভুয়া হলে ধরা পড়ে); না করলে প্রত্যাশিত ক্ষতি p × (দাম + ১২০)। তাই
ফোন করুন যদি p > ৪০ / (দাম + ১২০)
৳৫০০-এর অর্ডারে সীমা ৪০/৬২০ ≈ ০.০৬৫; ৳৫০০০-এর অর্ডারে ৪০/৫১২০ ≈ ০.০০৮। দামি অর্ডারে খুব সামান্য সন্দেহেই ফোন করা লাভজনক। নিচের ব্লক ৪০০০টি কাল্পনিক অর্ডারে (দাম, প্রথম অর্ডার কি না, রাত ১টা থেকে ৫টার মধ্যে কি না) চারটি সিদ্ধান্তের নিয়ম একই test অর্ধেকে তুলনা করে: majority (কখনো ফোন নয়), একটি হাতে-লেখা নিয়ম, ০.৫ threshold-এর model, আর অর্ডারভেদে threshold-এর model.
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
rng = np.random.default_rng(11)
n = 4000 # কাল্পনিক অর্ডার
amount = np.round(rng.lognormal(7.3, 0.7, n)) # টাকা
first = rng.random(n) < 0.3 # প্রথম অর্ডার?
night = rng.random(n) < 0.2 # রাত ১টা-৫টায়?
z = -5.2 + 0.0004 * amount + 1.3 * first + 1.0 * night
fraud = (rng.random(n) < 1 / (1 + np.exp(-z))).astype(int)
X = np.column_stack([amount / 1000, first, night])
i_tr, i_te = train_test_split(np.arange(n), test_size=0.5, random_state=42, stratify=fraud)
p = LogisticRegression().fit(X[i_tr], fraud[i_tr]).predict_proba(X[i_te])[:, 1]
y, a = fraud[i_te], amount[i_te]
print("fraud rate:", round(fraud.mean(), 3), "| test orders:", len(y))
CALL = 40 # যাচাই-ফোনের খরচ, টাকা
LOSS = a + 120 # ছাড় পাওয়া ভুয়া অর্ডারের ক্ষতি
rules = {
"majority: never call": np.zeros(len(y), bool),
"rule: first & >3000": (X[i_te, 1] == 1) & (a > 3000),
"model: p > 0.5": p > 0.5,
"model: p > CALL/LOSS": p > CALL / LOSS,
}
print(f"{'decision':22s} {'acc':>5s} {'calls':>5s} {'caught':>6s} {'cost/1000':>9s}")
for name, call in rules.items():
cost = CALL * call.sum() + (LOSS * (y == 1) * ~call).sum()
acc = (call == (y == 1)).mean()
print(f"{name:22s} {acc:5.3f} {call.sum():5d} {(call & (y == 1)).sum():3d}/{y.sum()}"
f" {cost / len(y) * 1000:9.0f}")আসল আউটপুট (ব্রাউজারের Python, scikit-learn 1.8.0):
fraud rate: 0.032 | test orders: 2000
decision acc calls caught cost/1000
majority: never call 0.969 0 0/63 101334
rule: first & >3000 0.937 83 10/63 73435
model: p > 0.5 0.969 4 2/63 89560
model: p > CALL/LOSS 0.623 780 44/63 26665
Accuracy দেখলে majority আর ০.৫-threshold-এর model সেরা (০.৯৬৯), আর খরচ-ভিত্তিক model সবচেয়ে খারাপ (০.৬২৩)। টাকা দেখলে ছবি উল্টো: কখনো ফোন না করলে প্রতি ১০০০ অর্ডারে প্রায় ৳১,০১,৩৩৪ ক্ষতি; হাতে-লেখা নিয়মে ৳৭৩,৪৩৫; ০.৫-এ model প্রায় কিছুই করে না (৪টি ফোন), ৳৮৯,৫৬০; আর অর্ডারভেদে সীমায় ৭৮০টি ফোন করে ৬৩টি ভুয়ার ৪৪টি ধরে, খরচ নামে ৳২৬,৬৬৫-এ, প্রায় এক-চতুর্থাংশ। সরল model-টি নিয়মকে হারাল শুধু সঠিক সিদ্ধান্তের নিয়মের সঙ্গে জুড়লে। এটি একটি seed-এর একটি run.
তিনটি সতর্কতা। (১) সূত্রটি ধরে নেয় p সত্যিকারের সম্ভাবনা; এখানে ডেটা logistic নিয়মেই বানানো, বাস্তবে আগে calibration যাচাই করুন। (২) দামগুলো বানানো; আসল সংখ্যা জোগাড় করাই framing-এর বড় কাজ। (৩) সীমাটি তত্ত্ব থেকে এসেছে; কিছু tune করলে তা validation ভাগে করুন, test-এ নয়। ভুয়া অর্ডারের মতো বিরল শ্রেণির বিস্তারিত কৌশল (class weight, resampling) পর্ব ৫০-এ।
৮ · বাজারঘরের চারটি framing — আর কখন ML নয়
চারটি প্রশ্ন পাশাপাশি বসালে framing একটি টেবিল হয়ে যায়। কাজের শুরুতে এমন টেবিলে দলের সম্মতি নেওয়া অনেক সময় বাঁচায়।
| দিক | Churn | ডেলিভারির দেরি | চাহিদা | ভুয়া অর্ডার |
|---|---|---|---|---|
| সিদ্ধান্ত | কাকে কুপন | কোন প্রতিশ্রুতি দেখানো | কাল কতজন প্যাকার | কাকে যাচাই-ফোন |
| Unit | সক্রিয় ক্রেতা × cutoff | অর্ডার | দিন (বা দিন × গুদাম) | অর্ডার |
| Prediction time | মাসের ১ তারিখ রাত | “অর্ডার করুন” চাপার মুহূর্ত | আগের রাত ১০টা | অর্ডার নিশ্চিতের মুহূর্ত |
| Target | ৬০ দিনে অর্ডার নেই | নিশ্চিত থেকে হাতে পাওয়া, ঘণ্টা | দিনের মোট অর্ডার | ৩০ দিনের মধ্যে ভুয়া প্রমাণিত |
| Loss | log loss | pinball, τ = ০.৯ | absolute বা pinball (কম কর্মীর দাম বেশি হলে τ > ০.৫) | log loss |
| Metric | কুপনের পরে ধরে রাখা ক্রেতা (uplift) | রক্ষার হার + গড় প্রতিশ্রুতি | MAE, পাশে অভাবের দিনের সংখ্যা | প্রতি ১০০০ অর্ডারে মোট খরচ |
| Baseline | “৪৫ দিন কেনেননি” নিয়ম | জেলাভিত্তিক ৯০তম percentile | seasonal naive | এখনকার নিয়ম |
| বড় ফাঁদ | তোলার দিনে মাপা recency | courier-এর তোলার সময় feature-এ | ছুটির দিন আর ঈদের মৌসুম | শুধু যাচাই হওয়া অর্ডারের label |
Churn-এ আসল প্রশ্ন “কে চলে যাবেন” নয়, “কুপন পেলে কার আচরণ বদলাবে”: এটি uplift বা causal প্রশ্ন, যা পর্ব ৬৪ (Causal inference-এর পরিচয়) আর পর্ব ৬৫-এ (Customer analytics) আসবে।
কখন ML নয়
Framing-এর একটি সৎ ফল হতে পারে: “এখানে ML লাগবে না।” কয়েকটি চেনা লক্ষণ:
- উত্তরটি হিসাব করা যায়: ডেলিভারি চার্জ ওজন আর জেলার একটি টেবিল থেকেই আসে; শেখার কিছু নেই।
- সরল নিয়ম baseline-এর মইয়ে টিকে যায়: চাহিদার উদাহরণে seasonal naive-কে সামান্য হারানো model-এর খরচ আর ঝুঁকি যুক্তিসংগত নাও হতে পারে।
- Label নেই বা অসম্ভব দেরিতে আসে: নতুন দোকানে churn-এর এক বছরের ইতিহাসও নেই।
- সিদ্ধান্ত বিরল কিন্তু বড়: নতুন গুদাম কোথায় হবে, বছরে একবার; এখানে বিশ্লেষণ আর মানুষের বিচার, model নয়।
- সিদ্ধান্তে ব্যাখ্যা আর আপিল লাগে: যেমন account বন্ধ করা; model শুধু সহায়ক।
Google-এর Martin Zinkevich-এর লেখা “Rules of Machine Learning” নির্দেশিকার প্রথম নিয়মটিই প্রায় এই কথা: machine learning ছাড়াই পণ্য চালু করতে ভয় পাবেন না। নিয়ম দিয়ে শুরু করলে ডেটা জমে আর পরে ML-এর তুলনার মানদণ্ড তৈরি থাকে।
আরও গভীরে: Gneiting (২০১১, JASA, “Making and Evaluating Point Forecasts”) দেখান কোন scoring function কোন পরিসংখ্যানের জন্য “consistent”, অর্থাৎ সৎ উত্তরকে পুরস্কৃত করে। Bartlett, Jordan ও McAuliffe (২০০৬, JASA, “Convexity, Classification, and Risk Bounds”) surrogate loss আর ০-১ ঝুঁকির সম্পর্ক প্রমাণ করেন। Kaufman, Rosset, Perlich ও Stitelman (২০১২, ACM TKDD, “Leakage in Data Mining”) ফাঁসকে “learn-predict separation” দিয়ে ব্যাখ্যা করেন। আর Elkan (২০০১, IJCAI, “The Foundations of Cost-Sensitive Learning”) খরচ থেকে threshold আর example-dependent cost আলোচনা করেন।
পরীক্ষা ও ইন্টারভিউতে:
- Squared, absolute আর pinball loss-এর সেরা constant কী? যথাক্রমে গড়, median আর τ-quantile; derivative শূন্য করে প্রমাণ।
- Huber loss-এর derivative? |r| ≤ δ হলে r, নইলে δ · sign(r); তাই বড় outlier-এর টান δ-তে আটকে থাকে।
- Hinge আর log loss-এর পার্থক্য? log loss proper, সম্ভাবনা শেখায়; hinge শুধু দিক শেখায় আর margin ১ পেরোলে থামে।
- Target leakage কীভাবে ধরবেন? প্রতিটি feature-এর “কখন জানা যায়” যাচাই, সন্দেহজনক রকম উঁচু score, একটি feature-এ অস্বাভাবিক importance, আর সময়ভিত্তিক ভাগে মাপ পড়ে যাওয়া।
- খরচ অসমান হলে threshold? Calibrated p-তে p > CFP / (CFP + CFN); খরচ অর্ডারভেদে হলে সীমাও অর্ডারভেদে।
৯ · AI-এর যুগে — AI assistant দিয়ে framing আর loss বাছাই যাচাই
AI assistant framing-এর খসড়া আর বিকল্প loss বা baseline দ্রুত দিতে পারে। কিন্তু সে জানে না আপনার কলাম কখন লেখা হয় বা দোকানের খরচ কত, আর প্রায়ই চেনা ছাঁচে উত্তর দেয়: “classification, accuracy, random split, XGBoost”.
| AI-এর সাধারণ ভুল | কীভাবে ধরবেন |
|---|---|
| সব কলাম feature-এ, কোনটি কখন জানা যায় তা না দেখে | প্রতিটি কলামের পাশে “কোন সময়ে জানা” লিখুন; prediction time-এর পরের সব বাদ |
| এলোমেলো split, সময়ের বা ক্রেতার গ্রুপ না মেনে | Unit আর cutoff দেখে time-based বা group split |
| Skewed target-এ squared loss, কিন্তু মূল্যায়ন MAE বা percentile-এ | Metric কোন পরিসংখ্যান চায় তা আগে লিখে loss মেলান |
| Imbalance-এ accuracy, আর threshold ০.৫ | Majority baseline-এর পাশে মাপুন; খরচ থেকে threshold |
| নেই এমন parameter বা পুরোনো API (যেমন বাদ পড়া loss নাম) | নিজের scikit-learn version-এর docs, আর একবার চালিয়ে দেখা |
| Loss-এর derivative বা সেরা constant-এর ভুল কিন্তু বিশ্বাসযোগ্য প্রমাণ | পাঁচটি সংখ্যায় হাতে বা কোডে যাচাই, অংশ ৫-এর মতো |
AI-কে সমাধান চাওয়ার আগে framing-এর প্রশ্নগুলো করাতে বলুন। নিচের prompt-এ ব্যক্তিগত ডেটা নেই, শুধু কলামের নাম আর ব্যবসার বিবরণ; আসল ক্রেতার তথ্য কখনো পেস্ট করবেন না।
AI-এর framing হাতে পেলে — যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।
প্র ০১একটি proxy label কীভাবে সম্পূর্ণ ঠিক কাজ করা model-কেও ক্ষতিকর বানাতে পারে?
সবচেয়ে বেশি আলোচিত উদাহরণ এসেছে স্বাস্থ্যসেবা থেকে। ২০১৯ সালে Ziad Obermeyer ও সহকর্মীরা Science-এ একটি গবেষণা প্রকাশ করেন, যেখানে যুক্তরাষ্ট্রের হাসপাতালগুলোতে ব্যবহৃত একটি বাণিজ্যিক ঝুঁকি-নির্ণয় algorithm বিশ্লেষণ করা হয়। লক্ষ্য ছিল কোন রোগীর বাড়তি যত্নের দরকার তা খুঁজে বের করা। কিন্তু “স্বাস্থ্যের প্রয়োজন” সরাসরি মাপা কঠিন, তাই algorithm-এর target ছিল ভবিষ্যৎ স্বাস্থ্য-খরচ। গবেষকদের বিশ্লেষণে দেখা যায়, একই খরচের স্তরে কৃষ্ণাঙ্গ রোগীরা গড়ে বেশি অসুস্থ ছিলেন, কারণ চিকিৎসার সুযোগে বৈষম্যের ফলে তাঁদের পেছনে কম খরচ হতো। ফলে model খরচ ঠিকভাবেই অনুমান করছিল, কিন্তু খরচ নিজেই প্রয়োজনের একটি পক্ষপাতদুষ্ট proxy ছিল। তাঁদের হিসাবে label বদলে স্বাস্থ্যের সরাসরি মাপের কাছাকাছি নিলে বাড়তি যত্নের জন্য বাছাই হওয়া কৃষ্ণাঙ্গ রোগীর অনুপাত অনেক বেড়ে যেত।
শিক্ষাটি হলো: model-এর accuracy, AUC বা calibration সবই ভালো থাকতে পারে, অথচ সিদ্ধান্ত ভুল হতে পারে, কারণ ভুলটা model-এ নয়, প্রশ্নে। কোনো metric এই ভুল ধরবে না, কারণ metric-ও সেই একই proxy label দিয়ে মাপা।
বাজারঘরে একই ফাঁদ ছোট আকারে আছে। “সন্তুষ্টি”-র proxy হিসেবে “অভিযোগ করেননি” নিলে যে ক্রেতারা অভিযোগ করতে অভ্যস্ত নন, বা যাঁদের কাছে হেল্পলাইনে ফোন করা কঠিন, তাঁরা সবাই সন্তুষ্ট দেখাবেন। ভুয়া অর্ডারের label যদি শুধু যাচাই হওয়া অর্ডার থেকে আসে, model শিখবে আগের নিয়ম কাদের সন্দেহ করত, ভুয়া কারা তা নয়।
প্রতিকার তিনটি স্তরে। প্রথমত, framing-এর নথিতে proxy আর আসল লক্ষ্যের ফাঁক স্পষ্ট লেখা। দ্বিতীয়ত, ছোট একটি নমুনায় আসল লক্ষ্য মাপা (যেমন কিছু ক্রেতার জরিপ), আর proxy-র সঙ্গে তার সম্পর্ক দলভেদে দেখা। তৃতীয়ত, ফলাফল বিভিন্ন দলে আলাদা করে মাপা, যা পর্ব ৬০-এ (ML-এ ন্যায্যতা) বিস্তারিত আসবে।
মূল উপলব্ধি: label একটি সিদ্ধান্ত, তথ্য নয়। Model যত ভালো, ভুল label-কে তত বিশ্বস্তভাবে বড় করে।
প্র ০২যদি শেষে accuracy বা খরচ দিয়েই বিচার হয়, তাহলে সরাসরি সেটি দিয়ে train না করে log loss বা hinge কেন?
প্রথম কারণ গাণিতিক। Classification-এর সবচেয়ে স্বাভাবিক লক্ষ্য, ভুলের সংখ্যা, একটি সিঁড়ির মতো function: ওজন একটু নাড়ালে বেশিরভাগ সময় একটি উদাহরণও দিক বদলায় না, তাই ঢাল শূন্য; আর যখন বদলায়, হঠাৎ লাফ। Gradient descent এখানে কোনো দিক পায় না। তার ওপর, একটি linear classifier-এর জন্যও ভুলের সংখ্যা ঠিক ঠিক সর্বনিম্ন করা সাধারণ অবস্থায় NP-hard বলে computational learning theory-তে পরিচিত ফল আছে। তাই আমরা একটি সহজ, convex, মসৃণ বা প্রায়-মসৃণ “বদলি” কমাই: surrogate loss.
দ্বিতীয় প্রশ্ন: বদলি কমালে আসল জিনিস কমবে তো? ২০০৬ সালে Peter Bartlett, Michael Jordan আর Jon McAuliffe দেখান, একটি convex margin loss যদি একটি সরল শর্ত মানে (মোটামুটি, m = 0-তে ঢাল ঋণাত্মক), তাহলে তার ঝুঁকি কমলে ০-১ ঝুঁকিও সেরা সম্ভাব্য মানের দিকে যায়, আর তাঁরা দুটির মধ্যে একটি পরিমাণগত সম্পর্কও দেন। Log loss, hinge, exponential loss (AdaBoost-এর পেছনে) সবাই এই শর্ত মানে। ২০০২ সালে Yi Lin আলাদাভাবে দেখান, hinge-এর সেরা উত্তর হলো sign(p − ½), অর্থাৎ এটি সরাসরি Bayes-সেরা সিদ্ধান্তের দিকে যায়, কিন্তু সম্ভাবনার মাপ হারায়।
তৃতীয় কারণ ব্যবহারিক। খরচের সিদ্ধান্তে প্রতিটি অর্ডারের p লাগে, আর খরচ বদলালে (ফোনের দাম বাড়ল, courier-এর চার্জ কমল) model নতুন করে train না করে শুধু সীমা বদলানোই সুবিধাজনক। Log loss-এর মতো proper loss সেটি সম্ভব করে: একবার ভালো সম্ভাবনা শিখলে যেকোনো খরচের কাঠামোয় সিদ্ধান্ত বসানো যায়। সরাসরি একটি নির্দিষ্ট খরচ দিয়ে train করলে model সেই খরচেই বাঁধা পড়ে।
তবে বিপরীত মতও আছে। কিছু ক্ষেত্রে, যেমন ranking বা নির্দিষ্ট precision-এ recall সর্বোচ্চ করা, সরাসরি metric-ঘনিষ্ঠ loss (pairwise ranking loss ইত্যাদি) ভালো কাজ করে, আর gradient boosting-এ কাস্টম loss দেওয়া সহজ। তখনও সাধারণত একটি মসৃণ রূপ লাগে।
মূল উপলব্ধি: loss হলো optimizer-এর ভাষা, metric হলো আপনার ভাষা। দুটির মাঝে একটি প্রমাণিত সেতু থাকলে বদলি দিয়ে train করা নিরাপদ।
প্র ০৩একটি offline metric-এ বড় উন্নতি কি সবসময় ব্যবসার উন্নতি? Netflix Prize থেকে কী শেখার আছে?
২০০৬ সালে Netflix একটি প্রকাশ্য প্রতিযোগিতা ঘোষণা করে: সিনেমার rating অনুমানে তাদের নিজস্ব ব্যবস্থার চেয়ে RMSE ১০% কমাতে পারলে দশ লাখ ডলার পুরস্কার। ২০০৯ সালে “BellKor’s Pragmatic Chaos” দল লক্ষ্যে পৌঁছে পুরস্কার জেতে। Metric ছিল স্পষ্ট, ডেটা ভাগ ছিল সতর্ক (একটি গোপন test অংশসহ), আর প্রতিযোগিতাটি matrix factorization ও ensemble-এর গবেষণাকে অনেক এগিয়ে দেয়।
কিন্তু পরে Netflix-এর প্রকৌশলীরা তাঁদের blog-এ লেখেন (২০১২), বিজয়ী সমাধানের সব অংশ তাঁরা চালু করেননি; তাঁদের ভাষ্যে, শেষ ধাপের বাড়তি নির্ভুলতা চালু করার প্রকৌশল-খরচের যোগ্য মনে হয়নি, যদিও প্রতিযোগিতার শুরুর দিকের কিছু কৌশল তাঁরা ব্যবহার করেন। তাঁরা আরও লেখেন, ততদিনে ব্যবসা DVD পাঠানো থেকে streaming-এর দিকে সরে গিয়েছিল, যেখানে rating অনুমানের চেয়ে কী দেখানো হবে (ranking) আর মানুষ আসলে কী দেখে, সেই সংকেত বেশি গুরুত্বপূর্ণ।
এখান থেকে তিনটি framing শিক্ষা। এক, metric একটি প্রশ্নের সঙ্গে বাঁধা; প্রশ্ন বদলালে (“কত rating দেবেন” থেকে “কী দেখবেন”) পুরোনো metric-এর উন্নতি কম কাজের হয়ে যায়। দুই, offline metric-এর শেষ কয়েক শতাংশ উন্নতির দাম প্রায়ই বেশি: বড় ensemble মানে ধীর, ব্যয়বহুল আর রক্ষণাবেক্ষণে কঠিন ব্যবস্থা। তিন, RMSE সব ভুলকে বর্গ দিয়ে সমান দেখে, অথচ ব্যবসার কাছে তালিকার ওপরের কয়েকটি সুপারিশই সবচেয়ে গুরুত্বপূর্ণ।
মূল উপলব্ধি: metric ব্যবসার প্রশ্নের একটি ছায়া; ছায়ার উন্নতি তখনই অর্থবহ, যখন প্রশ্নটি বদলায়নি আর উন্নতির দাম লাভের চেয়ে কম।
প্র ০৪দোকানের মজুদ ঠিক করতে চাহিদার কোন সংখ্যাটি অনুমান করা উচিত: গড়, না অন্য কিছু?
Operations research-এ একটি পুরোনো ও বিখ্যাত সমস্যা আছে, newsvendor problem: খবরের কাগজ বিক্রেতা সকালে কতগুলো কাগজ কিনবেন, যখন চাহিদা অনিশ্চিত আর বিকেলে বেঁচে যাওয়া কাগজ প্রায় মূল্যহীন। ধরুন একটি কাগজ কম পড়লে লাভ হারান cu টাকা (underage), একটি বেশি থাকলে লোকসান co টাকা (overage). প্রত্যাশিত খরচ সর্বনিম্ন করার সেরা মজুদ হলো চাহিদার বণ্টনের এই quantile:
τ* = cu / (cu + co)
প্রমাণটি অংশ ৫-এর pinball-যুক্তিই: মজুদ একটি একক বাড়ালে, চাহিদা তার বেশি হলে (সম্ভাবনা 1 − F) cu বাঁচে, কম হলে (সম্ভাবনা F) co নষ্ট হয়; দুটি সমান হয় যখন F = cu / (cu + co). আসলে এই খরচ-কাঠামোটাই τ-pinball loss-এর একটি গুণিতক, τ = cu / (cu + co).
বাজারঘরের উদাহরণে ধরুন একটি কাঁচা খাবারের বাক্স কম পড়লে ৳৯০ লাভ হারায়, আর বেশি থাকলে নষ্ট হয়ে ৳৩০ লোকসান। τ* = ৯০ / ১২০ = ০.৭৫। অর্থাৎ গড় চাহিদা নয়, চাহিদার ৭৫তম percentile পরিমাণ মজুদ রাখা লাভজনক। যদি model squared loss দিয়ে গড় শেখে আর মজুদ সেই গড়ে বসে, তাহলে প্রায় অর্ধেক দিন মাল কম পড়বে; ডান-হেলানো চাহিদায় তার চেয়েও বেশি দিন। আর পচনশীল নয় এমন পণ্যে co ছোট (শুধু গুদামের খরচ), তাই τ* আরও ওপরে।
এখান থেকে framing-এর একটি সাধারণ নিয়ম আসে, যাকে Gneiting ২০১১ সালে জোর দিয়ে বলেছিলেন: কোনো point forecast চাওয়ার সময় বলে দিন কোন পরিসংখ্যান চান। “আগামী কালের চাহিদা কত?” প্রশ্নটি অসম্পূর্ণ; “আগামী কালের চাহিদার ৭৫তম percentile কত?” সম্পূর্ণ। আরও ভালো হলো পুরো বণ্টন বা কয়েকটি quantile অনুমান করা, যাতে খরচ বদলালে নতুন model না লাগে। অনুমানের পরিসর আর তার নিশ্চয়তা পর্ব ২৪ আর পর্ব ৫৮-এ (Conformal prediction) আসবে।
মূল উপলব্ধি: অসমান খরচের সিদ্ধান্তে গড় প্রায় কখনো সেরা উত্তর নয়; খরচের অনুপাত বলে দেয় কোন quantile, আর loss সেটিকেই শেখাবে।
প্র ০৫Model নিজেই যখন ভবিষ্যতের label বদলে দেয়, তখন framing-এ কী ভাবতে হয়?
Churn model ঝুঁকিপূর্ণ ক্রেতাকে কুপন পাঠায়। কুপন পেয়ে অনেকে কেনেন, তাই তাঁদের label হয় “churn = ০”। পরের মাসে নতুন ডেটায় model আবার train হলে সে দেখবে, যাঁদের সে ঝুঁকিপূর্ণ বলেছিল তাঁরা আসলে থেকে গেছেন, আর শিখবে সেই ধরনের ক্রেতা নিরাপদ। পরের দফায় তাঁদের কুপন বন্ধ, তাঁরা চলে যান, আর চক্র ঘোরে। একে বলে feedback loop: model-এর সিদ্ধান্ত ভবিষ্যতের training ডেটা বদলে দেয়।
ভুয়া অর্ডারে একই সমস্যা আরও তীব্র। যে অর্ডার আটকানো হলো, সেটি আসলে ভুয়া ছিল কি না কখনো পুরোপুরি জানা যায় না (selective labels). Juan Perdomo ও সহকর্মীরা ২০২০ সালে “Performative Prediction” প্রবন্ধে এমন পরিস্থিতির একটি আনুষ্ঠানিক কাঠামো দেন, যেখানে অনুমান নিজেই ডেটার বণ্টন বদলায়। D. Sculley ও সহকর্মীরা ২০১৫ সালের “Hidden Technical Debt in Machine Learning Systems” প্রবন্ধে এমন লুকানো feedback loop-কে ML ব্যবস্থার একটি প্রধান ঝুঁকি হিসেবে তালিকাভুক্ত করেন।
Framing-এর পর্যায়েই কয়েকটি প্রতিরোধ বসানো যায়:
- Holdout দল: এলোমেলোভাবে বাছা অল্প কিছু ঝুঁকিপূর্ণ ক্রেতাকে কুপন না পাঠানো, যাতে “হস্তক্ষেপ ছাড়া কী হতো” তার নিরপেক্ষ label জমে। ভুয়া অর্ডারে সামান্য কিছু অর্ডার এলোমেলোভাবে যাচাই করা।
- সিদ্ধান্তের খাতা: কাকে কী score-এ কী করা হলো, সব লিখে রাখা, যাতে পরে treatment-এর প্রভাব আলাদা করা যায়।
- প্রশ্ন বদলানো: “কে চলে যাবেন” না জিজ্ঞেস করে “কুপনে কার আচরণ বদলাবে” (uplift), যা পর্ব ৬৪-এর causal inference-এর বিষয়।
Holdout-এর একটি নৈতিক ও ব্যবসায়িক দাম আছে (কিছু ক্রেতা কুপন পান না, কিছু ভুয়া অর্ডার পার পায়), তাই দলের আকার আর মেয়াদ সচেতনভাবে ঠিক করতে হয়।
মূল উপলব্ধি: যে model সিদ্ধান্ত নেয়, সে শুধু পৃথিবী দেখে না, বদলায়ও। ভবিষ্যতের সৎ label-এর জন্য framing-এই জায়গা রাখতে হয়।
অনুশীলন
কাগজ-কলম আর একটি Python সেশন হাতে রাখুন।
-
হাতে হিসাব (numerical): পাঁচটি অর্ডারের ডেলিভারি ঘণ্টা: ১০, ১২, ১৫, ২০, ৪০। (ক) গড়, median আর ২৫% quantile (pinball, τ = ০.২৫-এর সেরা constant) বের করুন। (খ) c = ১০, ১২, ১৫-এ মোট pinball loss (τ = ০.২৫) হিসাব করে মিলিয়ে দেখুন। (গ) Huber (δ = ১)-এর derivative r = ০.৪ আর r = −৩-এ কত? (ঘ) Natural log-এ log loss log(1 + e−m)-এর derivative m = ০ আর m = ২-এ কত?
(ক) গড় = ৯৭/৫ = ১৯.৪; median = ১৫; τ = ০.২৫, n = ৫, τn = ১.২৫, তাই সেরা c হলো এমন মান যার নিচে ১.২৫-এর বেশি নয় আর সমান-বা-নিচে ১.২৫-এর কম নয় এমন বিন্দু: c = ১২।
(খ) c = ১০: সব residual ≥ 0, তাই ০.২৫ × (০ + ২ + ৫ + ১০ + ৩০) = ১১.৭৫। c = ১২: নিচের ১০-এ ০.৭৫ × ২ = ১.৫; ওপরে ০.২৫ × (০ + ৩ + ৮ + ২৮) = ৯.৭৫; মোট ১১.২৫। c = ১৫: ০.৭৫ × (৫ + ৩) = ৬; ০.২৫ × (৫ + ২৫) = ৭.৫; মোট ১৩.৫। সবচেয়ে কম c = ১২-এ। (তুলনা: squared loss-এর মোট c = ১৫-এ ৬৮৪, c = ১৯.৪-এ ৫৮৭.২, গড়ই জেতে।)
(গ) |০.৪| ≤ ১, তাই derivative = r = ০.৪; |−৩| > ১, তাই δ · sign(r) = −১।
(ঘ) derivative = −1/(1 + em). m = ০-তে −০.৫; m = ২-এ −1/(1 + 7.389) ≈ −০.১১৯। ঠিক দিকে আত্মবিশ্বাস বাড়লেও log loss একটু ঠেলতে থাকে, hinge সেখানে থেমে যায়।
-
নকশা ও সমালোচনা: একজন সহকর্মী এই framing দিলেন: “Target: account_status = ‘deleted’. Feature: last_login (আজকের টেবিল থেকে), total_orders, refund_count, সব সময়ের। এলোমেলো ৮০/২০ split. Metric: accuracy. লক্ষ্য: যাঁরা account মুছবেন, তাঁদের কুপন।” অন্তত পাঁচটি সমস্যা চিহ্নিত করে একটি ভালো framing লিখুন।
- Target: account মোছা খুব বিরল আর churn-এর খুব সরু অংশ; বেশিরভাগ চলে যাওয়া ক্রেতা account মোছেন না। Label window-ও নেই।
- Prediction time নেই: last_login আজকের টেবিল থেকে, তাই যিনি মুছেছেন তাঁর last_login স্বাভাবিকভাবেই পুরোনো: temporal leakage.
- সব সময়ের গোনা: total_orders আর refund_count-এ label-এর পরের ঘটনাও ঢুকেছে।
- এলোমেলো split: সময় আর ক্রেতা মানা হয়নি।
- Accuracy: বিরল শ্রেণিতে “কেউ মুছবেন না” বললেই প্রায় ১০০%; majority baseline নেই।
- সিদ্ধান্তের অমিল: account মুছতে চাওয়া ক্রেতাকে কুপন পাঠানো হয়তো বিরক্তিকরও।
ভালো framing: unit = আগের ৯০ দিনে সক্রিয় ক্রেতা × মাসিক cutoff; target = cutoff-এর পরের ৬০ দিনে অর্ডার নেই; feature শুধু cutoff পর্যন্ত (অর্ডার সংখ্যা, recency, ফেরত); অসম্পূর্ণ জানালা বাদ; time-based split; loss = log loss; metric = AUC আর প্রতি কুপনে খরচ বা লাভ; baseline = “৪৫ দিন কেনেননি” নিয়ম আর DummyClassifier; সঙ্গে একটি holdout দল।
-
আউটপুট অনুমান করুন: চালানোর আগে লিখুন নিচের কোড কী ছাপবে।
import numpy as np from sklearn.dummy import DummyRegressor y = np.array([2, 3, 3, 4, 13.0]); X = np.zeros((5, 1)) for s, kw in [("mean", {}), ("median", {}), ("quantile", {"quantile": 0.75})]: m = DummyRegressor(strategy=s, **kw).fit(X, y) print(s, m.predict(X[:1])) for c in (3, 5): print(c, np.mean(np.abs(y - c)), np.mean((y - c) ** 2))লেখার সময়ে ডেস্কটপে (Python 3.14, scikit-learn 1.9.1) চালানো সত্যিকারের আউটপুট:
mean [5.] median [3.] quantile [4.] 3 2.4 20.4 5 3.2 16.4গড় ২৫/৫ = ৫; median ৩; ৭৫% quantile ৪ (পাঁচটি মানে অবস্থান ০.৭৫ × ৪ = ৩, অর্থাৎ সাজানো তালিকার চতুর্থটি)। তারপর loss: c = ৩-এ MAE (১ + ০ + ০ + ১ + ১০)/৫ = ২.৪, MSE (১ + ০ + ০ + ১ + ১০০)/৫ = ২০.৪; c = ৫-এ MAE ৩.২ কিন্তু MSE ১৬.৪। অর্থাৎ MAE-তে median (৩) জেতে, MSE-তে গড় (৫): যে metric দিয়ে বিচার, সেই অনুযায়ী baseline বাছতে হয়।
-
কোডিং: pandas দিয়ে একটি অর্ডার টেবিল থেকে churn-এর training টেবিল বানান। Cutoff ২০২৬-০৩-৩১; unit = আগের ৯০ দিনে অন্তত একটি অর্ডার; feature: ওই ৯০ দিনের অর্ডার সংখ্যা আর cutoff-এ recency (দিন); label = পরের ৬০ দিনে অর্ডার নেই। অর্ডার: A (০১-০৫, ০৩-২০, ০৪-১৫), B (০২-১০, ০৩-২৮), C (০১-২০), D (০৩-৩০, ০৫-০২), E (০৪-১০)।
import pandas as pd orders = pd.DataFrame({ "customer": ["A", "A", "A", "B", "B", "C", "D", "D", "E"], "date": pd.to_datetime(["2026-01-05", "2026-03-20", "2026-04-15", "2026-02-10", "2026-03-28", "2026-01-20", "2026-03-30", "2026-05-02", "2026-04-10"]), }) cut = pd.Timestamp("2026-03-31") past = orders[(orders.date > cut - pd.Timedelta(days=90)) & (orders.date <= cut)] future = orders[(orders.date > cut) & (orders.date <= cut + pd.Timedelta(days=60))] feat = past.groupby("customer").agg(n_orders_90d=("date", "size"), last=("date", "max")) feat["recency_days"] = (cut - feat.pop("last")).dt.days feat["churn"] = (~feat.index.isin(future.customer)).astype(int) print(feat)লেখার সময়ে ডেস্কটপে (pandas 3.1.1) চালানো সত্যিকারের আউটপুট:
n_orders_90d recency_days churn customer A 2 11 0 B 2 3 1 C 1 70 1 D 1 1 0E নেই, কারণ cutoff-এর আগে তাঁর কোনো অর্ডার নেই (তিনি এই unit-এর বাইরে)। A-এর জানুয়ারির অর্ডার গোনা হয়েছে, কারণ ৫ জানুয়ারি cutoff-এর আগের ৯০ দিনের (১ জানুয়ারি থেকে ৩১ মার্চ) ভেতরে পড়ে। D-এর ০৫-০২-এর অর্ডার ৬০ দিনের জানালায় পড়ে, তাই churn = ০। মূল কৌশল: feature শুধু
pastথেকে, label শুধুfutureথেকে, আর দুটির সীমা একইcut.
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি ML task লেখার ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- ব্যবসার প্রশ্ন আর তার সঙ্গে বাঁধা সিদ্ধান্ত লেখা
- Target-এর সংজ্ঞা আর label window ঠিক করা
- Unit of prediction আর prediction time ঠিক করা
- শুধু prediction time-এ জানা তথ্য থেকে feature বাছা
- যে পরিসংখ্যান দরকার, তা শেখায় এমন loss বাছা
- Metric আর baseline একই split-এ মাপা
পাঁচটি ডেলিভারির দিন ১, ২, ২, ৩, ৭। সব অর্ডারের জন্য একটিই সংখ্যা বলতে হলে squared loss-এর মোট সবচেয়ে কম হয় কোন সংখ্যায়?
- ২
- ৩
- ২.৩৩
- ৭
একটি regression model pinball loss দিয়ে τ = ০.৯-এ train করা হলো। একটি অর্ডারের জন্য তার অনুমানকে সবচেয়ে ঠিকভাবে কী বলা যায়?
- ওই ধরনের অর্ডারের গড় ডেলিভারির সময়
- ওই ধরনের অর্ডারের median সময়
- ওই ধরনের অর্ডারের ৯০% যে সময়ের মধ্যে পৌঁছায়, তার অনুমান
- সময়মতো পৌঁছানোর সম্ভাবনা ০.৯
Churn model-এ feature “শেষ অর্ডারের পর কত দিন” হিসাব করা হয়েছে ডেটা তোলার দিনে, যা label window শেষ হওয়ার পরে। Test-এ AUC ০.৯৫। সবচেয়ে সম্ভাব্য ব্যাখ্যা কী?
- Recency churn-এর খুব শক্তিশালী সূচক, তাই model চমৎকার
- Model overfit করেছে, regularization বাড়ালে ঠিক হবে
- Class imbalance-এর কারণে AUC বেশি দেখাচ্ছে
- Temporal leakage: feature-এ label window-এর তথ্য ঢুকেছে
খরচ দেখে threshold বসাতে প্রতিটি অর্ডারের ভালো সম্ভাবনা দরকার। কোন loss দিয়ে train করা model সাধারণত এটি দেয়, আর কেন?
- Log loss, কারণ এটি proper scoring rule
- Hinge, কারণ এটি margin বড় করে
- ০-১ loss, কারণ এটি সরাসরি ভুল গোনে
- Absolute loss, কারণ outlier-এ নড়ে না
একটি যাচাই-ফোনের খরচ ৳৪০। একটি ভুয়া অর্ডার ছাড় পেলে ক্ষতি ৳২০০০। Model-এর সম্ভাবনা calibrated হলে এই অর্ডারে কোন সম্ভাবনার ওপরে ফোন করা লাভজনক?
- ০.৫
- ০.০৪
- ০.০২
- ০.৯৮
একটি দোকানের দৈনিক অর্ডারে স্পষ্ট সাপ্তাহিক ছন্দ আছে (শুক্রবার সবচেয়ে বেশি)। পরের দিনের অর্ডার অনুমানের model-এর জন্য প্রথম যে baseline-কে হারানো জরুরি, সেটি কোনটি?
- সব দিনের গড়
- Seasonal naive: সাত দিন আগের একই বারের মান
- Naive: আগের দিনের মান
- Train ডেটার সবচেয়ে ঘন ঘন দেখা সংখ্যা
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- ML task = প্রশ্ন → target → unit → prediction time → feature → loss → metric; প্রতিটি আংটা লিখে রাখুন।
- Feature আসবে শুধু prediction time পর্যন্ত জানা তথ্য থেকে; label window আর ডেটা তোলার দিন আলাদা রাখুন।
- Squared → গড়, absolute → median, pinball τ → τ-quantile, log loss → সম্ভাবনা, hinge → শুধু দিক.
- Loss, metric আর ব্যবসার মূল্য আলাদা; loss আর metric একই পরিসংখ্যান চাইলে ভালো, আর অন্তত দুটি পরস্পরবিরোধী metric দেখুন।
- Baseline-এর মই একই split-এ; খরচ অর্ডারভেদে হলে সিদ্ধান্ত p > CFP / (CFP + CFN), প্রতিটি অর্ডারে নিজের সীমায়।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ০৩ · শেখার তত্ত্ব — ERM, generalisation gap, PAC আর VC-এর অন্তর্দৃষ্টিপরবর্তী পর্বTraining-এর loss থেকে নতুন ডেটার ঝুঁকি: কখন আর কতটা বিশ্বাস করা যায়।
- মেশিন লার্নিং · কোর্স হোম৭৭টি পর্বপুরো কোর্সের ১৪টি মডিউলের মানচিত্র।
- AI-এর ভিত্তি কোর্সের পর্ব ৫৬ · Train, validation আর test — data leakage-এর ফাঁদআগের কোর্সLeakage-এর চার চেহারা আর split-এর নিয়ম।
- AI-এর ভিত্তি কোর্সের পর্ব ৬০ · মূল্যায়ন — accuracy, precision, recall, F1 আর ROCআগের কোর্সConfusion matrix, threshold আর খরচের প্রথম হিসাব।
- DBMS ও SQL · Window functionপাশের ট্র্যাকতারিখ ধরে point-in-time feature SQL-এ বানানোর হাতিয়ার।