Foundationপ্রথম নীতি থেকে
LEVEL 13লেসন ২১/২৩কঠিন৫৫ মিনিট

Benchmarking ও Statistical Analysis

Benchmarking and Statistical Analysis

advanced-architecture module-এর benchmarking লেসন CPU-microbenchmark-এর engineering সমাধান দিয়েছিল — এই লেসন সেই একই সংখ্যাগুলোর পেছনের পরিসংখ্যান ব্যাখ্যা করে, সাধারণভাবে: confidence interval, p-value-এর প্রকৃত অর্থ, আর bootstrap resampling — যেকোনো research claim-এ প্রযোজ্য, শুধু CPU benchmark-এ না।

এই লেসন শেষে আপনি পারবেন

  • Latency-জাতীয় ডেটায় mean কেন প্রায়ই বিভ্রান্তিকর তা distribution-এর skewness দিয়ে ব্যাখ্যা করতে পারবেন
  • Variance ও standard deviation থেকে হাতে confidence interval হিসাব করতে পারবেন
  • p-value-এর সঠিক সংজ্ঞা বলতে পারবেন এবং সবচেয়ে সাধারণ ভুল ব্যাখ্যা চিনতে পারবেন
  • Bootstrap resampling দিয়ে distribution-নিরপেক্ষভাবে confidence interval হিসাব করতে পারবেন এবং কোড লিখতে পারবেন

আগে যা বোঝা থাকা দরকার

আগে এটা বুঝি

advanced-architecture/benchmarking-methodology লেসনে আমরা দেখেছিলাম দুইটা algorithm-এর mean latency (10.2ms বনাম 10.4ms) তুলনা করার সময় confidence interval overlap করলে “A দ্রুত” দাবি করা বিপজ্জনক। সেই লেসনটা মূলত engineering-কেন্দ্রিক ছিল — warm-up, dead-code elimination, NUMA pinning, CPU governor — কীভাবে একটা পরিষ্কার সংখ্যা পাওয়া যায় তার উপর।

এই লেসন একটা ধাপ পেছনে গিয়ে জিজ্ঞাসা করে: সেই সংখ্যাটা রিপোর্ট করার পরও, সিদ্ধান্তটা আসলে কতটা নির্ভরযোগ্য? এটা শুধু CPU microbenchmark-এর প্রশ্ন না — database throughput তুলনা, দুইটা ML model-এর accuracy তুলনা, নেটওয়ার্ক protocol-এর latency তুলনা — যেকোনো জায়গায় “A বনাম B, কোনটা ভালো” প্রশ্নের পেছনে ঠিক এই একই পরিসংখ্যান লাগে। আর এখানেই সবচেয়ে বেশি সৎ গবেষকও ভুল করেন — p-value-এর অর্থ ভুল বোঝা প্রায় সর্বজনীন।

মূল ধারণা

Mean, Median, Percentile — কখন কোনটা বলে সত্যি কথা

benchmarking-methodology লেসনের সেই CPU-নির্দিষ্ট উদাহরণটা মনে করুন — outlier-এর কারণে mean বিভ্রান্তিকর হয়ে যাওয়া। এখানে একটা ভিন্ন, বেশি সাধারণ প্রেক্ষাপটে দেখি: কেন latency-জাতীয় ডেটা প্রায় সবসময়ই এই সমস্যায় ভোগে, শুধু কাকতালীয়ভাবে না।

একটা distributed system-এর ১০০টা request-এর response time (মিলিসেকেন্ডে), sorted:

৯৫টা request:  ১৮-২৫ ms-এর মধ্যে (স্বাভাবিক processing)
৩টা request:   ৮০-১১০ ms (GC pause / retry)
২টা request:   ৪৫০-৬০০ ms (network timeout + retry)

এই distribution right-skewed — একটা লম্বা লেজ ডানদিকে। এটা কাকতালীয় না; latency-জাতীয় ডেটা প্রায় সবসময়ই এভাবে skewed হয়, কারণ ব্যর্থতার কারণগুলো (queueing, retry, GC pause, network hiccup) সবসময় সময় যোগ করে, কখনো বিয়োগ করে না — একটা request -500ms সময় নিতে পারে না, কিন্তু +500ms নিতে পারে।

