সরাসরি পর্বে যান
পর্ব ২২ · ৭৭-এর মধ্যে · মডিউল ৪

Model তুলনার পরিসংখ্যান — paired test, McNemar আর একাধিক তুলনা

Statistics for Comparing Models — McNemar's Test, Corrected and 5×2cv Paired Tests, Friedman Test and Multiple-Comparison Corrections

Taught in Bangla, this lesson matches each comparison question to a test: McNemar's test on one test set, corrected resampled t and 5×2cv for algorithms, and Friedman with Nemenyi critical difference across datasets. In-browser simulations show naive t-tests on repeated CV rejecting a true null about half the time, and compare Bonferroni, Holm and Benjamini–Hochberg, plus practical significance and ROPE.

এই পর্বে যা শিখবেন

  • দুই classifier-এর অনুমান থেকে McNemar-এর 2×2 টেবিল বানানো, হাতে χ² আর exact p-value বের করা, আর পার্থক্যের interval দেওয়া
  • CV-র fold কেন পরস্পর-সম্পর্কিত, naive t-test কত ভুল করে, আর corrected test ও 5×2cv কীভাবে কাজ করে (simulation দিয়ে যাচাই)
  • অনেক ডেটাসেটে অনেক model তুলনায় average rank, Friedman test আর Nemenyi-র critical difference
  • Bonferroni, Holm আর Benjamini–Hochberg হাতে চালানো, আর FWER বনাম FDR-এর পার্থক্য সংখ্যায় দেখা
  • Statistical আর practical significance আলাদা করা, আর Bayesian তুলনার ROPE ধারণা

AI-এর ভিত্তি কোর্সের পর্ব ৩৭-এ hypothesis test, p-value, t-test আর Bonferroni-র প্রথম পরিচয় পেয়েছেন, আর পর্ব ৬৬-এ repeated আর nested CV. এই কোর্সের পর্ব ০৪-এ seed-ভেদে ছড়ানো, mean ± sd আর Nadeau–Bengio-র corrected resampled t-test দেখেছেন, সেখানে প্রতিশ্রুতি ছিল তুলনার পূর্ণ পরিসংখ্যান এখানে আসবে। এই পর্ব সেই কাজটি করে: কোন প্রশ্নে কোন test, test-টি নিজেই কতটা সৎ, আর অনেকগুলো তুলনা একসঙ্গে করলে কী হয়। চালানো যায় এমন চারটি ব্লক পাতাতেই চলে (ব্রাউজারের Python, SciPy, scikit-learn আর statsmodels); প্রথমবার প্যাকেজ নামতে কয়েক সেকেন্ড লাগে, scikit-learn-এ প্রায় দশ সেকেন্ড।

১ · “০.৮৬ বনাম ০.৮৪” কেন যথেষ্ট নয় — আগে প্রশ্নটি ঠিক করা

দুজন ডাক্তার একই ১০০ জন রোগী দেখলেন। ডাক্তার ক ৮৬ জনের রোগ ঠিক ধরলেন, ডাক্তার খ ৮৪ জনের। ক কি ভালো? এখন খেয়াল করুন: যে রোগীদের দুজনই ঠিক ধরেছেন, বা দুজনই ভুল করেছেন, তাঁরা কে ভালো সে বিষয়ে কিছুই বলেন না। প্রশ্নের উত্তর লুকিয়ে আছে শুধু মতভেদের রোগীদের মধ্যে: কতজনকে শুধু ক ঠিক ধরেছেন, আর কতজনকে শুধু খ। যদি সেই সংখ্যা ৬ বনাম ৪ হয়, তাহলে ১০টি মতভেদের মধ্যে ৬–৪ ফল মুদ্রা ছোড়াতেও সহজে আসে।

ML-এ “model A-র accuracy ০.৮৬, B-র ০.৮৪” লাইনটি প্রতিদিন লেখা হয়। এর পেছনে অন্তত তিনটি এলোমেলোতার উৎস আছে: test set (কোন সারিগুলো মাপার জন্য পড়েছে), training set (কোন সারিগুলো দিয়ে শেখানো হয়েছে), আর algorithm-এর ভেতরের এলোমেলোতা (seed, initialization). কোন উৎস হিসাবে ধরবেন, তা নির্ভর করে প্রশ্নের ওপর। Thomas Dietterich ১৯৯৮ সালে Neural Computation-এ প্রশ্নগুলোকে মোটামুটি এভাবে আলাদা করেছিলেন:

প্রশ্নকোন এলোমেলোতা গুনতে হয়সাধারণ testএই পাতায়
এই দুটি trained model-এর কোনটি নতুন ডেটায় ভালো?শুধু test setMcNemar testঅংশ ২–৩
এই ডেটার আকারে কোন algorithm ভালো?training set + test setcorrected t, 5×2cvঅংশ ৪–৫
অনেক ডেটাসেটে কোন algorithm সাধারণত ভালো?ডেটাসেট নিজেই নমুনাWilcoxon, Friedmanঅংশ ৬
অনেকগুলো তুলনার কোনগুলো বিশ্বাসযোগ্য?বাছাইয়ের সুযোগHolm, BHঅংশ ৭–৮

প্রতিটি test-এর কাঠামো একই, যা পর্ব ৩৭-এ দেখেছেন: একটি null hypothesis (দুজন সমান ভালো), একটি test statistic, আর p-value = null সত্য হলে এত বড় বা আরও বড় statistic আসার সম্ভাবনা। একটি test “সৎ” যদি null সত্য হলে তার p < ০.০৫ হওয়ার হার সত্যিই প্রায় ৫% হয়; এই হারকে বলে Type I error rate. আর আসল পার্থক্য ধরার সম্ভাবনা হলো test-এর power.

২ · একই test set-এ দুই classifier — McNemar-এর 2×2 টেবিল

দুটি classifier A আর B একই n-টি test সারিতে অনুমান করেছে। প্রতিটি সারি চারটি ঘরের একটিতে পড়ে, আর এই ঘরগুলো একটি contingency table:

B ঠিকB ভুল
A ঠিকa (দুজনই ঠিক)b (শুধু A ঠিক)
A ভুলc (শুধু B ঠিক)d (দুজনই ভুল)

A-র accuracy (a + b)/n, B-র (a + c)/n, তাই পার্থক্য (b − c)/n: a আর d বাদ পড়ে যায়। b আর c-কে বলে discordant (মতভেদের) সারি। Null hypothesis হলো দুজনের ভুলের হার সমান; সেটি সত্য হলে, মতভেদের কোনো সারিতে “A ঠিক” হওয়ার সম্ভাবনা ঠিক ½. অর্থাৎ b + c-টি মতভেদ দেওয়া থাকলে b একটি binomial(b + c, ½) চলক। এখান থেকে দুটি রূপ আসে:

Exact: p = 2 · P(X ≥ max(b, c)), X ~ Binomial(b + c, ½)    χ² রূপ: χ² = (|b − c| − 1)² / (b + c), df = 1

χ² রূপটি binomial-এর normal approximation-এর বর্গ: b − c-এর গড় ০ আর variance b + c, তাই (b − c)/√(b + c) প্রায় standard normal, আর তার বর্গ ১ df-এর χ². “−১” হলো continuity correction: পূর্ণসংখ্যার গণনাকে মসৃণ বক্ররেখা দিয়ে মাপলে যে আশাবাদী ঝোঁক আসে, তা কমানো (A. L. Edwards ১৯৪৮ সালে এই সংশোধন প্রস্তাব করেন বলে প্রচলিত)। Quinn McNemar পরীক্ষাটি ১৯৪৭ সালে Psychometrika-তে প্রকাশ করেন, মনোবিজ্ঞানে একই মানুষের আগে-পরে উত্তরের তুলনার জন্য। b + c ছোট হলে (অনেক বইয়ে ২৫-এর নিচে বলা হয়, এটি একটি প্রথা) exact রূপ নিন।

অর্ডার ১ থেকে ১০1 = ফেরত আসবে

            
  1. তিনটি সারি। দশটি অর্ডারের আসল ফল আর দুই model-এর অনুমান। আলাদা আলাদা accuracy দেখার বদলে প্রতিটি অর্ডারে দুজনকে পাশাপাশি দেখতে হবে, কারণ দুজন একই অর্ডার দেখেছে: এটিই paired তুলনা।
  2. প্রতিটি অর্ডারের ঘর। A ভুল করেছে অর্ডার ৩ আর ৬-এ, B ভুল করেছে ২, ৪, ৬ আর ৯-এ। অর্ডার ৬-এ দুজনই ভুল (d); ২, ৪ আর ৯-এ শুধু A ঠিক (b); ৩-এ শুধু B ঠিক (c); বাকি পাঁচটিতে দুজনই ঠিক (a).
  3. টেবিল। a = ৫, b = ৩, c = ১, d = ১; যোগফল ১০. প্রতিটি অর্ডার ঠিক একটি ঘরে।
  4. Accuracy-র উৎস। A-র ৮/১০ = a + b, B-র ৬/১০ = a + c. বিয়োগ করলে a কেটে যায়: পার্থক্য (b − c)/n = ২/১০. অর্থাৎ পুরো তুলনাটি মাত্র চারটি মতভেদের অর্ডারে দাঁড়িয়ে।
  5. Exact p. Null-এ b ~ Binomial(৪, ½). P(X ≥ ৩) = [C(৪,৩) + C(৪,৪)]/১৬ = ৫/১৬. Two-sided p = ২ × ৫/১৬ = ০.৬২৫.
  6. শিক্ষা। Accuracy-তে ২০ শতাংশ বিন্দুর পার্থক্য, তবু p = ০.৬২৫: চারটি মতভেদে ৩–১ ফল মুদ্রা ছুড়েও প্রায়ই আসে। ছোট test set-এ বড় দেখানো পার্থক্যও প্রমাণ নয়।

McNemar কী মাপে না। এটি দুটি নির্দিষ্ট, ইতিমধ্যে train করা model-এর তুলনা; এলোমেলোতা শুধু test set থেকে। অন্য training ডেটায় বা অন্য seed-এ train করলে ফল কী হতো, সে প্রশ্ন এটি তোলে না। আর একটি শর্ত: test সারিগুলো পরস্পর স্বাধীন হতে হবে; একই গ্রাহকের দশটি অর্ডার test set-এ থাকলে তারা স্বাধীন নয়, তখন গ্রাহক ধরে bootstrap (পর্ব ২১, Bootstrap আর resampling) বেশি নিরাপদ।

৩ · McNemar হাতে-কলমে — χ², exact binomial আর statsmodels

বাজারঘরের ১,৫০০টি কাল্পনিক অর্ডার: ডেলিভারিতে কত দিন, দাম, আর এটি গ্রাহকের প্রথম অর্ডার কি না। লক্ষ্য, অর্ডারটি ফেরত আসবে কি না। প্রথম ১,০০০টিতে দুটি model train হয়, A = logistic regression, B = গভীরতা ৪-এর decision tree; শেষ ৫০০টি তালাবন্ধ test set. ব্লকটি টেবিল বানায়, তারপর তিনভাবে p-value বের করে: নিজের সূত্রে χ², SciPy-র binomtest দিয়ে exact, আর statsmodels-এর mcnemar দিয়ে যাচাই।