mean≈42.1 msmedian=21 msp99≈580 ms\text{mean} \approx 42.1\text{ ms} \qquad \text{median} = 21\text{ ms} \qquad p_{99} \approx 580\text{ ms}

Mean (42.1ms) কাউকেই প্রতিনিধিত্ব করে না — ৯৫% user-এর অভিজ্ঞতা (~২০ms)-এর চেয়ে দ্বিগুণেরও বেশি, অথচ সবচেয়ে খারাপ অভিজ্ঞতা (৬০০ms)-এর চেয়ে অনেক কম। এটা একটা কাল্পনিক সংখ্যা যা কারো বাস্তব অভিজ্ঞতা না।

Median (21ms) সংখ্যাগরিষ্ঠ user-এর অভিজ্ঞতা সঠিকভাবে ধরে — কিন্তু সেই ৫% user-কে সম্পূর্ণ আড়াল করে দেয় যারা ভয়াবহ অভিজ্ঞতা পাচ্ছেন।

p99 (~580ms) সেই লুকানো ৫%-এর গল্প বলে — এটাই advanced-architecture/benchmarking-methodology লেসনের “Tail at Scale” আলোচনার ঠিক সেই ধারণা, শুধু এখানে সাধারণ research-context-এ প্রয়োগ করা হচ্ছে।

Variance ও Standard Deviation — “কতটা ছড়ানো” মাপা

Mean/median শুধু “কেন্দ্র” বলে — distribution কতটা ছড়ানো তা বলে না। এটা মাপে variance:

Var(X)=1n∑i=1n(xi−xˉ)2s=Var(X)\text{Var}(X) = \frac{1}{n}\sum_{i=1}^n (x_i - \bar{x})^2 \qquad s = \sqrt{\text{Var}(X)}

(s = sample standard deviation — variance-এর বর্গমূল, কারণ variance-এর একক মূল ডেটার বর্গ, যা সরাসরি বোঝা কঠিন; s একই এককে ফিরিয়ে আনে)

দুইটা algorithm একই mean দিতে পারে, সম্পূর্ণ ভিন্ন s নিয়ে:

AlgorithmMeansব্যাখ্যা
A10.0 ms0.3 msপ্রায় সবসময় 9.7-10.3ms-এর মধ্যে — predictable
B10.0 ms4.2 msমাঝে মাঝে 2ms, মাঝে মাঝে 18ms — অস্থির

দুইটার “গড়” identical, কিন্তু একটা production system-এ B ব্যবহার করা অনেক বেশি ঝুঁকিপূর্ণ — latency SLA guarantee দেওয়া প্রায় অসম্ভব। শুধু mean তুলনা করলে এই পার্থক্যটা সম্পূর্ণ অদৃশ্য থেকে যায়।

Confidence Interval — একটা সম্পূর্ণ সাংখ্যিক উদাহরণ

দুইটা ML model-এর accuracy তুলনা করছি, 10-fold cross-validation-এ (প্রতিটা fold একটা independent measurement):

Model A accuracy (১০ fold):  [0.842, 0.851, 0.839, 0.847, 0.855,
                               0.838, 0.849, 0.844, 0.846, 0.841]
Model B accuracy (১০ fold):  [0.858, 0.849, 0.862, 0.855, 0.847,
                               0.860, 0.851, 0.856, 0.853, 0.859]

Model A: mean = 0.8452, s = 0.0057

Model B: mean = 0.8550, s = 0.0048

Standard error (SE) — mean-এর নিজস্ব uncertainty, sample size দিয়ে সংকুচিত:

SE=snSE = \frac{s}{\sqrt{n}}

SEA=0.005710=0.0018SEB=0.004810=0.0015SE_A = \frac{0.0057}{\sqrt{10}} = 0.0018 \qquad SE_B = \frac{0.0048}{\sqrt{10}} = 0.0015

95% confidence interval (normal approximation, 1.96 × SE):

CIA=0.8452±1.96(0.0018)=[0.8417, 0.8487]CI_A = 0.8452 \pm 1.96(0.0018) = [0.8417,\ 0.8487] CIB=0.8550±1.96(0.0015)=[0.8521, 0.8579]CI_B = 0.8550 \pm 1.96(0.0015) = [0.8521,\ 0.8579]

দুইটা interval overlap করে না (0.8487 < 0.8521) — এই ডেটায় Model B-র accuracy পরিসংখ্যানগতভাবে তাৎপর্যপূর্ণভাবে বেশি বলা যায়।

ভেতরে কী ঘটছে

P-value — সবচেয়ে ভুল-বোঝা সংখ্যা বিজ্ঞানে

সঠিক সংজ্ঞা: ধরে নিন null hypothesis সত্যি (অর্থাৎ, ধরে নিন Model A আর Model B-র মধ্যে কোনো real পার্থক্য নেই — উভয়ের সত্যিকার accuracy সমান, observed পার্থক্যটা নিছক sampling noise)। এই ধারণার অধীনে, এত বড়, বা এর চেয়ে বেশি চরম পার্থক্য observe করার সম্ভাবনা কত — এটাই p-value।

p=P(এত চরম বা তার চেয়ে বেশি চরম data∣H0 সত্যি)p = P(\text{এত চরম বা তার চেয়ে বেশি চরম data} \mid H_0 \text{ সত্যি})

p < 0.05 মানে: “যদি সত্যিই কোনো পার্থক্য না থাকত, তাহলে নিছক কাকতালীয়ভাবে এই মাপের (বা তার চেয়ে বড়) পার্থক্য দেখার সম্ভাবনা 5%-এর কম হতো।” এতটাই কম যে, প্রচলিতভাবে আমরা H₀ (কোনো পার্থক্য নেই) প্রত্যাখ্যান করি।

যে ভুলগুলো সবাই করে

“p < 0.05 মানে 'এই effect আসল হওয়ার সম্ভাবনা 95%' অথবা 'null hypothesis সত্যি হওয়ার সম্ভাবনা মাত্র 5%'।”

এটা p-value-এর সবচেয়ে সাধারণ, সবচেয়ে বিপজ্জনক ভুল ব্যাখ্যা — এমনকি অভিজ্ঞ গবেষকরাও প্রায়ই এই ভুল করেন। American Statistical Association 2016 সালে একটা আনুষ্ঠানিক বিবৃতি প্রকাশ করে এই ভুল ব্যাখ্যার বিরুদ্ধে সতর্ক করতে বাধ্য হয়েছিল।

সমস্যাটা কোথায়: p-value হিসাব হয় ধরে নিয়ে H₀ সত্যি (P(data | H₀))। কিন্তু “effect আসল হওয়ার সম্ভাবনা” প্রশ্ন করছে উল্টো দিকের কিছু (P(H₀ | data)) — আর এই দুইটা জিনিস সাধারণত সমান না (Bayes’ theorem-এর মৌলিক শিক্ষা, mathematics/probability লেসনে দেখা)।

একটা সংখ্যাগত উদাহরণ দিয়ে বোঝা যাক — একটা medical test-এর সাদৃশ্যে: ধরুন একটা রোগ জনসংখ্যার মাত্র 1%-এর আছে (এটাই এখানে “null hypothesis সত্যি হওয়ার prior সম্ভাবনা” — বেশিরভাগ hypothesis-ই প্রথমে ভুল হয়, একটা এলোমেলোভাবে বাছা exploratory research-এ)। একটা test-এর false positive rate = 5% (ঠিক p < 0.05 থ্রেশহোল্ডের সমতুল্য), আর true positive rate = 80%।

10,000 জনের মধ্যে: 100 জন সত্যিই আক্রান্ত (80 জন positive ধরা পড়বে), 9,900 জন সুস্থ (5% অর্থাৎ 495 জন ভুলভাবে positive ধরা পড়বে)। মোট positive result: 80 + 495 = 575, তার মধ্যে সত্যিকার আক্রান্ত মাত্র 80।

P(সত্যিই আক্রান্ত∣positive result)=80575≈14%P(\text{সত্যিই আক্রান্ত} \mid \text{positive result}) = \frac{80}{575} \approx 14\%

5% false positive rate সত্ত্বেও, একটা positive result সত্যি হওয়ার সম্ভাবনা মাত্র 14% — কারণ base rate (রোগের প্রকৃত প্রাদুর্ভাব) কম। ঠিক একইভাবে, একটা p < 0.05 ফলাফল “effect সত্যি হওয়ার ৯৫% সম্ভাবনা” বোঝায় না — সেটা নির্ভর করে effect-টা আগে থেকে কতটা সম্ভাব্য ছিল (prior), যা p-value নিজে হিসাবেই ধরে না।