import numpy as np
from scipy import stats
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from statsmodels.stats.contingency_tables import mcnemar

rng = np.random.default_rng(22)          # কাল্পনিক বাজারঘর: অর্ডার ফেরত আসবে কি না
n = 1500
days = rng.gamma(3, 1.2, n)              # ডেলিভারিতে দিন
price = rng.lognormal(6.5, 0.6, n) / 100 # দাম, শত টাকা
first = rng.integers(0, 2, n)            # প্রথম অর্ডার?
z = -3 + 0.45 * days + 0.08 * price + 0.9 * first + 0.6 * (days > 5) * first
y = (rng.random(n) < 1 / (1 + np.exp(-z))).astype(int)
X = np.column_stack([days, price, first])
tr, te = slice(0, 1000), slice(1000, None)   # প্রথম ১০০০ train, শেষ ৫০০ test

pA = LogisticRegression(C=1.0).fit(X[tr], y[tr]).predict(X[te])
pB = DecisionTreeClassifier(max_depth=4, random_state=0).fit(X[tr], y[tr]).predict(X[te])
okA, okB = pA == y[te], pB == y[te]
print(f"accuracy  A (logistic) = {okA.mean():.3f}   B (tree) = {okB.mean():.3f}")

a = int(np.sum(okA & okB)); b = int(np.sum(okA & ~okB))
c = int(np.sum(~okA & okB)); d = int(np.sum(~okA & ~okB))
print("table [[both right, only A right], [only B right, both wrong]]:")
print(np.array([[a, b], [c, d]]))
chi2 = (abs(b - c) - 1) ** 2 / (b + c)                # Edwards-এর continuity correction
print(f"chi2 (corrected) = {chi2:.3f}, p = {stats.chi2.sf(chi2, 1):.4f}")
print(f"exact binomial: p = {stats.binomtest(b, b + c, 0.5).pvalue:.4f}")
r1 = mcnemar([[a, b], [c, d]], exact=True)
r2 = mcnemar([[a, b], [c, d]], exact=False, correction=True)
print(f"statsmodels exact p = {r1.pvalue:.4f}, chi2 p = {r2.pvalue:.4f}")

আসল আউটপুট (ব্রাউজারের Python):

accuracy  A (logistic) = 0.678   B (tree) = 0.634
table [[both right, only A right], [only B right, both wrong]]:
[[291  48]
 [ 26 135]]
chi2 (corrected) = 5.959, p = 0.0146
exact binomial: p = 0.0141
statsmodels exact p = 0.0141, chi2 p = 0.0146

A-র accuracy ০.৬৭৮, B-র ০.৬৩৪: পার্থক্য ০.০৪৪, যা (b − c)/n = (৪৮ − ২৬)/৫০০ = ২২/৫০০ হুবহু। ৫০০টির মধ্যে ৪২৬টিতে (২৯১ + ১৩৫) দুজন একই ফল দিয়েছে; পুরো সিদ্ধান্ত ৭৪টি মতভেদের ওপর। নিজের সূত্রে χ² = (২২ − ১)²/৭৪ = ৪৪১/৭৪ = ৫.৯৫৯, p = ০.০১৪৬. Exact binomial-এ p = ০.০১৪১, প্রায় একই, কারণ ৭৪টি মতভেদ normal approximation-এর জন্য যথেষ্ট। statsmodels-এর দুটি রূপ হুবহু মিলেছে। তাহলে এই test set-এ logistic regression ভালো, আর এটি কাকতাল হওয়ার সম্ভাবনা কম। প্রথমবার scikit-learn আর statsmodels নামতে কয়েক সেকেন্ড লাগে।

p-value-এর পাশে পার্থক্যের interval

p-value বলে “শূন্য পার্থক্যের সঙ্গে ডেটা কতটা বেমানান”, কিন্তু পার্থক্য কত বড় হতে পারে বলে না। জোড়া অনুপাতের পার্থক্য d̂ = (b − c)/n-এর standard error:

SE = √[ (b + c)/n − d̂² ] / √n

এখানে (b + c)/n = ০.১৪৮ আর d̂² = ০.০০১৯৪, তাই SE = √০.১৪৬১ / √৫০০ = ০.৩৮২২/২২.৩৬ ≈ ০.০১৭১. ৯৫% interval (Wald রূপ) ০.০৪৪ ± ১.৯৬ × ০.০১৭১ = [০.০১০৫, ০.০৭৭৫]. রিপোর্টের লাইন: “একই ৫০০টি test অর্ডারে A − B = +৪.৪ শতাংশ বিন্দু (৯৫% CI ১.১ থেকে ৭.৮), McNemar exact p = ০.০১৪”.

৪ · CV fold কেন স্বাধীন নয় — corrected test আর 5×2cv

এবার দ্বিতীয় প্রশ্ন: algorithm A কি এই আকারের ডেটায় B-র চেয়ে ভালো? এখানে training set-এর এলোমেলোতাও গুনতে হয়, তাই একটি test set যথেষ্ট নয়; চাই অনেক train/test ভাগ। সবচেয়ে প্রচলিত পথ: একই k-fold ভাগে দুজনকে চালিয়ে প্রতিটি fold-এর পার্থক্য d1, …, dk নেওয়া, তারপর paired t-test: t = d̄ / √(s²/k), k − 1 df. সমস্যা হলো t-test ধরে নেয় d-গুলো স্বাধীন। নিচের stepper দেখায় কেন তারা নয়।

n = 100, ১০-foldtrain ৯০ · test ১০

            
  1. Test অংশ। ১০টি fold-এর test অংশ পরস্পর আলাদা, প্রতিটি সারি ঠিক একবার test হয়। এই দিক থেকে সব ঠিক আছে।
  2. Training অংশ। কিন্তু যেকোনো দুটি fold-এর training set-এ ১০০ − ১০ − ১০ = ৮০টি সারি এক, অর্থাৎ ৯০-এর প্রায় ৮৯%. দুটি model প্রায় একই ডেটায় শেখে।
  3. সম্পর্কিত পার্থক্য। তাই কোনো ডেটাসেটে যদি ভাগ্যক্রমে A-র পক্ষে কিছু থাকে (যেমন কিছু অদ্ভুত সারি যা A ভালো সামলায়), তা প্রায় সব fold-এ একসঙ্গে দেখা দেয়। d-গুলোর মধ্যে ধনাত্মক correlation ρ আসে।
  4. গড়ের আসল variance. J-টি সংখ্যার প্রতিটির variance σ² আর যেকোনো দুটির correlation ρ হলে Var(d̄) = σ²[ρ + (১ − ρ)/J]. ρ = ০ হলে সাধারণ σ²/J; কিন্তু ρ = ০.১ আর J = ১০ হলেই ০.১৯σ², প্রায় দ্বিগুণ। আর J বাড়ালে প্রথম পদ ρσ² কখনো কমে না।
  5. Nadeau–Bengio. নমুনার s² আসলে প্রায় (১ − ρ)σ² মাপে। তাঁরা ρ-কে ntest/n হিসেবে অনুমান করে লেখেন Var(d̄) ≈ s²(1/J + ntest/ntrain). ১০-fold-এ ntest/ntrain = ১০/৯০ = ০.১১১, তাই গুণক ০.১ থেকে ০.২১১, আর SE প্রায় ১.৪৫ গুণ।
  6. Repeated CV. ১০ বার ১০-fold চালালে J = ১০০. Naive গুণক ০.০১, কিন্তু সংশোধিত ০.১২১: SE প্রায় ৩.৫ গুণ। পুনরাবৃত্তি গড়কে স্থির করে, কিন্তু নতুন ডেটা আনে না; naive t সেটিকে নতুন প্রমাণ ভেবে ভুল করে।

Yoshua Bengio আর Yves Grandvalet ২০০৪ সালে দেখান যে k-fold CV-র variance-এর কোনো সাধারণ unbiased অনুমান নেই; তাই প্রতিটি সংশোধনই আনুমানিক। Claude Nadeau আর Bengio-র সংশোধন (২০০৩, Machine Learning জার্নাল) এসেছিল random subsampling-এর জন্য, আর Remco Bouckaert ও Eibe Frank ২০০৪ সালে একে ১০ × ১০ repeated CV-তে প্রয়োগ করে ভালো ফল পান। পর্ব ০৪-এ এই সংশোধন দিয়ে interval চওড়া করেছিলেন; এখানে আরেকটি পথ।

Dietterich-এর 5×2cv paired t-test

ভাবনাটি হলো fold-এর overlap সীমিত রাখা। ডেটা অর্ধেক অর্ধেক ভাগ, দুজনকে প্রথম অর্ধেকে train করে দ্বিতীয়তে মাপা, তারপর উল্টো। দুটি পার্থক্য pi(1) আর pi(2), গড় p̄i, আর variance si² = (pi(1) − p̄i)² + (pi(2) − p̄i)². এটি ৫ বার, প্রতিবার নতুন এলোমেলো ভাগে। Statistic:

t̃ = p1(1) / √( (1/5) ∑i=1..5 si² ),   ৫ df-এর t-distribution

লবে শুধু প্রথম ভাগের প্রথম পার্থক্য, কারণ Dietterich-এর বিশ্লেষণে তখন লব আর হর প্রায় স্বাধীন থাকে, যা t-distribution-এর শর্ত। দুটি অর্ধেক training set-এ কোনো মিল নেই, আর ৫টি পুনরাবৃত্তি variance-এর অনুমান স্থির করে। দাম হলো প্রতিটি model শেখে মাত্র অর্ধেক ডেটায়, আর লবে একটিমাত্র সংখ্যা থাকায় power কম।

৫ · Null সত্য হলে কে কত ভুল করে — একটি ছোট simulation

দাবি যাচাইয়ের সৎ পথ হলো উত্তর-জানা জগৎ বানানো। নিচের ব্লকে দুটি feature x1 আর x2 সমান শক্তিশালী, আর label নির্ভর করে x1 + x2-এর ওপর। A শুধু x1 দেখে, B শুধু x2; গঠনগতভাবে দুজন হুবহু সমান ভালো, তাই null সত্য। ২০০টি নতুন ডেটাসেট (প্রতিটিতে ২০০ সারি) বানিয়ে চারটি test চালানো হয়, আর গোনা হয় কতবার p < ০.০৫ এসেছে। সৎ test-এর হার প্রায় ০.০৫ হওয়ার কথা; ২০০ বারে দৈবের কারণে ±০.০৩-এর মতো ওঠানামা স্বাভাবিক। Classifier হিসেবে খুব সরল একটি নিয়ম (দুই class-এর গড়ের মাঝে সীমা), যাতে হাজার হাজার fit ব্রাউজারে দ্রুত চলে।