সঠিক ভাষা: “যদি সত্যিই কোনো পার্থক্য না থাকত, এই ডেটা দেখার সম্ভাবনা 5%-এর কম” — p-value শুধু এইটুকুই বলে, তার বেশি কিছু না।

মূল ধারণা

Bootstrap Resampling — distribution ধরে না নিয়েও CI বের করা

উপরের normal-approximation CI (mean ± 1.96 × SE) একটা assumption করে — ডেটা প্রায় normal distribution অনুসরণ করে। কিন্তু আমরা এই লেসনেই দেখেছি latency-জাতীয় ডেটা skewed, normal না। Median বা p99-এর মতো রাশির জন্য তো কোনো সহজ closed-form CI সূত্রই নেই।

Bootstrap এই সমস্যা সমাধান করে সম্পূর্ণ ভিন্নভাবে — assumption ছাড়াই, শুধু computation দিয়ে:

Bootstrap resampling algorithm — ধাপে ধাপে
  1. আসল samplen টা observed measurement, যেমন ১০০টা latency
  2. Resampleএকই n আকারের একটা নতুন sample বানান — আসল sample থেকে replacement-সহ randomly বেছে (একই মান একাধিকবার আসতে পারে)
  3. Statistic হিসাব করুনএই resample-এর উপর যে statistic চান (median, mean, p99) তা হিসাব করুন
  4. পুনরাবৃত্তি করুনধাপ ২-৩, কয়েক হাজার বার (যেমন B=10,000)
  5. CI বের করুনসেই কয়েক হাজার statistic-এর 2.5th ও 97.5th percentile-ই 95% CI

কেন এটা কাজ করে (স্বজ্ঞাত ব্যাখ্যা): আসল sample-টাই সত্যিকার population সম্পর্কে আমাদের সেরা তথ্য। বারবার সেই sample থেকে replacement-সহ নতুন sample বানিয়ে, আমরা কার্যকরভাবে অনুকরণ করছি “যদি আমরা আবার আসল population থেকে নতুন sample নিতাম, তাহলে statistic-টা কতটা বদলাতে পারত” — কোনো normal distribution বা অন্য কোনো গাণিতিক সূত্রের উপর নির্ভর না করেই।

নিজে চালিয়ে দেখুন

EXPERIMENT

Bootstrap দিয়ে Median-এর Confidence Interval — একটা কার্যকর, চালানোর-মতো উদাহরণ

Python 3· ২০ মিনিট
import random
import statistics

random.seed(7)


def make_skewed_latencies(n=200):
    """বাস্তবসম্মত right-skewed latency ডেটা — বেশিরভাগ দ্রুত, কিছু ধীর।"""
    data = []
    for _ in range(n):
        if random.random() < 0.95:
            data.append(random.gauss(20, 3))       # স্বাভাবিক request
        else:
            data.append(random.gauss(300, 80))     # tail — GC/retry
    return [max(1.0, x) for x in data]


def bootstrap_ci(data, statistic_fn, num_resamples=10000, ci=0.95):
    n = len(data)
    boot_stats = []
    for _ in range(num_resamples):
        resample = [data[random.randrange(n)] for _ in range(n)]
        boot_stats.append(statistic_fn(resample))
    boot_stats.sort()
    lower_idx = int((1 - ci) / 2 * num_resamples)
    upper_idx = int((1 + ci) / 2 * num_resamples)
    return boot_stats[lower_idx], boot_stats[upper_idx]


latencies = make_skewed_latencies()

median_val = statistics.median(latencies)
mean_val = statistics.fmean(latencies)

median_ci = bootstrap_ci(latencies, statistics.median)
mean_ci = bootstrap_ci(latencies, statistics.fmean)


def p95(sample):
    s = sorted(sample)
    return s[int(len(s) * 0.95)]


p95_val = p95(latencies)
p95_ci = bootstrap_ci(latencies, p95)

print(f"Median : {median_val:6.2f} ms   95% bootstrap CI = [{median_ci[0]:.2f}, {median_ci[1]:.2f}]")
print(f"Mean   : {mean_val:6.2f} ms   95% bootstrap CI = [{mean_ci[0]:.2f}, {mean_ci[1]:.2f}]")
print(f"p95    : {p95_val:6.2f} ms   95% bootstrap CI = [{p95_ci[0]:.2f}, {p95_ci[1]:.2f}]")

Illustrative output:

Median :  20.31 ms   95% bootstrap CI = [19.71, 20.94]
Mean   :  33.87 ms   95% bootstrap CI = [26.42, 43.19]
p95    :  61.44 ms   95% bootstrap CI = [24.86, 189.32]

তিনটা পর্যবেক্ষণ:

১. Median-এর CI সংকীর্ণ — কারণ median একটা robust statistic, কিছু চরম outlier দিয়ে খুব বেশি প্রভাবিত হয় না, তাই resample-জুড়ে স্থিতিশীল থাকে।

২. Mean-এর CI অনেক চওড়া (26.42 থেকে 43.19) — কারণ mean সরাসরি outlier-এর দ্বারা প্রভাবিত, resample-এ কখনো বেশি tail-value পড়ে যায় কখনো কম, ফলে mean resample-জুড়ে অনেক বেশি ওঠানামা করে। এটাই সংখ্যায় দেখা যায় mean কেন এই ধরনের ডেটায় কম নির্ভরযোগ্য।

৩. p95-এর CI সবচেয়ে চওড়া (24.86 থেকে 189.32) — tail percentile সবচেয়ে কম data point দিয়ে নির্ধারিত হয় (মাত্র ~5% data), তাই সবচেয়ে বেশি uncertain। এটা একটা গুরুত্বপূর্ণ, প্রায়ই উপেক্ষিত ব্যবহারিক শিক্ষা: p99 claim করতে p50 claim-এর চেয়ে অনেক বেশি sample লাগে, নির্ভরযোগ্য CI পেতে।

এটা কী প্রমাণ করে

Bootstrap resampling normal-distribution assumption ছাড়াই median-এর মতো একটা রাশির জন্য CI দেয় — এমনকি skewed distribution-এও নির্ভরযোগ্যভাবে কাজ করে, যেখানে classic SE-ভিত্তিক CI ভুল হতে পারে।

নিজে বানান

BUILD IT

Bootstrap দিয়ে দুইটা System তুলনা করা

Python · ●●●○○
  1. দুইটা ডেটাসেটের bootstrap CI হিসাব করুন (উপরের function পুনর্ব্যবহার করে)
  2. দুইটা CI overlap করে কি না স্বয়ংক্রিয়ভাবে যাচাই করুন
  3. সেই সাথে একটা "bootstrap difference" পদ্ধতি প্রয়োগ করুন — সরাসরি পার্থক্যের CI
  4. দুইটা পদ্ধতির সিদ্ধান্ত মিলছে কি না তুলনা করুন

শুধু দুইটা আলাদা CI-এর overlap দেখার চেয়ে একটা পরিসংখ্যানগতভাবে শক্তিশালী উপায় — সরাসরি পার্থক্যের bootstrap distribution বানানো:

import random
import statistics

random.seed(3)


def bootstrap_diff_ci(data_a, data_b, statistic_fn, num_resamples=10000, ci=0.95):
    """A - B পার্থক্যের bootstrap CI — সরাসরি, overlap-check-এর চেয়ে নির্ভুল।"""
    n_a, n_b = len(data_a), len(data_b)
    diffs = []
    for _ in range(num_resamples):
        resample_a = [data_a[random.randrange(n_a)] for _ in range(n_a)]
        resample_b = [data_b[random.randrange(n_b)] for _ in range(n_b)]
        diffs.append(statistic_fn(resample_a) - statistic_fn(resample_b))
    diffs.sort()
    lower_idx = int((1 - ci) / 2 * num_resamples)
    upper_idx = int((1 + ci) / 2 * num_resamples)
    return diffs[lower_idx], diffs[upper_idx]


# দুইটা algorithm-এর latency sample (illustrative)
algo_a = [random.gauss(22, 4) for _ in range(80)]
algo_b = [random.gauss(19, 4) for _ in range(80)]

diff_lo, diff_hi = bootstrap_diff_ci(algo_a, algo_b, statistics.median)

print(f"A-এর median: {statistics.median(algo_a):.2f} ms")
print(f"B-এর median: {statistics.median(algo_b):.2f} ms")
print(f"পার্থক্যের (A - B) 95% bootstrap CI: [{diff_lo:.2f}, {diff_hi:.2f}] ms")

if diff_lo > 0:
    print("→ A পরিসংখ্যানগতভাবে ধীর (পার্থক্য সবসময় ধনাত্মক)")
elif diff_hi < 0:
    print("→ A পরিসংখ্যানগতভাবে দ্রুত (পার্থক্য সবসময় ঋণাত্মক)")
else:
    print("→ CI শূন্য অতিক্রম করে — তাৎপর্যপূর্ণ পার্থক্য প্রমাণিত হয়নি")

Illustrative output:

A-এর median: 22.14 ms
B-এর median: 18.87 ms
পার্থক্যের (A - B) 95% bootstrap CI: [1.92, 4.61] ms
→ A পরিসংখ্যানগতভাবে ধীর (পার্থক্য সবসময় ধনাত্মক)

কেন এই পদ্ধতি দুইটা আলাদা CI-এর overlap check-এর চেয়ে ভালো: দুইটা আলাদা CI দেখে “overlap নেই” সিদ্ধান্ত নেওয়া রক্ষণশীল (conservative) — এটা কখনো কখনো একটা সত্যিকার তাৎপর্যপূর্ণ পার্থক্য মিস করে ফেলে, কারণ এটা দুইটা independent uncertainty যোগ করে ফেলে দুইবার। সরাসরি পার্থক্যের bootstrap distribution বানালে এই সমস্যা হয় না — এটাই বাস্তব A/B testing platform (industry standard) যেভাবে করে।

নিজে বাড়ান:

  1. num_resamples কমিয়ে 100 করুন — CI কতটা অস্থির (run প্রতি ভিন্ন) হয়ে যায় দেখুন, আর কেন 10,000+ সাধারণত ব্যবহৃত হয়
  2. একটা synthetic ক্ষেত্রে দুইটা distribution-এর সত্যিকার পার্থক্য শূন্য বানিয়ে (একই parameter দিয়ে generate করে) — CI-টা কত শতাংশ সময় সঠিকভাবে “শূন্য” অন্তর্ভুক্ত করে তা 1000 বার পুনরাবৃত্তি করে পরীক্ষা করুন (এটাই CI-এর “coverage” যাচাই করার পদ্ধতি)
  3. Normal-approximation CI (mean ± 1.96×SE) আর bootstrap CI দুইটাই হিসাব করে skewed বনাম non-skewed ডেটায় তুলনা করুন — কোথায় তারা উল্লেখযোগ্যভাবে ভিন্ন ফল দেয়?

বাস্তব সিস্টেমে

যেখানে এই পরিসংখ্যান সিদ্ধান্ত নির্ধারণ করে

A/B testing platform-এর ইঞ্জিন। Netflix, Airbnb, Booking.com-এর মতো কোম্পানির internal experimentation platform-এর মূল হলো ঠিক এই লেসনের bootstrap ও CI গণনা, স্বয়ংক্রিয়ভাবে হাজার হাজার experiment-এ একসাথে প্রয়োগ করা — একজন product manager শুধু “কোনটা জিতেছে” দেখেন, কিন্তু নিচে চলছে এই একই bootstrap resampling।

ML paper-এ accuracy রিপোর্ট। ভালো ML paper শুধু “accuracy 85.5%” লেখে না — cross-validation fold-জুড়ে standard deviation বা CI-ও রিপোর্ট করে (এই লেসনের worked example ঠিক এই প্যাটার্ন অনুসরণ করে)। এই CI ছাড়া একটা 0.1% improvement দাবি করা অর্থহীন — সেটা noise-এর মধ্যেই পড়ে যেতে পারে।

Database/systems benchmark paper। সিরিয়াস venue-তে (VLDB, OSDI, SOSP) reviewer এখন রুটিনভাবে জিজ্ঞাসা করেন error bar/CI কোথায় — advanced-architecture/benchmarking-methodology লেসনে দেখা প্রতিটা সতর্কতার সাথে এই লেসনের পরিসংখ্যান একসাথে ব্যবহৃত হয় একটা সম্পূর্ণ, প্রতিরক্ষাযোগ্য claim বানাতে।

Continuous Integration-এ performance regression detection। Rust compiler, Chromium-এর মতো বড় প্রজেক্ট প্রতি commit-এ automated benchmark চালায় — bootstrap বা অনুরূপ পরিসংখ্যান দিয়ে সিদ্ধান্ত নেয় একটা সামান্য সংখ্যাগত পার্থক্য সত্যিকার regression, নাকি CI-machine noise। Naive threshold-ভিত্তিক rule ("5% ধীর হলেই fail") false positive-এ ভরে যায়, এই কারণেই।

Base rate fallacy বাস্তব জগতে। এই লেসনের medical-test উদাহরণ (p-value-এর ভুল ব্যাখ্যা বোঝাতে) নিজেই একটা বাস্তব সমস্যা — spam filter, fraud detection, security intrusion detection সিস্টেমেও একই ভুল ঘটে: একটা 1% false-positive-rate detector, বিরল ঘটনার জন্য, প্রায়ই বেশিরভাগ alert-ই false positive তৈরি করে, যদি না base rate বিবেচনা করা হয়।

বুঝেছেন কি না দেখুন

1

একটা paper লিখেছে “p = 0.03, তাই আমাদের অনুসন্ধান 97% নিশ্চিত সত্য।” এই বাক্যে কী ভুল আছে?

স্মরণ

এই বাক্যটা p-value-এর দুইটা সাধারণ ভুল ব্যাখ্যা একসাথে করছে।

প্রথমত, p = 0.03 মানে “যদি null hypothesis (কোনো effect নেই) সত্যি হতো, তাহলে এই ডেটা (বা তার চেয়ে চরম) দেখার সম্ভাবনা 3%” — এটা “আমাদের অনুসন্ধান সত্যি হওয়ার সম্ভাবনা” না। এই দুইটা সম্পূর্ণ ভিন্ন conditional probability (P(data|H₀) বনাম P(H₀|data)), আর এই লেসনের medical-test উদাহরণ দেখিয়েছে এই দুইটা অনেক দূরে থাকতে পারে, base rate-এর উপর নির্ভর করে।

দ্বিতীয়ত, “97% নিশ্চিত” একটা confidence-এর ভাষা যা p-value প্রদান করে না — p-value একটা binary-ধাঁচের threshold test-এর অংশ (< 0.05 কি না), এটা কোনো “নিশ্চয়তার শতাংশ” না।

সঠিক ভাষা হতো: “null hypothesis সত্যি ধরে নিলে, এই মাপের পার্থক্য কাকতালীয়ভাবে দেখার সম্ভাবনা 3%-এর কম — তাই আমরা null hypothesis প্রত্যাখ্যান করছি প্রচলিত 0.05 থ্রেশহোল্ডে,” এবং এর সাথে effect size ও CI যোগ করা, শুধু p-value একা না।

2

কেন bootstrap CI-এ p99-এর CI প্রায় সবসময় median-এর CI-এর চেয়ে অনেক চওড়া হয়? এটার একটা ব্যবহারিক পরিণতি কী পরের experiment ডিজাইন করার সময়?

যুক্তি

Median একটা robust statistic — এটা নির্ধারিত হয় ডেটার “মাঝখানের” মান দিয়ে, আর n টা ডেটা পয়েন্টের প্রায় অর্ধেকই এর কাছাকাছি থাকে। প্রতিটা resample-এ median সামান্যই বদলায়, কারণ অনেক data point মিলেই median নির্ধারণ করে।

p99 নির্ধারিত হয় সবচেয়ে কম সংখ্যক data point দিয়ে — মাত্র সেরা 1% (একটা n=100 sample-এ, কার্যত একটা মাত্র point)। Bootstrap resample-এ কোন point-টা সেই 1%-এ পড়বে তা প্রতিবার অনেক বদলে যেতে পারে — ফলে resample-জুড়ে p99-এর মান অনেক বেশি ওঠানামা করে, CI চওড়া হয়।

ব্যবহারিক পরিণতি: যদি কোনো experiment-এর লক্ষ্য p99 latency নিয়ে একটা নির্দিষ্ট claim করা (যেমন “p99 20% কমেছে”), তাহলে median নিয়ে একই claim-এর চেয়ে অনেক বেশি sample দরকার একটা সংকীর্ণ, বিশ্বাসযোগ্য CI পেতে — এটা cs-theory/hypothesis-formation-and-experiment-design লেসনের sample-size আলোচনার সরাসরি সম্প্রসারণ। Pre-registration লেখার সময় p99-নির্ভর claim-এর জন্য উল্লেখযোগ্যভাবে বড় n ধরে রাখা উচিত।

3

দুইটা caching strategy-র median latency-র bootstrap CI: A = [14.2, 15.8]ms, B = [15.1, 16.9]ms। এই দুইটা CI overlap করে ([15.1, 15.8])। এই অবস্থায় সঠিক উপসংহার কী, আর কী বলা উচিত না?

প্রয়োগ

সঠিক উপসংহার: “এই ডেটায় A আর B-র মধ্যে পরিসংখ্যানগতভাবে তাৎপর্যপূর্ণ পার্থক্য পাওয়া যায়নি — যদিও A-এর point estimate (14.2-15.8-এর মাঝামাঝি কোথাও) সংখ্যাগতভাবে B-এর চেয়ে কম, এই পার্থক্যটা measurement noise-এর মধ্যেই পড়তে পারে।”

যা বলা উচিত না: “A দ্রুত” — শুধু point estimate ছোট হওয়াটা যথেষ্ট প্রমাণ না, এই লেসনের পুরো কেন্দ্রীয় বার্তা এটাই।

পরবর্তী পদক্ষেপ (একটা উপসংহারে না গিয়ে): এই লেসনের বিল্ড-ইট অংশের পরামর্শ অনুযায়ী, সরাসরি পার্থক্যের (A - B) bootstrap CI হিসাব করা উচিত — দুইটা আলাদা CI-এর overlap check-এর চেয়ে এটা বেশি নির্ভুল সিদ্ধান্ত দেয়, কারণ এতে দুইটা sample-এর মধ্যে সম্ভাব্য correlation বা ভিন্ন variance সরাসরি হিসাবে আসে। যদি পার্থক্যের CI-ও শূন্য অতিক্রম করে, তাহলে নিশ্চিতভাবে বলা যায় পার্থক্যটা তাৎপর্যপূর্ণ প্রমাণিত হয়নি — আর তখন sample size বাড়ানোই পরবর্তী যৌক্তিক পদক্ষেপ, নতুন metric খোঁজা না (যা p-hacking-এ নিয়ে যাবে)।

এরপর কী

আমরা এখন জানি কীভাবে একটা claim পরিসংখ্যানগতভাবে প্রতিরক্ষাযোগ্য করতে হয়। কিন্তু একটা প্রশ্ন এখনো বাকি: আপনার সহকর্মী, বা এক বছর পরের আপনি নিজে, যদি এই একই experiment আবার চালাতে চান — তারা কি একই ফলাফল পাবেন? Random seed, library version, hardware, এমনকি floating-point rounding-এর ছোট পার্থক্যও একটা “প্রতিরক্ষাযোগ্য” ফলাফলকে অপ্রতিরূপণযোগ্য করে দিতে পারে।

পরের লেসনে আমরা reproducibility-র প্রশ্নে ঢুকব — এটা কেন একটা প্রকৃত সংকট (crisis), reproducibility ও replicability-র পার্থক্য, আর আপনার নিজের কাজকে reproducible করার একটা বাস্তব checklist।

আরও পড়ুন

  • Producing Wrong Data Without Doing Anything Obviously Wrong! — Todd Mytkowicz, Amer Diwan, Matthias Hauswirth, Peter F. Sweeney · ASPLOS 2009 — advanced-architecture module-এই আলোচিত, measurement bias-এর ক্লাসিক উদাহরণ
  • An Introduction to the Bootstrap — Bradley Efron, Robert Tibshirani · Bootstrap resampling-এর মূল, প্রামাণ্য পাঠ্য
  • The ASA Statement on p-Values: Context, Process, and Purpose — American Statistical Association · 2016 — p-value-এর অপব্যাখ্যা নিয়ে পরিসংখ্যানবিদদের আনুষ্ঠানিক, সর্বসম্মত সতর্কবার্তা