import numpy as np
from scipy import stats

def fit_predict(xtr, ytr, xte):          # ছোট classifier: দুই class-এর গড়ের মাঝখানে সীমা
    m0, m1 = xtr[ytr == 0].mean(), xtr[ytr == 1].mean()
    return ((xte > (m0 + m1) / 2) == (m1 > m0)).astype(int)

def diff(X, y, te):                      # A দেখে শুধু x1, B শুধু x2: গঠনগতভাবে সমান ভালো
    tr = np.ones(len(y), bool); tr[te] = False
    return (np.mean(fit_predict(X[tr, 0], y[tr], X[te, 0]) == y[te])
            - np.mean(fit_predict(X[tr, 1], y[tr], X[te, 1]) == y[te]))

rng = np.random.default_rng(4)
n, reps, k = 200, 200, 10
names = ["naive t, 10-fold", "naive t, 10x10 CV", "corrected t, 10x10", "5x2cv t"]
rej = np.zeros(4)
for r in range(reps):                    # প্রতিবার নতুন ডেটাসেট, null সত্য
    X = rng.normal(size=(n, 2)); y = (X[:, 0] + X[:, 1] + rng.normal(0, 1.5, n) > 0).astype(int)
    d = np.array([[diff(X, y, f) for f in np.array_split(rng.permutation(n), k)]
                  for _ in range(10)])   # ১০ বার ১০-fold = ১০০টি পার্থক্য
    D, J = d.ravel(), d.size
    t1 = d[0].mean() / np.sqrt(d[0].var(ddof=1) / k)
    t2 = D.mean() / np.sqrt(D.var(ddof=1) / J)
    t3 = D.mean() / np.sqrt(D.var(ddof=1) * (1 / J + 1 / (k - 1)))   # Nadeau–Bengio
    p1s, s2 = [], []
    for i in range(5):                   # Dietterich-এর 5×2cv
        h = rng.permutation(n)[: n // 2]
        a, b = diff(X, y, h), diff(X, y, np.setdiff1d(np.arange(n), h))
        p1s.append(a); s2.append((a - b) ** 2 / 2)
    t4 = p1s[0] / np.sqrt(np.mean(s2))
    pv = [2 * stats.t.sf(abs(t), df) for t, df in ((t1, k - 1), (t2, J - 1), (t3, J - 1), (t4, 5))]
    rej += np.array(pv) < 0.05
print(f"{reps} datasets, true difference = 0, alpha = 0.05")
for nm, v in zip(names, rej / reps):
    print(f"  {nm:20s} rejects {v:.3f}")

আসল আউটপুট (ব্রাউজারের Python):

200 datasets, true difference = 0, alpha = 0.05
  naive t, 10-fold     rejects 0.045
  naive t, 10x10 CV    rejects 0.490
  corrected t, 10x10   rejects 0.025
  5x2cv t              rejects 0.045

সবচেয়ে বড় খবর দ্বিতীয় সারি: ১০ × ১০ repeated CV-র ১০০টি পার্থক্যে naive t-test চালালে, সত্যিকারের কোনো পার্থক্য না থাকা সত্ত্বেও ৪৯% ডেটাসেটে “significant” এসেছে। প্রতিশ্রুত ৫%-এর প্রায় দশ গুণ। Nadeau–Bengio সংশোধনে হার ০.০২৫, বরং একটু রক্ষণশীল (ভুল কম, তবে power-ও কিছুটা কম)। 5×2cv-এ ০.০৪৫, লক্ষ্যের কাছে। একক ১০-fold-এ naive t-ও এখানে ০.০৪৫, কারণ এই classifier খুব স্থির: training set সামান্য বদলালে তার সীমা প্রায় নড়ে না, তাই ρ ছোট। ২০০ বারের অনুমানে প্রতিটি হারের নিজস্ব অনিশ্চয়তা প্রায় ±০.০৩, তাই ০.০২৫ আর ০.০৪৫-এর পার্থক্যকে বেশি গুরুত্ব দেবেন না।

কিন্তু “একক ১০-fold-এ naive t ঠিক আছে” সিদ্ধান্তটি এই একটি স্থির classifier-এর। একই কোডে শুধু fit_predict-কে 1-nearest neighbour দিয়ে বদলানো হলো (return ytr[np.abs(xte[:, None] - xtr[None, :]).argmin(1)]), যা খুব অস্থির, কারণ প্রতিটি অনুমান একটি training সারির ওপর নির্ভর করে। ডেস্কটপে সত্যিকারের run (Python 3.14.4, NumPy 2.5.4, SciPy 1.18.1, একই seed, একটি run):

$ python null_sim_1nn.py
200 datasets, true difference = 0, alpha = 0.05
  naive t, 10-fold     rejects 0.115
  naive t, 10x10 CV    rejects 0.620
  corrected t, 10x10   rejects 0.110
  5x2cv t              rejects 0.125

অস্থির learner-এ একক ১০-fold-এর naive t ১১.৫%, repeated CV-র naive t ৬২%. আর লক্ষ করুন, এখানে সংশোধিত test আর 5×2cv-ও ১১–১৩%-এ উঠেছে। কারণটি গভীর: এখানে null হলো “অনেক ডেটাসেট জুড়ে গড়ে A আর B সমান”. কিন্তু একটি নির্দিষ্ট ২০০ সারির ডেটাসেটে, 1-NN-এর কাছে দৈবক্রমে x1 বা x2 একটু বেশি কাজের হতে পারে। একটি ডেটাসেটের ভেতরের কোনো resampling সেই ডেটাসেট-থেকে-ডেটাসেট ওঠানামা পুরো দেখতে পায় না, আর Bengio–Grandvalet-এর ফলাফল ঠিক এটিই বলে। শিক্ষা তিনটি: repeated CV-তে naive t কখনো নয়; corrected test বা 5×2cv ব্যবহার করুন, তবে এগুলোকে আনুমানিক ধরুন; আর সম্ভব হলে একাধিক স্বাধীন ডেটাসেট বা একটি বড় তালাবন্ধ test set জোগাড় করুন। (একটি simulation-এর সংখ্যা সাধারণ সত্য নয়; অন্য learner আর ডেটায় হার আলাদা হবে।)

৬ · অনেক ডেটাসেটে অনেক model — average rank আর Friedman test

বাজারঘর আটটি জেলায় আলাদা করে ফেরত-অনুমানের model রাখতে চায়, আর চারটি algorithm-এর মধ্যে বাছাই করতে চায়। প্রতিটি জেলার ডেটা আলাদা, কঠিনতাও আলাদা। প্রথম প্রলোভন: আট জেলার accuracy-র গড় নিয়ে তুলনা। Janez Demšar ২০০৬ সালে Journal of Machine Learning Research-এ (এই বিষয়ের বহুল উদ্ধৃত প্রবন্ধ) এর বিরুদ্ধে যুক্তি দেন: সহজ ডেটাসেটের ০.০১ আর কঠিনটির ০.০১ সমান অর্থ বহন করে না, আর একটি অদ্ভুত ডেটাসেট গড় টেনে নিতে পারে। তাঁর সুপারিশ: দুই algorithm-এর জন্য Wilcoxon signed-rank test, অনেকগুলোর জন্য Friedman test.

Friedman test (অর্থনীতিবিদ Milton Friedman, ১৯৩৭) প্রতিটি ডেটাসেটে k-টি algorithm-কে rank দেয় (১ = সেরা, সমান হলে গড় rank), তারপর প্রতিটি algorithm-এর average rank Rj নেয়। Null-এ সব algorithm সমান, তাই প্রত্যাশিত rank (k + 1)/2. N-টি ডেটাসেটে:

χ²F = [12N / (k(k + 1))] · [ ∑j Rj² − k(k + 1)²/4 ],   প্রায় χ²k−1

Null বাতিল হলে প্রশ্ন আসে, কোন জোড়া আলাদা? Demšar-এর প্রস্তাবিত post-hoc হলো Nemenyi test: দুটি algorithm-এর average rank-এর পার্থক্য critical difference CD = qα√(k(k + 1)/(6N))-এর বেশি হলে তারা আলাদা। qα আসে studentized range বণ্টন থেকে, √2 দিয়ে ভাগ করে; k = ৪-এ q0.05 ≈ ২.৫৬৯. এই CD-ই Demšar-এর পরিচিত “critical difference diagram”-এর ভিত্তি, যেখানে algorithm-গুলো average rank-এর রেখায় বসে আর CD-র মধ্যে থাকা দলগুলো একটি দাগে যুক্ত থাকে।

import numpy as np
import pandas as pd
from scipy import stats
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score, StratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB

models = {"logistic": LogisticRegression(),
          "tree": DecisionTreeClassifier(max_depth=4, random_state=0),
          "knn": KNeighborsClassifier(15, algorithm="kd_tree"),
          "nbayes": GaussianNB()}
rows = {}
for s in range(8):                       # ৮টি কাল্পনিক জেলা, প্রতিটিতে আলাদা ফেরত-ডেটা
    X, y = make_classification(n_samples=300, n_features=6, n_informative=3 + s % 3,
                               n_redundant=1, flip_y=0.05 * (1 + s % 2), random_state=s)
    cv = StratifiedKFold(5, shuffle=True, random_state=s)
    rows[f"district {s + 1}"] = {m: cross_val_score(est, X, y, cv=cv).mean()
                                 for m, est in models.items()}
acc = pd.DataFrame(rows).T.round(3)
ranks = acc.rank(axis=1, ascending=False)        # প্রতিটি সারিতে ১ = সেরা
print(acc.assign(best=acc.idxmax(axis=1)))
print("average rank:", ranks.mean().round(3).to_dict())
stat, p = stats.friedmanchisquare(*[acc[m] for m in acc.columns])
print(f"Friedman chi2 = {stat:.3f}, p = {p:.4f}")
k, N = acc.shape[1], acc.shape[0]
q = stats.studentized_range.ppf(0.95, k, 1e6) / np.sqrt(2)   # Nemenyi-র q_0.05
cd = q * np.sqrt(k * (k + 1) / (6 * N))
print(f"q_0.05 = {q:.3f}, critical difference CD = {cd:.3f}")

আসল আউটপুট (ব্রাউজারের Python):

            logistic   tree    knn  nbayes      best
district 1     0.697  0.847  0.870   0.760       knn
district 2     0.870  0.807  0.870   0.837  logistic
district 3     0.867  0.840  0.887   0.880       knn
district 4     0.843  0.800  0.843   0.830  logistic
district 5     0.823  0.873  0.907   0.823       knn
district 6     0.837  0.827  0.910   0.810       knn
district 7     0.867  0.833  0.893   0.827       knn
district 8     0.817  0.757  0.837   0.767       knn
average rank: {'logistic': 2.438, 'tree': 3.25, 'knn': 1.125, 'nbayes': 3.188}
Friedman chi2 = 14.610, p = 0.0022
q_0.05 = 2.569, critical difference CD = 1.658

k-NN আট জেলার ছয়টিতে একা সেরা, আর দুটিতে (জেলা ২ আর ৪) logistic-এর সঙ্গে সমান: সেখানে দুজনই rank ১.৫ পায় (idxmax সমান হলে প্রথম কলামটি দেখায়, তাই “logistic” লেখা)। তাই k-NN-এর average rank (৬ × ১ + ২ × ১.৫)/৮ = ১.১২৫. সূত্রে হাতে বসালে: ∑Rj² = ২.৪৩৮² + ৩.২৫² + ১.১২৫² + ৩.১৮৮² ≈ ২৭.৯৩, k(k + 1)²/4 = ২৫, তাই χ²F = (১২ × ৮/২০) × ২.৯৩ = ৪.৮ × ২.৯৩ ≈ ১৪.০৬. SciPy দিয়েছে ১৪.৬১, কারণ সমান rank থাকলে সে একটি tie-সংশোধন করে। দুটিতেই p অনেক ছোট (৩ df-এ), তাই “চারজন সমান” বাতিল। এবার CD = ১.৬৫৮: k-NN বনাম tree-র পার্থক্য ৩.২৫ − ১.১২৫ = ২.১২৫ আর বনাম naive Bayes ২.০৬৩, দুটিই CD-র বেশি, তাই আলাদা। কিন্তু k-NN বনাম logistic মাত্র ১.৩১৩, CD-র কম: আট জেলার ডেটায় এই দুজনকে আলাদা বলা যায় না, যদিও k-NN প্রায় সবখানে এগিয়ে।

সতর্কতা আর বিকল্প। Ronald Iman আর James Davenport ১৯৮০ সালে দেখান যে χ²F অনেক সময় বেশি রক্ষণশীল; তাঁদের FF = (N − 1)χ²F/(N(k − 1) − χ²F), (k − 1, (k − 1)(N − 1)) df-এ, Demšar-ও পছন্দ করেছিলেন। এখানে FF = ৭ × ১৪.০৬/(২৪ − ১৪.০৬) ≈ ৯.৯১. আর Alessio Benavoli, Giorgio Corani ও Francesca Mangili ২০১৬ সালে JMLR-এ দেখান যে mean-rank ভিত্তিক post-hoc test-এর একটি অদ্ভুত দিক আছে: A আর B আলাদা কি না, সেই সিদ্ধান্ত নির্ভর করতে পারে তুলনায় অন্য কোন algorithm-গুলো রাখা হয়েছে তার ওপর। তাঁদের পরামর্শ, জোড়ায় জোড়ায় Wilcoxon signed-rank (বা sign test) চালিয়ে Holm দিয়ে সংশোধন (অংশ ৭)। কোনটি “সঠিক” তা নিয়ে আলোচনা চলছে; রিপোর্টে পদ্ধতিটি স্পষ্ট লিখে দিন।

৭ · একাধিক তুলনা — FWER, FDR, Bonferroni, Holm আর BH

অংশ ৬-এর ছয়টি জোড়া, বা ২০টি জেলায় নতুন বনাম পুরোনো model: প্রতিটিতে ৫%-এ test চালালে, null সব জায়গায় সত্য হলেও অন্তত একটি মিথ্যা আবিষ্কারের সম্ভাবনা দ্রুত বাড়ে। m-টি স্বাধীন test-এ তা ১ − ০.৯৫m; m = ২০-এ প্রায় ০.৬৪. পর্ব ৩৭-এ এটি simulation-এ দেখেছেন, আর পর্ব ০৪-এ “garden of forking paths” হিসেবে। এখানে প্রতিকারগুলো নিখুঁতভাবে। দুটি আলাদা লক্ষ্য আছে:

FWER — একটিও মিথ্যা নয়

Family-wise error rate = P(অন্তত একটি মিথ্যা আবিষ্কার). লক্ষ্য একে ≤ α রাখা। যেখানে একটি ভুল দাবিই ক্ষতিকর (একটি model “নিরাপদ” বলা, নিয়ন্ত্রিত ক্ষেত্রের সিদ্ধান্ত), সেখানে এটি।

FDR — আবিষ্কারের মধ্যে মিথ্যার অনুপাত

False discovery rate = E[V/R], V = মিথ্যা আবিষ্কার, R = মোট আবিষ্কার (R = ০ হলে ০ ধরা হয়)। লক্ষ্য একে ≤ q রাখা। অনেক প্রার্থী থেকে পরের ধাপের জন্য বাছাই করতে (feature screening, কোন জেলায় আরও পরীক্ষা) এটি যুক্তিসঙ্গত।

Bonferroni: প্রতিটি test-কে α/m-এ চালানো। যুক্তি পর্ব ০৩-এর union bound: P(কোনো একটি মিথ্যা) ≤ ∑ P(প্রতিটি মিথ্যা) ≤ m · α/m = α. কোনো স্বাধীনতার শর্ত লাগে না, তবে m বড় হলে খুব কড়া। Holm (Sture Holm, ১৯৭৯, Scandinavian Journal of Statistics): p-value-গুলো ছোট থেকে বড় সাজিয়ে p(1) ≤ … ≤ p(m); i-তম-কে তুলনা করা α/(m − i + 1)-এর সঙ্গে, প্রথম যেখানে ব্যর্থ সেখানে থামা, আর তার আগের সবগুলো বাতিল। এটিও যেকোনো নির্ভরশীলতায় FWER ≤ α রাখে, আর সবসময় Bonferroni-র সমান বা বেশি আবিষ্কার করে; তাই Bonferroni-র বদলে Holm না নেওয়ার কারণ প্রায় নেই। Benjamini–Hochberg (Yoav Benjamini আর Yosef Hochberg, ১৯৯৫): সবচেয়ে বড় i খোঁজা যেখানে p(i) ≤ i·q/m, আর ১ থেকে i পর্যন্ত সব বাতিল। স্বাধীন (বা এক ধরনের ধনাত্মক নির্ভরশীল) test-এ FDR ≤ (m0/m)·q, যেখানে m0 হলো সত্য null-এর সংখ্যা। যেকোনো নির্ভরশীলতার জন্য Benjamini আর Daniel Yekutieli ২০০১ সালে একটি রক্ষণশীল রূপ দেন।

p = 0.030, 0.001, 0.200, 0.014, 0.012m = 5

            
  1. সাজানো। পাঁচটি জেলার p-value ছোট থেকে বড় সাজানো হলো। তুলনার জন্য Bonferroni: সব p-কে একই সীমা ০.০৫/৫ = ০.০১-এর সঙ্গে মেলালে শুধু ০.০০১ পার হয়।
  2. ধাপ ১. সবচেয়ে ছোট p-কে সবচেয়ে কড়া সীমা α/৫-এর সঙ্গে মেলানো: ০.০০১ ≤ ০.০১, বাতিল। এই ধাপটি Bonferroni-র সঙ্গে হুবহু এক।
  3. ধাপ ২. একটি null বাতিল হয়েছে, বাকি চারটির জন্য সীমা α/৪ = ০.০১২৫. ০.০১২ সামান্য নিচে, বাতিল। Bonferroni-র ০.০১ সীমায় এটি টিকত না: Holm-এর বাড়তি power এখান থেকেই।
  4. ধাপ ৩. সীমা α/৩ ≈ ০.০১৬৭; ০.০১৪ নিচে, বাতিল।
  5. ধাপ ৪. সীমা α/২ = ০.০২৫; ০.০৩০ ওপরে। এখানেই থামতে হয়: “step-down” মানে প্রথম ব্যর্থতার পর বাকি সব, এমনকি পরে কোনোটি নিজের সীমার নিচে থাকলেও, বাতিল নয়। Holm দিয়েছে ৩টি আবিষ্কার।
  6. Adjusted p. একই সিদ্ধান্ত adjusted p-value দিয়ে: (m − i + 1)·p(i), তারপর আগেরগুলোর সর্বোচ্চ নিয়ে একঘেয়ে করা (০.০৪২ থেকে ০.০৪৮)। যেগুলো ≤ ০.০৫, সেগুলো বাতিল: প্রথম তিনটি। statsmodels-এর multipletests ঠিক এই সংখ্যা দেয়।
  7. BH-এর সঙ্গে। BH নিচ থেকে নয়, ওপর থেকে খোঁজে (step-up): বড়তম i যেখানে p(i) ≤ i·q/m. i = ৪-এ ০.০৩০ ≤ ০.০৪, তাই প্রথম চারটি বাতিল। একই পাঁচটি p থেকে Bonferroni ১, Holm ৩, BH ৪: লক্ষ্য যত নরম, আবিষ্কার তত বেশি।

৮ · ২০টি p-value আর জানা উত্তর — কে কত মিথ্যা আবিষ্কার করে

বাজারঘর ২০টি জেলায় নতুন সুপারিশ-model আর পুরোনোটি পাশাপাশি চালিয়েছে; প্রতিটি জেলায় ৪০টি জোড়া পার্থক্য (ধরুন একই দিনে দুই model-এর ঝুড়ির মূল্যের পার্থক্য, standardize করা)। Simulation-এ আমরা জানি: শুধু প্রথম ৫টি জেলায় আসল উন্নতি আছে (গড় ০.৬ SD), বাকি ১৫টিতে কিছুই নেই। প্রতিটি জেলায় paired t-test, তারপর চারটি নীতি। প্রথমে একটি পরীক্ষা খুঁটিয়ে, তারপর ২,০০০ বার পুনরাবৃত্তি করে দীর্ঘমেয়াদি হার। Holm আর BH নিজে vectorize করে লেখা, কারণ multipletests একবারে একটি সারি নেয় আর হাজার বার ডাকলে ব্রাউজারে ধীর; প্রথম অংশে statsmodels-এর সঙ্গে মিলিয়ে নেওয়া হয়েছে।

import numpy as np
from scipy import stats
from statsmodels.stats.multitest import multipletests

m, a = 20, 0.05                          # ২০টি জেলায় নতুন বনাম পুরোনো model; শুধু প্রথম ৫টিতে আসল উন্নতি
true = np.zeros(m, bool); true[:5] = True
def pvalues(rng, R, n=40):               # প্রতিটি জেলায় ৪০টি জোড়া পার্থক্য → paired t-test
    d = rng.normal(0.6 * true[:, None], 1.0, size=(R, m, n))
    return stats.ttest_1samp(d, 0.0, axis=2).pvalue           # আকার (R, m)

def decide(P, meth):                     # P-এর প্রতিটি সারি একটি পুরো পরীক্ষা
    if meth == "none": return P <= a
    if meth == "bonferroni": return P <= a / m
    i = np.arange(1, m + 1); ps = np.sort(P, axis=1)
    ok = ps <= (a / (m - i + 1) if meth == "holm" else a * i / m)
    k = ok.cumprod(1).sum(1) if meth == "holm" else np.where(ok, i, 0).max(1)
    return P.argsort(1).argsort(1) < k[:, None]              # সবচেয়ে ছোট k-টি বাতিল

methods = ["none", "bonferroni", "holm", "fdr_bh"]
P1 = pvalues(np.random.default_rng(22), 1)
print("smallest 7 p:", " ".join(f"{v:.4f}" for v in np.sort(P1[0])[:7]))
for meth in methods:
    rej = decide(P1, meth)[0]
    same = meth == "none" or (rej == multipletests(P1[0], a, method=meth)[0]).all()
    print(f"{meth:10s} found {rej.sum()}, false {(rej & ~true).sum()}, statsmodels agrees: {same}")

P = pvalues(np.random.default_rng(0), 2000)          # ২০০০ বার পুরো পরীক্ষা
print("2000 repeats:  P(any false)  mean FDP  power")
for meth in methods:
    rej = decide(P, meth); V = (rej & ~true).sum(1)
    fdp = V / np.maximum(rej.sum(1), 1)
    print(f"  {meth:10s} {np.mean(V > 0):9.3f} {fdp.mean():9.3f} {rej[:, true].mean():6.3f}")

আসল আউটপুট (ব্রাউজারের Python):

smallest 7 p: 0.0000 0.0001 0.0001 0.0037 0.0045 0.0443 0.0714
none       found 6, false 1, statsmodels agrees: True
bonferroni found 3, false 0, statsmodels agrees: True
holm       found 3, false 0, statsmodels agrees: True
fdr_bh     found 5, false 0, statsmodels agrees: True
2000 repeats:  P(any false)  mean FDP  power
  none           0.542     0.120  0.959
  bonferroni     0.039     0.009  0.707
  holm           0.048     0.011  0.728
  fdr_bh         0.190     0.038  0.868

একটি পরীক্ষা: সংশোধন ছাড়া ৬টি আবিষ্কার, যার একটি মিথ্যা (p = ০.০৪৪৩, একটি শূন্য-প্রভাবের জেলা)। Bonferroni-র সীমা ০.০৫/২০ = ০.০০২৫, তাই শুধু প্রথম তিনটি (০.০০০০ মানে ০.০০০০৫-এর কম)। Holm-এ চতুর্থ ধাপের সীমা ০.০৫/১৭ ≈ ০.০০২৯৪, আর p(4) = ০.০০৩৭ তার ওপরে, তাই এখানেও ৩টি। BH-এ p(5) = ০.০০৪৫ ≤ ৫ × ০.০৫/২০ = ০.০১২৫, আর p(6) = ০.০৪৪৩ > ০.০১৫, তাই ৫টি, পাঁচটিই আসল। চারটি নীতিতেই নিজের লেখা কোড আর statsmodels একই সিদ্ধান্ত দিয়েছে। ২,০০০ বারে: সংশোধন ছাড়া ৫৪% পরীক্ষায় অন্তত একটি মিথ্যা আবিষ্কার, আর আবিষ্কারের গড়ে ১২% মিথ্যা। Bonferroni (০.০৩৯) আর Holm (০.০৪৮) FWER ৫%-এর নিচে রেখেছে; Holm-এর power একটু বেশি (০.৭২৮ বনাম ০.৭০৭)। BH-এর FWER ১৯%, কিন্তু সে সেটির প্রতিশ্রুতি দেয়নি; তার গড় FDP ০.০৩৮, যা তত্ত্বের (m0/m)·q = (১৫/২০) × ০.০৫ = ০.০৩৭৫-এর সঙ্গে প্রায় হুবহু মেলে, আর power ০.৮৬৮, Holm-এর চেয়ে অনেক বেশি।

ML-এ লুকানো বহু তুলনাও আছে: ২০০টি config-এর সেরাটিকে একই validation set-এ baseline-এর সঙ্গে তুলনা, ১৫টি metric-এর যেটিতে উন্নতি সেটিই রিপোর্ট, বা একই test set বারবার দেখা। সংখ্যা জানা থাকলে সংশোধন করুন; তার চেয়েও নির্ভরযোগ্য হলো বাছাই আর মূল্যায়ন আলাদা ডেটায় রাখা, যেমন তালাবন্ধ test set বা nested CV.

৯ · Statistical বনাম practical significance, Bayesian দৃষ্টি আর কোন test কখন

p < ০.০৫ মানে শুধু “শূন্য পার্থক্যের সঙ্গে ডেটা বেমানান”. ১০ লাখ test সারিতে ০.০২ শতাংশ বিন্দুর পার্থক্যও significant হবে, অথচ তা নতুন model চালানোর খরচ, latency বা রক্ষণাবেক্ষণের দাম পোষায় না। উল্টো দিকে ২০০ সারিতে ৪ শতাংশ বিন্দুর আসল উন্নতি p > ০.০৫ দিতে পারে, কারণ power কম। American Statistical Association ২০১৬ সালে p-value নিয়ে বিবৃতিতে (Wasserstein আর Lazar) ঠিক এটিই জোর দিয়ে বলে: p-value প্রভাবের আকার বা গুরুত্ব মাপে না। তাই রিপোর্টে সবসময় effect size আর তার interval দিন, আর আগে থেকে ঠিক করুন কত বড় পার্থক্য ব্যবসার কাছে অর্থপূর্ণ।

ব্যবহারিক সীমার ধারণাটি Bayesian তুলনার কেন্দ্রে। Benavoli, Corani, Demšar আর Zaffalon ২০১৭ সালে JMLR-এ “Time for a change” শিরোনামের একটি টিউটোরিয়ালে প্রস্তাব করেন: একটি ROPE (region of practical equivalence) ঠিক করুন, যেমন accuracy-র পার্থক্য ±০.০১-এর মধ্যে হলে “কার্যত সমান”. তারপর পার্থক্যের posterior থেকে তিনটি সম্ভাবনা বের করুন: P(A ভালো), P(কার্যত সমান), P(B ভালো). উত্তর তখন “p = ০.০৩” নয়, বরং “৮৫% সম্ভাবনায় A অন্তত ১ শতাংশ বিন্দু ভালো”, যা সিদ্ধান্তের ভাষার কাছাকাছি। CV-র correlation সামলাতে Corani আর Benavoli ২০১৫ সালে একটি Bayesian correlated t-test দেন, যেখানে Nadeau–Bengio-র ρ = ntest/n একই ভূমিকা নেয়।

কোন পরিস্থিতিতে কোন test — এক নজরে

Choosing a comparison test: what you have decides what you can claim

Which statistical test to use for comparing models ১ · একটি test set, দুটি trained model → McNemar (b, c) b + c কম হলে exact binomial ২ · এক ডেটাসেট, দুটি algorithm → 5×2cv t বা corrected CV t repeated CV-তে naive t কখনো নয় ৩ · দুটি algorithm, অনেক ডেটাসেট → Wilcoxon signed-rank প্রতিটি ডেটাসেট একটি জোড়া ৪ · অনেক algorithm, অনেক ডেটাসেট → Friedman, তারপর post-hoc Nemenyi CD, বা Holm-সহ Wilcoxon ৫ · অনেক test একসঙ্গে → Holm (FWER) বা BH (FDR) Bonferroni-র বদলে Holm সবশেষে: effect size + interval আর আগে ঠিক করা ব্যবহারিক সীমা
ছবি ৯.১ — ওপরের সারিগুলোতে যত নিচে নামবেন, দাবি তত সাধারণ (“এই দুটি model” থেকে “এই ধরনের algorithm”), আর তত বেশি এলোমেলোতার উৎস গুনতে হয়। কোনো পরিস্থিতিতেই p-value একা সিদ্ধান্ত নয়।

আরও গভীরে: Dietterich-এর ১৯৯৮ সালের প্রবন্ধ (“Approximate statistical tests for comparing supervised classification learning algorithms”) পাঁচটি test-এর Type I error simulation-এ মেপেছিল, আর এই পর্বের অংশ ৫ তারই একটি ছোট সংস্করণ। Nadeau আর Bengio (২০০৩) CV-র variance-এর উৎস বিশ্লেষণ করেন; Bengio আর Grandvalet (২০০৪, JMLR) দেখান সাধারণ unbiased অনুমান অসম্ভব। Ethem Alpaydın ১৯৯৯ সালে দশটি পার্থক্যই ব্যবহার করা combined 5×2cv F test দেন। Salvador García আর Francisco Herrera ২০০৮ সালে JMLR-এ Demšar-এর কাজ বাড়িয়ে Holm, Shaffer ও Bergmann–Hommel-এর মতো post-hoc পদ্ধতি তুলনা করেন।

পরীক্ষা ও ইন্টারভিউতে:

  • McNemar test-এ কোন ঘরগুলো লাগে, কেন? শুধু মতভেদের b আর c; accuracy-র পার্থক্য (b − c)/n, a আর d কেটে যায়। χ² = (|b − c| − 1)²/(b + c), ১ df.
  • k-fold-এর পার্থক্যে naive paired t-test কেন আশাবাদী? Training set-গুলো বড় অংশে এক, তাই পার্থক্যগুলো correlated; Var(d̄)-এর ρσ² অংশ বাদ পড়ে। সংশোধন: (1/J + ntest/ntrain).
  • 5×2cv-এর df কত, লবে কী? ৫ df; লবে প্রথম পুনরাবৃত্তির প্রথম fold-এর পার্থক্য।
  • অনেক ডেটাসেটে গড় accuracy কেন নয়? ডেটাসেটগুলোর মাপ তুলনীয় নয়, outlier ডেটাসেট গড় টানে; প্রতিটিতে rank নিয়ে Friedman.
  • Holm আর BH-এর পার্থক্য? Holm step-down, FWER রক্ষা করে; BH step-up, FDR রক্ষা করে আর সাধারণত বেশি আবিষ্কার দেয়।

১০ · AI-এর যুগে — “significant উন্নতি” দাবি যাচাই

AI assistant-এর দেওয়া তুলনার কোড প্রায় সবসময় চলে। বিপদ হলো ভুল test-ও একটি p-value দেয়, যা দেখতে সঠিকটির মতোই। পরিচিত ভুলগুলো:

AI প্রায়ই যা করেকেন ভুলকীভাবে ধরবেন
Repeated CV-র ১০০টি fold-score-এ ttest_rel চালায়Fold correlated; Type I error বহুগুণ (অংশ ৫-এ ৪৯%)Corrected t বা 5×2cv; ছোট simulation-এ null-এর হার মাপুন
একই test set-এ দুটি accuracy-কে স্বাধীন অনুপাত ধরে z-test করেজোড়া তথ্য ফেলে দেয়; ভুল varianceContingency table বানিয়ে McNemar
Training-set accuracy বা একটি split-এর সংখ্যা দিয়ে “significant” বলেOverfitting আর একটি ভাগের ভাগ্যতালাবন্ধ test set, বা কয়েকটি seed আর fold
২০টি জোড়া তুলনা করে সংশোধন ছাড়া p < ০.০৫-গুলো রিপোর্ট করেমিথ্যা আবিষ্কার প্রায় নিশ্চিতHolm বা BH; কতগুলো test হয়েছে লিখুন
পুরোনো বা বানানো API দেয় (যেমন অস্তিত্বহীন scipy.stats.mcnemar)SciPy-তে McNemar নেই; আছে statsmodels-এনিজের version-এর docs খুলে নাম আর argument মিলান
“p = ০.০০১, তাই বড় উন্নতি” লেখেp প্রভাবের আকার নয়পার্থক্য আর interval, আগে ঠিক করা ব্যবহারিক সীমার সঙ্গে

AI-কে শুধু “test দাও” নয়, প্রশ্ন, অনুমান আর যাচাই চাইতে বলুন:

আমার কাছে দুটি classifier আছে (logistic regression আর gradient boosting), ৩,০০০ সারির একটি ডেটায়। ১. প্রথমে জিজ্ঞেস করো আমি কোন প্রশ্নের উত্তর চাই: এই দুটি trained model-এর তুলনা, নাকি এই ডেটা-আকারে algorithm দুটির তুলনা। প্রশ্ন অনুযায়ী McNemar, 5×2cv বা corrected repeated-CV t-test বেছে নাও আর কারণ বলো। ২. McNemar হলে contingency table ছাপো, statsmodels-এর mcnemar দিয়ে exact আর χ² দুটি p দাও, আর পার্থক্যের ৯৫% interval দাও। ৩. CV হলে প্রতিটি fold-এর পার্থক্য ছাপো, আর naive t কেন চলবে না তা এক লাইনে লেখো। ৪. সব seed নির্দিষ্ট রাখো; test set আলাদা রাখো, তাতে কোনো tuning কোরো না; কোনো warning চাপা দিও না। ৫. যে function বা argument ব্যবহার করছ, সেগুলো আমার statsmodels আর SciPy version-এ আছে কি না কীভাবে যাচাই করব বলো। ৬. শেষে লেখো কোন দাবিগুলো এই ফল থেকে করা যায় না।

AI-এর দেওয়া তুলনার ফল হাতে পেলে — যাচাইয়ের চেকলিস্ট

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

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

প্র ০১নতুন model-এর উন্নতি “statistically significant”. এটুকু দেখেই কি deploy করা উচিত?

না, কারণ significance আর গুরুত্ব আলাদা প্রশ্নের উত্তর। p-value বলে, শূন্য পার্থক্য সত্য হলে এত বড় পার্থক্য দেখা কতটা অস্বাভাবিক। এটি নির্ভর করে পার্থক্যের আকার আর নমুনার আকার দুটির ওপর। বাজারঘরের মতো একটি দোকানে যদি ২০ লাখ লগ সারিতে তুলনা হয়, তবে ০.০৫ শতাংশ বিন্দুর পার্থক্যও p = ০.০০১ দিতে পারে। অথচ নতুন model হয়তো তিন গুণ ধীর, বেশি মেমরি খায়, বা রক্ষণাবেক্ষণে কঠিন।

পরিসংখ্যানবিদেরা এই ভুল নিয়ে বহুদিন ধরে সতর্ক করছেন। Jacob Cohen মনোবিজ্ঞানে effect size-এর ওপর জোর দেন, আর American Statistical Association ২০১৬ সালে p-value নিয়ে তাদের প্রথম আনুষ্ঠানিক বিবৃতিতে বলে যে p-value প্রভাবের আকার বা ফলের গুরুত্ব মাপে না, আর শুধু একটি সীমা পার হওয়া দিয়ে বৈজ্ঞানিক বা ব্যবসায়িক সিদ্ধান্ত নেওয়া উচিত নয়। ২০১৯ সালে The American Statistician-এর একটি বিশেষ সংখ্যায় কেউ কেউ “statistically significant” শব্দটিই বাদ দেওয়ার প্রস্তাব করেন; এ নিয়ে পরিসংখ্যানবিদদের মধ্যে মতভেদ আছে।

ML-এ সিদ্ধান্তের কাঠামো সাধারণত এমন: (১) আগে থেকে একটি ব্যবহারিক সীমা ঠিক করা, যেমন “ফেরত-অনুমানে recall অন্তত ২ শতাংশ বিন্দু না বাড়লে বদল নয়”; (২) পার্থক্যের interval বের করা; (৩) interval-এর পুরোটা সীমার ওপরে হলে বদল, পুরোটা নিচে হলে না, আর মাঝামাঝি হলে আরও ডেটা। এর সঙ্গে আসে খরচের দিক: latency, ব্যাখ্যাযোগ্যতা, fairness, আর অফলাইন metric-এর উন্নতি আসলে ব্যবসায়িক ফলে অনুবাদ হয় কি না, যার জন্য A/B test লাগে (পর্ব ৬২ আর ৬৩)।

উল্টো ভুলও আছে: “p > ০.০৫, তাই দুজন সমান”. ছোট test set-এ power কম; সমতা দাবি করতে হলে interval সরু হতে হবে আর পুরোটা ব্যবহারিক সীমার ভেতরে থাকতে হবে, যা equivalence testing বা Bayesian ROPE-এর ধারণা।

মূল উপলব্ধি: significance শুধু বলে পার্থক্যটি সম্ভবত শূন্য নয়; deploy-এর সিদ্ধান্ত নেয় পার্থক্যের আকার, তার অনিশ্চয়তা আর খরচ মিলিয়ে।

প্র ০২Dietterich ১৯৯৮ সালেই repeated CV-তে naive t-test-এর বিপদ দেখিয়েছিলেন। তবু ML গবেষণায় তুলনার পরিসংখ্যান এত দুর্বল কেন?

কারণ কয়েকটি স্তরে। প্রথম, সংস্কৃতি: ML-এর বড় অংশ benchmark-কেন্দ্রিক, যেখানে একটি টেবিলে সবচেয়ে বড় সংখ্যাটি bold করাই প্রথা। Demšar ২০০৬ সালে কয়েক বছরের ICML প্রবন্ধ ঘেঁটে দেখান, অনেক প্রবন্ধ অনেক ডেটাসেটে তুলনা করলেও পরিসংখ্যানিক test ব্যবহার করত কম, আর যারা করত তাদের অনেকে জোড়া t-test-এর মতো অনুপযুক্ত পদ্ধতি নিত। তাঁর প্রবন্ধটি এরপর খুব বেশি উদ্ধৃত হয়, আর Friedman-Nemenyi-র CD diagram অনেক প্রবন্ধে দেখা যায়, তবু অভ্যাস পুরো বদলায়নি।

দ্বিতীয়, খরচ: বড় neural network একবার train করতেই অনেক টাকা আর সময় লাগে। ৫ × ২ বা ১০ × ১০ বার চালানো প্রায়ই অসম্ভব, তাই অনেকে একটি seed-এর একটি run রিপোর্ট করেন। ২০১০-এর দশকের শেষে কয়েকটি গবেষণা দেখায় যে শুধু random seed বদলালেই reinforcement learning বা NLP-র কিছু benchmark-এ ফলের ওঠানামা প্রকাশিত “উন্নতি”-র সমান বা বেশি হতে পারে (যেমন Henderson ও সহকর্মীদের ২০১৮ সালের deep RL-এর পুনরুৎপাদনযোগ্যতা নিয়ে কাজ)। তৃতীয়, প্রণোদনা: সম্মেলনে গ্রহণযোগ্যতা অনেকটা “state of the art” দাবির ওপর নির্ভর করত, যা বহু তুলনা থেকে সবচেয়ে ভালোটি বাছার উৎসাহ দেয়, অংশ ৭-এর ঠিক সেই ফাঁদ।

কিছু অগ্রগতিও হয়েছে। NeurIPS-এর মতো সম্মেলন ২০১৯-এর দিকে reproducibility checklist চালু করে, যেখানে error bar আর তার সংজ্ঞা জানাতে বলা হয়। Leaderboard-এ hidden test set আর জমা দেওয়ার সীমা বহু তুলনার সমস্যা কিছুটা কমায়। তবে পুরো সমাধান হয়নি।

আপনার নিজের কাজে মূল কথা হলো অনুপাত: যে পার্থক্য দাবি করছেন, সেটি seed-ভেদে ওঠানামার তুলনায় কত বড়? পর্ব ০৪-এর seed-variance মাপ আর এই পর্বের test একসঙ্গে সেটি দেখায়।

মূল উপলব্ধি: পদ্ধতি বহু আগেই জানা; দুর্বলতা আসে খরচ, প্রথা আর প্রণোদনা থেকে, তাই ভালো তুলনা একটি অভ্যাসের প্রশ্ন।

প্র ০৩Model তুলনায় Bayesian পদ্ধতি কি frequentist test-এর চেয়ে ভালো? বিতর্কটি কোথায়?

Benavoli, Corani, Demšar আর Zaffalon তাঁদের ২০১৭ সালের JMLR টিউটোরিয়ালে frequentist null hypothesis test-এর কয়েকটি সমস্যা তুলে ধরেন। প্রথম, null hypothesis “দুজন হুবহু সমান” প্রায় কখনো আক্ষরিক অর্থে সত্য নয়; যথেষ্ট ডেটা থাকলে যেকোনো ক্ষুদ্র পার্থক্যও significant হয়। দ্বিতীয়, p-value আমাদের আসল প্রশ্নের উত্তর দেয় না: আমরা জানতে চাই “A ভালো হওয়ার সম্ভাবনা কত”, কিন্তু p-value হলো “null সত্য হলে এই ডেটার সম্ভাবনা”. তৃতীয়, null বাতিল না হলে কিছুই বলা যায় না, সমতার প্রমাণও নয়।

তাঁদের বিকল্প: পার্থক্যের একটি posterior বণ্টন, আর ROPE. দুই classifier একটি ডেটাসেটে CV দিয়ে তুলনার জন্য Bayesian correlated t-test (Corani আর Benavoli, ২০১৫), যা Nadeau–Bengio-র correlation ধারণা নিয়ে কাজ করে; অনেক ডেটাসেটের জন্য Bayesian sign-rank test বা hierarchical model. ফল তিনটি সম্ভাবনা, যা সরাসরি সিদ্ধান্তে কাজে লাগে: যেমন “P(কার্যত সমান) = ০.৯২, তাই সরলটি রাখুন”.

সমালোচনাও আছে। ROPE-এর প্রস্থ কে ঠিক করবে? ০.০১ না ০.০২, সেই পছন্দ ফল বদলায়, আর পছন্দটি বিষয়ভিত্তিক। Prior-এর প্রভাব ছোট নমুনায় উল্লেখযোগ্য হতে পারে। Correlated t-test-এ ρ-এর মান নিজেই একটি আনুমানিক অনুমান, তাই অংশ ৫-এর 1-NN উদাহরণের মতো ক্ষেত্রে Bayesian পদ্ধতিও ভুল দিকে যেতে পারে। অনেক frequentist পরিসংখ্যানবিদ বলেন, interval আর equivalence test দিয়েই ROPE-এর মতো সিদ্ধান্ত নেওয়া যায় (দুটি one-sided test বা TOST).

ব্যবহারিক দৃষ্টিতে দুই পক্ষের মিল অনেক বেশি: দুজনই চায় প্রভাবের আকার আর তার অনিশ্চয়তা রিপোর্ট হোক, দুজনই CV-র correlation সামলাতে চায়, আর দুজনই একটি ব্যবহারিক সীমার কথা বলে। পার্থক্য মূলত ভাষায় আর দর্শনে। ছোট দলের কাজে যেকোনো একটি পথ সৎভাবে আর আগে থেকে ঠিক করে নেওয়াই বড় কথা।

মূল উপলব্ধি: Bayesian পদ্ধতি সিদ্ধান্তের ভাষায় উত্তর দেয়, কিন্তু ROPE আর prior-এর পছন্দ লুকানো নয়, প্রকাশ্য অনুমান; আসল লাভ আসে ব্যবহারিক সীমা আর অনিশ্চয়তা রিপোর্ট করার অভ্যাস থেকে।

প্র ০৪অনেক ডেটাসেটে average rank আর CD diagram জনপ্রিয়। এর দুর্বলতা কী, আর কখন অন্য পথ নেবেন?

Average rank-এর বড় সুবিধা হলো এটি ডেটাসেটের মাপের পার্থক্য উপেক্ষা করে: ০.৯৯ বনাম ০.৯৮ আর ০.৬১ বনাম ০.৫২ দুটিতেই শুধু “কে আগে” গোনা হয়। Friedman test কোনো বণ্টনের অনুমান নেয় না, আর outlier ডেটাসেটে টলে না। Demšar ২০০৬ সালে এগুলোর জন্যই একে সুপারিশ করেন।

কিন্তু সুবিধাটিই দুর্বলতা। প্রথম, rank প্রভাবের আকার হারায়: ০.০০১-এর জয় আর ০.১-এর জয় একই। অংশ ৬-এর run-এ k-NN জেলা ৫-এ logistic-এর চেয়ে ০.০৮৪ এগিয়ে, আর জেলা ৩-এ মাত্র ০.০২০, কিন্তু rank-এ দুটিই সমান অবদান। দ্বিতীয়, Benavoli, Corani আর Mangili (২০১৬) দেখান যে mean-rank post-hoc-এ A বনাম B-এর সিদ্ধান্ত নির্ভর করে তুলনায় অন্য কারা আছে তার ওপর: একটি দুর্বল নতুন algorithm যোগ করলে A আর B-এর rank-এর ব্যবধান বদলাতে পারে, যদিও A আর B-এর নিজেদের ফল একটুও বদলায়নি। এটি যুক্তিগতভাবে অস্বস্তিকর। তৃতীয়, Nemenyi খুব রক্ষণশীল; N ছোট হলে প্রায় কিছুই আলাদা হয় না, যেমন আমাদের run-এ k-NN আর logistic.

চতুর্থ, “ডেটাসেট একটি নমুনা” অনুমানটি নিজেই প্রশ্নসাপেক্ষ। UCI বা OpenML থেকে বাছা ২০টি ডেটাসেট কোন জনসংখ্যার এলোমেলো নমুনা? বাস্তবে সেগুলো প্রায়ই ছোট, পরিষ্কার আর পুরোনো; সেখানে জেতা মানে আপনার কোম্পানির ডেটায় জেতা নয়। বাজারঘরের আট জেলার উদাহরণে এটি অনেক বেশি যুক্তিসঙ্গত, কারণ জেলাগুলো সত্যিই আগ্রহের জনসংখ্যা।

বিকল্প পথ: শুধু দুটি algorithm হলে Wilcoxon signed-rank, যা পার্থক্যের আকারের rank-ও ব্যবহার করে। অনেকগুলো হলে জোড়ায় জোড়ায় Wilcoxon আর Holm. প্রভাবের আকার জরুরি হলে প্রতিটি ডেটাসেটের পার্থক্য আর interval একটি forest plot-এ দেখানো, বা hierarchical Bayesian model. আর একটি নির্দিষ্ট কাজের জন্য model বাছতে হলে অনেক ডেটাসেটের rank-এর চেয়ে নিজের ডেটায় সৎ CV বেশি মূল্যবান।

মূল উপলব্ধি: average rank মাপের পার্থক্য থেকে রক্ষা করে কিন্তু প্রভাবের আকার হারায় আর অন্য প্রার্থীদের ওপর নির্ভর করে; প্রশ্ন অনুযায়ী জোড়া test আর প্রভাবের ছবি পাশাপাশি দিন।

প্র ০৫FWER না FDR — কখন কোনটি রক্ষা করবেন? Hyperparameter search বা feature screening-এ এর অর্থ কী?

Bonferroni-র ধারণা পুরোনো (Carlo Emilio Bonferroni-র নামে, যদিও আধুনিক প্রয়োগ পরে জনপ্রিয় হয়), আর Holm ১৯৭৯ সালে এর একটি সবসময়-ভালো রূপ দেন। দুটিই এমন জগতের জন্য, যেখানে একটি মিথ্যা দাবিই ব্যয়বহুল: ওষুধের পরীক্ষা, নিয়ন্ত্রিত ক্ষেত্রে model অনুমোদন, বা “এই model প্রতিটি জেলায় পুরোনোটির চেয়ে খারাপ নয়” ধরনের নিরাপত্তা দাবি।

১৯৯০-এর দশকে পরিস্থিতি বদলায়। Microarray-এর মতো প্রযুক্তি একসঙ্গে হাজার হাজার জিন মাপে; FWER রক্ষা করতে গেলে প্রায় কোনো আবিষ্কারই টেকে না। Benjamini আর Hochberg ১৯৯৫ সালে প্রশ্নটি বদলে দেন: “একটিও ভুল নয়” না চেয়ে “আবিষ্কারের তালিকায় ভুলের অনুপাত গড়ে ৫%-এর কম” চাওয়া। এটি অনুসন্ধানমূলক কাজের জন্য স্বাভাবিক, কারণ তালিকার প্রার্থীদের পরে আলাদা পরীক্ষায় যাচাই করা হবে। অংশ ৮-এর simulation-এ BH-এর power ০.৮৬৮, Holm-এর ০.৭২৮; দাম হলো কোনো একটি পরীক্ষায় একটি মিথ্যা আবিষ্কার থাকার সম্ভাবনা ১৯%.

ML-এ তাই নিয়মটি মোটামুটি এমন। Feature screening, কোন জেলা বা segment-এ আরও খোঁজ নেবেন, কোন hyperparameter অঞ্চল সম্ভাবনাময়: FDR. চূড়ান্ত দাবি, যা কেউ যাচাই না করে বিশ্বাস করবে (“নতুন model সব জেলায় ভালো”): FWER, আর আদর্শভাবে নতুন ডেটায় নিশ্চিতকরণ। আর hyperparameter search? সেখানে সাধারণত p-value-ই থাকে না; বহু তুলনার সমস্যা আসে “সবচেয়ে ভালো validation score”-এর ফোলানো থেকে (selection bias). প্রতিকার সংশোধন নয়, আলাদা ডেটা: nested CV বা তালাবন্ধ test set.

একটি গভীর সমস্যা হলো adaptive analysis: একই holdout বারবার দেখে পরের প্রশ্ন ঠিক করলে test-এর সংখ্যাই অজানা হয়ে যায়। Cynthia Dwork ও সহকর্মীরা ২০১৫ সালে Science-এ “reusable holdout” নামে differential privacy-ভিত্তিক একটি পদ্ধতি প্রস্তাব করেন, যা holdout-এর উত্তর ইচ্ছা করে একটু noisy করে এই ক্ষয় কমায়। Kaggle-এর মতো প্রতিযোগিতার public leaderboard-এ overfit হওয়া এরই বাস্তব রূপ।

মূল উপলব্ধি: চূড়ান্ত, যাচাই-ছাড়া দাবিতে FWER (Holm), অনুসন্ধানের তালিকায় FDR (BH); আর যেখানে test গোনা যায় না, সেখানে আলাদা তালাবন্ধ ডেটাই একমাত্র নির্ভরযোগ্য রক্ষা।

অনুশীলন

হিসাবগুলো খাতায় করুন, তারপর উত্তর মেলান। চাইলে অংশ ৩, ৬ আর ৮-এর ব্লক বদলে যাচাই করুন।

  1. পূর্ণ numerical: (ক) ৪০০টি test অর্ডারে b = ১৮ (শুধু A ঠিক), c = ৭ (শুধু B ঠিক). Continuity correction-সহ McNemar χ² আর p বের করুন (১ df-এ χ² = ৩.৮৪১-এর p = ০.০৫), আর accuracy-র পার্থক্য কত? (খ) তিনটি model চারটি ডেটাসেটে accuracy: D1: A ০.৮১, B ০.৭৯, C ০.৭৫; D2: A ০.৭২, B ০.৭৪, C ০.৭০; D3: A ০.৮৮, B ০.৮৫, C ০.৮৬; D4: A ০.৬৫, B ০.৬৩, C ০.৬০. Average rank আর Friedman χ²F বের করুন।

    (ক) χ² = (|১৮ − ৭| − ১)²/(১৮ + ৭) = ১০০/২৫ = ৪.০, যা ৩.৮৪১-এর একটু ওপরে, তাই p একটু কম ০.০৫-এর: SciPy-তে chi2.sf(4, 1) = ০.০৪৫৫. Exact binomial-এ p = ০.০৪৩৩. পার্থক্য (১৮ − ৭)/৪০০ = ০.০২৭৫, অর্থাৎ ২.৭৫ শতাংশ বিন্দু; সীমানার কাছের ফল, তাই interval-সহ রিপোর্ট জরুরি। (খ) Rank (১ = সেরা): D1: A১, B২, C৩; D2: B১, A২, C৩; D3: A১, C২, B৩; D4: A১, B২, C৩. Average rank: A = (১ + ২ + ১ + ১)/৪ = ১.২৫, B = (২ + ১ + ৩ + ২)/৪ = ২.০, C = (৩ + ৩ + ২ + ৩)/৪ = ২.৭৫. χ²F = [১২ × ৪/(৩ × ৪)] × [১.২৫² + ২² + ২.৭৫² − ৩ × ১৬/৪] = ৪ × (১.৫৬২৫ + ৪ + ৭.৫৬২৫ − ১২) = ৪ × ১.১২৫ = ৪.৫. ২ df-এ p = e−৪.৫/২ ≈ ০.১০৫; চারটি ডেটাসেটে “তিনজন সমান” বাতিল করা যায় না, যদিও A তিনটিতে সেরা।

  2. সমালোচনা ও নকশা: একজন বিশ্লেষক (বা একটি AI assistant) লিখেছেন: “১২টি model-এর প্রতিটিকে baseline-এর সঙ্গে ১০ × ১০ repeated CV-তে তুলনা করেছি। ১০০টি fold-পার্থক্যে ttest_rel চালিয়ে ৫টিতে p < ০.০৫ পেয়েছি; সবচেয়ে কম p-এর model-টিই সেরা, তার test accuracy ০.৯১২, তাই এটি deploy করব।” Test accuracy মাপা হয়েছে সেই একই test set-এ, যা দেখে আগে কয়েকবার feature বদলানো হয়েছিল। কী কী সমস্যা, আর সঠিক নকশা কী?

    সমস্যা: (১) ১০০টি correlated fold-পার্থক্যে naive t-test: Type I error বহুগুণ বেশি (simulation-এ প্রায় ৫০%). (২) ১২টি তুলনা, কোনো সংশোধন নেই; null সব জায়গায় সত্য হলেও কয়েকটি “significant” আসা প্রত্যাশিত। (৩) সবচেয়ে ছোট p মানে সবচেয়ে বড় উন্নতি নয়; p প্রভাবের আকার মাপে না। (৪) Test set বারবার দেখা হয়েছে, তাই ০.৯১২ আশাবাদী (selection bias). (৫) কোনো effect size, interval বা ব্যবহারিক সীমা নেই। সঠিক নকশা: শুরুতেই একটি test set তালাবন্ধ; train অংশে প্রতিটি model-এর ১০ × ১০ CV, পার্থক্যে Nadeau–Bengio-সংশোধিত t (বা 5×2cv); ১২টি p-তে Holm (চূড়ান্ত দাবি) বা BH (পরের ধাপের তালিকা); টিকে যাওয়াদের মধ্যে পার্থক্যের আকার, interval আর খরচ মিলিয়ে একটি বাছাই; তারপর তালাবন্ধ test set-এ শুধু সেই একটির (আর baseline-এর) McNemar আর পার্থক্যের interval; রিপোর্টে কতগুলো model আর config চেষ্টা হয়েছে লেখা।

  3. আউটপুট অনুমান করুন: চালানোর আগে লিখে ফেলুন নিচের কোড কী ছাপবে।
    from statsmodels.stats.multitest import multipletests
    p = [0.004, 0.018, 0.027, 0.036, 0.045]
    for meth in ("holm", "fdr_bh"):
        reject, p_adj, _, _ = multipletests(p, alpha=0.05, method=meth)
        print(meth, reject.sum(), p_adj.round(3))
    holm 1 [0.02  0.072 0.081 0.081 0.081]
    fdr_bh 5 [0.02  0.045 0.045 0.045 0.045]

    Holm: ০.০০৪ ≤ ০.০৫/৫ = ০.০১, বাতিল; ০.০১৮ > ০.০৫/৪ = ০.০১২৫, থামুন: ১টি। Adjusted p = (m − i + 1)·p(i): ০.০২, ০.০৭২, ০.০৮১, ০.০৭২, ০.০৪৫; তারপর একঘেয়ে করতে আগেরগুলোর সর্বোচ্চ নেওয়া হয়, তাই শেষ তিনটি ০.০৮১. BH: সীমা i × ০.০১ = ০.০১, ০.০২, ০.০৩, ০.০৪, ০.০৫; সবচেয়ে বড় p ০.০৪৫ ≤ ০.০৫, তাই পাঁচটিই বাতিল! Adjusted p = m·p(i)/i: ০.০২, ০.০৪৫, ০.০৪৫, ০.০৪৫, ০.০৪৫ (পেছন থেকে সর্বনিম্ন নিয়ে)। শিক্ষা: সব p একসঙ্গে মাঝারি ছোট হলে BH “সবই সত্য” ধরে নেয়, Holm মাত্র একটিকে; দুটি আলাদা প্রশ্নের উত্তর দেয়। NumPy দশমিকের শেষ শূন্য ছাপে না বলে “0.02 ” দেখায়।

  4. 5×2cv হাতে: দুটি algorithm-এর error-এর পার্থক্য পাঁচটি ২-fold পুনরাবৃত্তিতে (p(1), p(2)): (০.০৪, ০.০২), (০.০৩, ০.০১), (০.০৫, ০.০১), (০.০২, ০.০৪), (০.০৩, ০.০৩). 5×2cv t̃ বের করুন। ৫ df-এ দুই দিকের ৫%-এর critical মান ২.৫৭১. সিদ্ধান্ত কী, আর একই দশটি সংখ্যায় naive t নিলে কী ঝুঁকি?

    প্রতিটি পুনরাবৃত্তিতে দুটি সংখ্যার si² = (p(1) − p(2))²/2 (দুটি বিচ্যুতির বর্গের যোগ, যা এর সমান): (০.০২)²/২ = ০.০০০২; ০.০০০২; (০.০৪)²/২ = ০.০০০৮; ০.০০০২; ০. গড় = ০.০০১৪/৫ = ০.০০০২৮. হর = √০.০০০২৮ ≈ ০.০১৬৭. লব p1(1) = ০.০৪. t̃ = ০.০৪/০.০১৬৭ ≈ ২.৩৯, যা ২.৫৭১-এর কম: ৫%-এ পার্থক্যের প্রমাণ নেই (p প্রায় ০.০৬)। দশটি পার্থক্যের গড় ০.০২৮, আর সেগুলোকে স্বাধীন ধরে naive t নিলে SE = sd/√১০ ≈ ০.০১৩২/৩.১৬ ≈ ০.০০৪২, t প্রায় ৬.৭: “অত্যন্ত significant”. কিন্তু এক পুনরাবৃত্তির দুই অর্ধেক একই ডেটা ভাগ করে নেয়, আর পাঁচ পুনরাবৃত্তিও একই ডেটাসেট থেকে; সংখ্যাগুলো স্বাধীন নয়, তাই naive t অংশ ৫-এর মতোই আশাবাদী।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকই test set-এ দুটি classifier তুলনার ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. প্রশ্ন, metric আর ব্যবহারিক সীমা আগে লিখে রাখা, আর test set তালাবন্ধ করা
  2. দুটি model শুধু training অংশে train আর tune করা
  3. একই test সারিতে দুজনের অনুমান নেওয়া
  4. প্রতিটি সারির ঘর গুনে 2×2 টেবিল বানানো (a, b, c, d)
  5. b আর c থেকে exact বা χ² McNemar p-value বের করা
  6. পার্থক্য (b − c)/n আর তার interval ব্যবহারিক সীমার সঙ্গে মিলিয়ে রিপোর্ট করা

একই test set-এ দুটি classifier: দুজনই ঠিক ৪১০টি, শুধু A ঠিক ৩০টি, শুধু B ঠিক ১৪টি, দুজনই ভুল ৪৬টি। Continuity correction-সহ McNemar χ² কত?

  • ৫.৮২
  • ৫.১১
  • ০.৩৪
  • ০.৩৪১

১০ বার ১০-fold CV চালিয়ে দুই algorithm-এর ১০০টি fold-পার্থক্য পাওয়া গেল। এগুলোতে সাধারণ paired t-test (৯৯ df) চালানোর মূল সমস্যা কী?

  • পার্থক্যগুলো normal নয়, তাই t-test অচল
  • ১০০টি সংখ্যা অনেক বেশি, তাই test-এর power কমে যায়
  • পার্থক্যগুলো correlated, তাই SE অনেক ছোট দেখায় আর মিথ্যা “significant” বেশি আসে
  • জোড়া না নিয়ে দুটি আলাদা দল হিসেবে t-test করা উচিত

চারটি p-value: ০.০০৪, ০.০১১, ০.০২০, ০.০৪০. α = ০.০৫-এ Holm-এর পদ্ধতি কয়টি null বাতিল করে?

  • ১টি
  • ২টি
  • ৩টি
  • ৪টি

Benjamini–Hochberg পদ্ধতি q = ০.০৫-এ কী রক্ষা করে?

  • আবিষ্কারগুলোর মধ্যে মিথ্যার প্রত্যাশিত অনুপাত (FDR) ০.০৫-এর নিচে
  • অন্তত একটি মিথ্যা আবিষ্কারের সম্ভাবনা ০.০৫-এর নিচে
  • প্রতিটি আবিষ্কার ৯৫% সম্ভাবনায় সত্য
  • সত্য প্রভাবের ৯৫% ধরা পড়বে

চারটি algorithm আটটি ডেটাসেটে তুলনা করা হলো। Average rank: P = ১.১২৫, Q = ২.৪৩৮, R = ৩.১৮৮, S = ৩.২৫০; Nemenyi-র CD = ১.৬৫৮. কোন জোড়াটি ৫%-এ আলাদা বলা যায় না?

  • P আর S
  • P আর R
  • P আর Q
  • কোনোটিই নয়, সব জোড়া আলাদা

২০ লাখ test সারিতে নতুন model-এর accuracy পুরোনোটির চেয়ে ০.০৫ শতাংশ বিন্দু বেশি, McNemar p = ০.০০২. সবচেয়ে যুক্তিসঙ্গত সিদ্ধান্ত কোনটি?

  • p < ০.০৫, তাই নতুন model অবশ্যই deploy করা উচিত
  • পার্থক্য সম্ভবত আসল, কিন্তু ব্যবহারিক সীমা আর খরচের সঙ্গে মিলিয়ে সিদ্ধান্ত নিতে হবে
  • p এত ছোট মানে কোথাও ভুল হয়েছে, ফলটি বাতিল
  • বড় test set-এ McNemar প্রযোজ্য নয়

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. প্রশ্ন আগে: নির্দিষ্ট দুটি model (শুধু test set-এর এলোমেলোতা), algorithm (training set-ও), নাকি অনেক ডেটাসেট; প্রশ্নই test ঠিক করে।
  2. McNemar: শুধু মতভেদের b আর c; χ² = (|b − c| − 1)²/(b + c), ছোট b + c-তে exact binomial(b + c, ½); পার্থক্য (b − c)/n আর তার interval.
  3. CV-র পার্থক্য: training set overlap-এর জন্য correlated; repeated CV-তে naive t কখনো নয়। Corrected: s²(1/J + ntest/ntrain); 5×2cv: ৫ df. দুটিই আনুমানিক।
  4. অনেক ডেটাসেট: প্রতিটিতে rank, Friedman χ²F, তারপর CD = qα√(k(k + 1)/(6N)) বা Holm-সহ জোড়া Wilcoxon.
  5. অনেক test: Holm (step-down, FWER) Bonferroni-র চেয়ে সবসময় সমান বা ভালো; BH (step-up, FDR) অনুসন্ধানে বেশি power. আর significance ≠ গুরুত্ব: effect size, interval আর ব্যবহারিক সীমা।

পরের পর্বে: মডিউল ৪ এখানে শেষ। পর্ব ২৩ (Linear model গভীরে — basis function, interaction আর regularization path) দিয়ে নতুন মডিউল শুরু: linear model দিয়ে বাঁকা সম্পর্ক ধরা, interaction পড়া, আর পুরো regularization path থেকে model বাছাই, যেখানে এই পর্বের তুলনার নিয়মগুলোই কাজে লাগবে।

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

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান