সরাসরি পর্বে যান
পর্ব ৩৬ · ৭৯-এর মধ্যে · মডিউল ৬

Distribution আর sampling — normal, binomial আর simulation

Probability Distributions and Sampling — Random Variables, Binomial, Poisson, Normal, scipy.stats, Stratified Samples and Monte Carlo

Taught in Bangla, this lesson builds a PMF and CDF from order counts, computes expected value and variance by hand and checks them by simulation, and uses scipy.stats for binomial, Poisson, normal and exponential questions. In-page runs compare simple random and stratified sampling and show Monte Carlo error shrinking as 1/√n.

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

  • Random variable, PMF, PDF আর CDF সহজ ভাষায়, আর গণনা থেকে নিজে একটি PMF বানানো
  • একটি ছোট PMF-এর expected value আর variance হাতে বের করে simulation দিয়ে মেলানো
  • Binomial, Poisson, normal আর exponential কখন কোনটি, সূত্র আর scipy.stats দিয়ে তাদের হিসাব
  • z-score থেকে সম্ভাবনা, আর উল্টো দিকে ppf দিয়ে সীমা বের করা
  • Simple random আর stratified sampling-এর পার্থক্য, sampling bias চেনা, আর Monte Carlo-র ভুল 1/√n হারে কমা নিজের চোখে দেখা

পর্ব ১৬-এ np.random.default_rng দিয়ে random সংখ্যা বানিয়েছেন, আর একটি ছোট Monte Carlo দিয়ে দেরিতে ডেলিভারির সম্ভাবনা অনুমান করেছেন। পর্ব ৩৫-এ (AI-এর জন্য সম্ভাবনা) event, conditional probability আর independence-এর নিয়ম আসছে। এই পর্বে সেই দুটি জোড়া লাগবে: একটি অনিশ্চিত সংখ্যার পুরো চেহারা কীভাবে লেখা যায় (distribution), তা থেকে কীভাবে নমুনা তোলা যায় (sampling), আর হাতে হিসাব কঠিন হলে কীভাবে অনেকবার ঘটিয়ে উত্তর পাওয়া যায় (simulation). উদাহরণ বাজারঘরের, এই কোর্সের কাল্পনিক অনলাইন দোকান। পাতার কোড ব্রাউজারেই চলে; প্রথমবার SciPy আর pandas নামাতে কয়েক সেকেন্ড লাগতে পারে।

১ · Random variable — অনিশ্চিত সংখ্যার একটি নাম

বাজারঘরের ম্যানেজার সকাল ১০টায় জানতে চান: “আগামী এক ঘণ্টায় কয়টি অর্ডার আসবে?” উত্তরটি আগে থেকে জানা নেই। হতে পারে ০, ২ বা ৫টি। কিন্তু একেবারে অজানাও নয়: অতীতের খাতা দেখে বলা যায় ২টি আসা বেশ সম্ভব, ১০টি প্রায় অসম্ভব। এমন একটি অনিশ্চিত সংখ্যাকে নাম দিলে, ধরুন X, তাকে বলে random variable: একটি নিয়ম, যা প্রতিটি সম্ভাব্য ফলাফলকে একটি সংখ্যা দেয়, আর সেই সংখ্যাগুলোর প্রত্যেকটির একটি সম্ভাবনা আছে। “Random” মানে এখানে “এলোমেলো” নয়, “আগে থেকে নিশ্চিত নয়”; আর “variable” মানে প্রোগ্রামের variable নয়, গণিতের একটি পরিমাণ।

আবহাওয়ার পূর্বাভাসের কথা ভাবুন। “কাল বৃষ্টি হবে কি না” একটি হ্যাঁ/না প্রশ্ন; “কাল কত মিলিমিটার বৃষ্টি হবে” একটি সংখ্যা, যা আজ জানা নেই। আবহাওয়া অফিস একটি সংখ্যা বলে না, বলে একটি ছবি: “৭০% সম্ভাবনা ১০ মিলিমিটারের কম, ৫% সম্ভাবনা ৫০-এর বেশি।” এই পুরো ছবিটিই distribution: কোন মান কতটা সম্ভব, তার পূর্ণ হিসাব।

Random variable দুই রকম, আর দুটির হিসাবের ভাষা আলাদা:

Discrete (গোনা যায়)

মানগুলো আলাদা আলাদা, মাঝখানে কিছু নেই: ঘণ্টায় অর্ডার ০, ১, ২, …; দিনে ফেরত আসা পার্সেল; একটি review-এর তারকা ১–৫। প্রতিটি মানের নিজস্ব সম্ভাবনা থাকে। পর্ব ২৯-এর discrete data এই ধরনের।

Continuous (মাপা যায়)

একটি পরিসরের যেকোনো মান হতে পারে: ডেলিভারির সময় ২.৩৭ দিন, পার্সেলের ওজন ৮৪৩.২ গ্রাম, দুই অর্ডারের মাঝের সময়। মান অসংখ্য, তাই সম্ভাবনা থাকে একটি পরিসরে, একক বিন্দুতে নয়। এটি continuous data.

একটি সূক্ষ্মতা: দাম টাকায় আর পয়সায় মাপা হয়, তাই কাগজে-কলমে তা discrete (বাজারঘর দাম রাখে পূর্ণসংখ্যার পয়সায়)। কিন্তু মান এত বেশি আর এত ঘন যে বিশ্লেষণে তাকে continuous ধরা সুবিধার। লেখার রীতি: বড় হাতের X মানে random variable নিজে, ছোট হাতের x মানে তার একটি নির্দিষ্ট মান। P(X = 2) পড়ুন “X-এর মান ২ হওয়ার সম্ভাবনা”।

২ · PMF, PDF আর CDF — সম্ভাবনা কোথায় থাকে

তিনটি সংক্ষিপ্ত নাম এই পর্ব জুড়ে বারবার আসবে। প্রথমে সহজ ভাষায়, তারপর ছবিতে।

  • PMF (probability mass function): discrete X-এর জন্য, প্রতিটি মানের সম্ভাবনা। P(X = 2) = 0.35 মানে “ঠিক ২টি অর্ডার আসার সম্ভাবনা ০.৩৫”। সব মানের PMF যোগ করলে 1.
  • PDF (probability density function): continuous X-এর জন্য, একটি বক্ররেখা। রেখার উচ্চতা সম্ভাবনা নয়, ঘনত্ব (density): কোন এলাকায় মান বেশি ঘন। সম্ভাবনা হলো রেখার নিচের ক্ষেত্রফল; পুরো রেখার নিচে মোট ক্ষেত্রফল 1.
  • CDF (cumulative distribution function): দুই ধরনের জন্যই, F(x) = P(X ≤ x), মানে “x বা তার কম” হওয়ার সম্ভাবনা। এটি শূন্য থেকে ধীরে ধীরে বেড়ে 1-এ পৌঁছায়, কখনো কমে না। পর্ব ৩০-এ ডেটা থেকে আঁকা ECDF এরই নমুনা-সংস্করণ।

Discrete-এ সম্ভাবনা দণ্ডের উচ্চতায়, continuous-এ বক্ররেখার নিচের ক্ষেত্রফলে

Left: PMF of orders per hour (bar height = probability). Right: PDF of delivery time (area = probability; one exact point has zero width, so zero probability)

PMF বনাম PDF PMF · ঘণ্টায় অর্ডার .15.30.35.15.05 01234 উচ্চতা = সম্ভাবনা যোগফল = 1 PDF · ডেলিভারির দিন 02346 .29 ঠিক 2: সম্ভাবনা 0 ক্ষেত্রফল = সম্ভাবনা মোট ক্ষেত্রফল = 1
ছবি ৩৬.১ — বাঁয়ে: ঘণ্টায় অর্ডারের PMF; প্রতিটি দণ্ডের উচ্চতাই সেই মানের সম্ভাবনা। ডানে: ডেলিভারির সময়ের একটি কাল্পনিক PDF (ডান দিকে লম্বা লেজ, অংশ ৭)। “২ থেকে ৩ দিনের মধ্যে” পৌঁছানোর সম্ভাবনা সবুজ অংশের ক্ষেত্রফল, প্রায় ০.২৯। লাল রেখাটি “ঠিক ২.০০০… দিন”: তার কোনো প্রস্থ নেই, তাই ক্ষেত্রফল, মানে সম্ভাবনা, শূন্য।
মূল ধারণা

Continuous random variable-এর ঠিক একটি মানের সম্ভাবনা শূন্য। “ডেলিভারি ঠিক ২ দিনে হবে” মানে ২.০০০০০০… দিন, এক ন্যানোসেকেন্ডও এদিক-ওদিক নয়; তার সম্ভাবনা ০। এর মানে ঘটনাটি অসম্ভব নয়; অসংখ্য মানের প্রতিটিতে আলাদা সম্ভাবনা ভাগ করা যায় না। তাই continuous-এ প্রশ্ন সবসময় পরিসরের: P(1.5 < T < 2.5). একই কারণে continuous-এ P(T ≤ 2) আর P(T < 2) সমান, কিন্তু discrete-এ P(X ≤ 2) আর P(X < 2) আলাদা, কারণ মাঝে P(X = 2) = 0.35 আছে।

PDF-এর উচ্চতা 1-এর বেশিও হতে পারে, কারণ তা সম্ভাবনা নয়: σ = 0.1-এর normal-এর চূড়া প্রায় 3.99, তবু নিচের মোট ক্ষেত্রফল 1. এবার গণনা থেকে একটি PMF আর CDF নিজের হাতে বানান। নিচে বাজারঘরের ঢাকা শাখার ২০ ঘণ্টার খাতা: প্রতিটি সংখ্যা এক ঘণ্টার অর্ডার।

গণনা থেকে PMF 2 1 0 3 2 1 1 2 4 2 0 1 3 2 1 2 1 0 2 3 .15.30.35.15.05 x গণনা CDF 01234
  1. কাঁচা খাতা। ২০টি ঘণ্টা, প্রতিটিতে ০ থেকে ৪টি অর্ডার। এই তালিকা নিজে কোনো distribution নয়, তার একটি নমুনা।
  2. গোনা। ০ এসেছে ৩ বার, ১ এসেছে ৬ বার, ২ এসেছে ৭ বার, ৩ এসেছে ৩ বার, ৪ এসেছে ১ বার। মোট 3 + 6 + 7 + 3 + 1 = 20, তাই কোনো ঘণ্টা বাদ পড়েনি। NumPy-তে এক লাইন: np.unique(h, return_counts=True).
  3. ভাগ করে PMF. প্রতিটি গণনাকে ২০ দিয়ে ভাগ: 3/20 = 0.15, 6/20 = 0.30, 7/20 = 0.35, 3/20 = 0.15, 1/20 = 0.05. দণ্ডগুলোর উচ্চতাই সম্ভাবনা, আর যোগ 1. এটি empirical PMF, মানে ডেটা থেকে মাপা; আসল distribution-এর একটি অনুমান।
  4. চলতি যোগফলে CDF. বাঁ থেকে যোগ করতে থাকুন: 0.15; 0.15 + 0.30 = 0.45; 0.45 + 0.35 = 0.80; 0.95; 1.00. NumPy-তে np.cumsum(pmf). CDF কখনো কমে না, আর শেষ ঘর সবসময় 1.
  5. CDF থেকে উত্তর। “এক ঘণ্টায় ২টি বা কম” = F(2) = 0.80, যা প্রথম তিনটি দণ্ডের যোগ (0.15 + 0.30 + 0.35). “৩টি বা বেশি” = 1 − F(2) = 0.20. এই 1 − F(x)-এর নাম survival function, scipy.stats-এ sf.

৩ · Expected value আর variance — গড়ে কত, ছড়ানো কত

পুরো distribution একটি টেবিল বা ছবি। প্রায়ই দুটি সংখ্যায় তার সারাংশ লাগে: কেন্দ্র কোথায়, আর মানগুলো কতটা ছড়ানো। Expected value (প্রত্যাশিত মান, E[X] বা μ, গ্রিক অক্ষর “মিউ”) হলো প্রতিটি মানকে তার সম্ভাবনা দিয়ে গুণ করে যোগফল:

E[X] = ∑ x · P(X = x)

এখানে ∑ (গ্রিক “সিগমা”, বড় হাতের) মানে “সব মানের জন্য যোগ করুন”। এটি ওজনসহ গড়: বেশি সম্ভব মান বেশি ওজন পায়। Variance (Var(X) বা σ2) হলো গড় থেকে দূরত্বের বর্গের প্রত্যাশিত মান, আর তার বর্গমূল standard deviation σ:

Var(X) = ∑ (x − μ)2 · P(X = x) = E[X2] − μ2

চায়ের দোকানের হিসাব খাতা ভাবুন। দোকানি জানেন, দিনে গড়ে কত কাপ বিক্রি হয়; সেটি expected value. কিন্তু গরম পানির হাঁড়ি কত বড় রাখবেন, তা ঠিক করতে জানা দরকার কোনো দিন কত বেশি বা কম হয়; সেটিই variance-এর প্রশ্ন। গড় একই হলেও যে দোকানে বিক্রি খুব ওঠানামা করে, সেখানে বেশি মজুত লাগে।

হাতে হিসাব — অংশ ২-এর PMF দিয়ে

xP(x)x · P(x)x − μ(x − μ)2 · P(x)
00.150.00−1.652.7225 × 0.15 = 0.408375
10.300.30−0.650.4225 × 0.30 = 0.12675
20.350.700.350.1225 × 0.35 = 0.042875
30.150.451.351.8225 × 0.15 = 0.273375
40.050.202.355.5225 × 0.05 = 0.276125
যোগ1.00μ = 1.65—σ2 = 1.1275

তাহলে ঘণ্টায় গড়ে 1.65টি অর্ডার, আর σ = √1.1275 ≈ 1.0618. “1.65টি অর্ডার” কোনো ঘণ্টায় আসে না; expected value একটি দীর্ঘমেয়াদি গড়, একটি সম্ভাব্য মান নয়। শর্টকাট সূত্রেও মেলান: E[X2] = 0 + 0.30 + 1.40 + 1.35 + 0.80 = 3.85, তাই Var = 3.85 − 1.652 = 3.85 − 2.7225 = 1.1275. এবার একই হিসাব কোডে, আর তারপর simulation দিয়ে: এই PMF থেকে অনেকগুলো কাল্পনিক ঘণ্টা তুলে তাদের গড় আর variance দেখা। নিচেরটি লেখকের যন্ত্রে সত্যিকারের run (Python 3.14.4, NumPy 2.5.1, SciPy 1.18.0); পাতার চারটি চালানো যায় এমন ব্লক পরের অংশগুলোর জন্য রাখা, তাই এটি কাগজে দেওয়া। কোডটি যেকোনো ব্লকে বসিয়ে মেলাতে পারেন।

import numpy as np
from scipy import stats

x = np.array([0, 1, 2, 3, 4])                  # ঘণ্টায় অর্ডার
p = np.array([0.15, 0.30, 0.35, 0.15, 0.05])   # PMF
E = np.sum(x * p)
var = np.sum((x - E) ** 2 * p)
print("E[X] =", round(E, 4), "| Var(X) =", round(var, 4), "| sd =", round(var ** 0.5, 4))

X = stats.rv_discrete(values=(x, p))           # একই PMF, scipy object
print("scipy:", X.mean().round(4), X.var().round(4))

rng = np.random.default_rng(42)
for n in (100, 10_000, 1_000_000):
    s = rng.choice(x, size=n, p=p)
    print(f"n={n:>9,}  mean={s.mean():.4f}  var={s.var():.4f}")

সত্যিকারের run-এর আউটপুট:

E[X] = 1.65 | Var(X) = 1.1275 | sd = 1.0618
scipy: 1.65 1.1275
n=      100  mean=1.5700  var=0.9851
n=   10,000  mean=1.6423  var=1.1250
n=1,000,000  mean=1.6503  var=1.1272

হাতের হিসাব, NumPy আর scipy.stats.rv_discrete (নিজের দেওয়া মান আর সম্ভাবনা থেকে একটি distribution object) তিনটিই 1.65 আর 1.1275 দিয়েছে। Simulation-এ ১০০টি ঘণ্টায় গড় 1.57, যা আসল মান থেকে 0.08 দূরে; দশ লাখ ঘণ্টায় 1.6503, দূরত্ব মাত্র 0.0003. নমুনা যত বড়, নমুনার গড় তত E[X]-এর কাছে: এটিই law of large numbers-এর মূল কথা, যা অংশ ৯-এ ছবিতে দেখবেন।

দুটি নিয়ম পরে বারবার কাজে লাগবে। এক, E[aX + b] = a·E[X] + b আর Var(aX + b) = a2·Var(X): প্রতিটি অর্ডারে ৬০ টাকা ডেলিভারি চার্জ হলে ঘণ্টায় চার্জের গড় 60 × 1.65 = 99 টাকা, আর variance 3600 × 1.1275. দুই, যোগফলের গড় সবসময় গড়ের যোগফল, কিন্তু variance যোগ হয় শুধু স্বাধীন (independent, পর্ব ৩৫) random variable-এর ক্ষেত্রে।

৪ · Bernoulli, binomial আর geometric — হ্যাঁ/না-এর গণনা

অংশ ২-এর PMF ছিল ডেটা থেকে মাপা। অনেক সময় পরিস্থিতির গঠন থেকেই PMF-এর সূত্র লেখা যায়, কয়েকটি parameter (মডেলের ঠিক করে দেওয়া সংখ্যা) দিয়ে। এমন পরিচিত ছাঁচগুলোকে নামে চেনা হয়। সবচেয়ে সরলটি দিয়ে শুরু।

Bernoulli: একটি পরীক্ষা, দুটি ফল: হ্যাঁ (1) বা না (0). বাজারঘরের একটি অর্ডার ফেরত আসবে কি না, সম্ভাবনা p. P(X = 1) = p, P(X = 0) = 1 − p; E[X] = p, Var(X) = p(1 − p). p = 0.1 হলে variance 0.09; p = 0.5-এ variance সবচেয়ে বেশি (0.25), কারণ তখনই ফল সবচেয়ে অনিশ্চিত।

Binomial: একই রকম n-টি স্বাধীন Bernoulli পরীক্ষায় মোট কয়টি “হ্যাঁ”। একটি দিনে ১০টি অর্ডার, প্রতিটি আলাদাভাবে ০.১ সম্ভাবনায় ফেরত আসে; X = দিনে ফেরত আসা অর্ডার। সূত্র:

P(X = k) = C(n, k) · pk · (1 − p)n − k

এখানে C(n, k) (“n choose k”) হলো n-টি থেকে k-টি বাছার উপায়ের সংখ্যা, Python-এ math.comb(n, k). যুক্তিটি সরল: নির্দিষ্ট k-টি ফেরত আর বাকি n − k-টি না ফেরতের একটি নির্দিষ্ট ক্রমের সম্ভাবনা pk(1 − p)n − k, আর এমন ক্রম আছে C(n, k)-টি। হাতে: P(X = 0) = 0.910 ≈ 0.3487; P(X = 1) = 10 × 0.1 × 0.99 ≈ 0.3874; P(X = 2) = 45 × 0.01 × 0.98 ≈ 0.1937. E[X] = np = 1, Var(X) = np(1 − p) = 0.9.

Binomial-এর শর্ত চারটি, আর বাস্তবে প্রায়ই একটি ভাঙে। n নির্দিষ্ট; প্রতিটি পরীক্ষার ফল শুধু দুটি; p সবার জন্য এক; আর পরীক্ষাগুলো স্বাধীন। একই ক্রেতার পাঁচটি অর্ডার হলে (একই ভুল সাইজ, একই মেজাজ) ফেরতগুলো স্বাধীন নয়; আবার কাপড়ের p আর চালের p আলাদা। তখন binomial বাস্তবের চেয়ে কম ছড়ানো দেখাবে।

Geometric (সংক্ষেপে): প্রথম “হ্যাঁ” আসতে কয়টি পরীক্ষা লাগে। প্রথম ফেরত আসা অর্ডারটি k-তম হওয়ার সম্ভাবনা (1 − p)k − 1·p, গড় 1/p: p = 0.1 হলে গড়ে দশম অর্ডারে প্রথম ফেরত। scipy.stats.geom এই সংজ্ঞাই নেয় (k শুরু 1 থেকে); কিছু বই “প্রথম হ্যাঁ-এর আগে কয়টি না” গোনে (শুরু 0 থেকে), তাই সূত্র মেলানোর আগে সংজ্ঞা দেখে নিন।

scipy.stats-এর এক ছাঁচ

scipy.stats-এর প্রতিটি distribution একই method দেয়। Parameter দিয়ে একবার বানালে তাকে বলে “frozen” distribution, যেমন X = stats.binom(10, 0.1); তারপর:

methodপ্রশ্নউদাহরণ (binom 10, 0.1)
pmf(k) / pdf(x)ঠিক k-এর সম্ভাবনা (discrete) / x-এ ঘনত্ব (continuous)X.pmf(0) ≈ 0.3487
cdf(x)P(X ≤ x)X.cdf(2) ≈ 0.9298
sf(x)P(X > x) = 1 − cdfX.sf(2) ≈ 0.0702, মানে ৩ বা বেশি
ppf(q)cdf-এর উল্টো: কোন মান পর্যন্ত q ভাগX.ppf(0.95) = 3.0
rvs(size, random_state)নমুনা তোলাX.rvs(5, random_state=rng)
mean(), var(), std()তত্ত্বের গড়, variance, σ1.0, 0.9, 0.9487

ppf (percent point function) নামটি অপরিচিত লাগলেও কাজটি পরিচিত: percentile. random_state-এ একটি পূর্ণসংখ্যা বা np.random.default_rng(42)-এর মতো Generator দেওয়া যায় (পর্ব ১৬); এই কোর্সে সবসময় Generator. নিচের কোডে binomial-এর PMF সূত্র দিয়ে আর scipy দিয়ে বের করে মেলানো হয়েছে, তারপর ১০,০০০টি কাল্পনিক দিন simulate করে তাদের আসল কম্পাঙ্ক (frequency) একই ছবিতে।

import math
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

n, p = 10, 0.1               # দিনে ১০টি অর্ডার, প্রতিটি ফেরতের সম্ভাবনা 0.1
k = np.arange(0, 6)
by_hand = np.array([math.comb(n, i) * p**i * (1 - p)**(n - i) for i in k])
X = stats.binom(n, p)        # frozen distribution object
print("k        :", k)
print("formula  :", by_hand.round(4))
print("scipy pmf:", X.pmf(k).round(4))
print("P(X >= 3):", round(1 - X.cdf(2), 4), "| sf(2):", round(X.sf(2), 4))
print("mean, var:", X.mean(), round(X.var(), 4), "| np, np(1-p):", n * p, round(n * p * (1 - p), 4))
print("ppf(0.95):", X.ppf(0.95))

rng = np.random.default_rng(42)
days = X.rvs(size=10_000, random_state=rng)      # ১০,০০০টি কাল্পনিক দিন
freq = np.bincount(days, minlength=n + 1)[:6] / days.size
print("simulated:", freq.round(4))
print("sim mean, var:", days.mean().round(4), days.var().round(4))

fig, ax = plt.subplots(figsize=(6, 3.2), layout="constrained")
ax.bar(k - 0.2, X.pmf(k), width=0.4, label="PMF (exact)")
ax.bar(k + 0.2, freq, width=0.4, label="simulated, 10,000 days")
ax.set_xlabel("returned orders out of 10")
ax.set_ylabel("probability")
ax.set_title("Binomial(n=10, p=0.1)")
ax.legend()
plt.show()

আসল আউটপুট:

k        : [0 1 2 3 4 5]
formula  : [0.3487 0.3874 0.1937 0.0574 0.0112 0.0015]
scipy pmf: [0.3487 0.3874 0.1937 0.0574 0.0112 0.0015]
P(X >= 3): 0.0702 | sf(2): 0.0702
mean, var: 1.0 0.9 | np, np(1-p): 1.0 0.9
ppf(0.95): 3.0
simulated: [0.353  0.3884 0.1896 0.0557 0.0112 0.0019]
sim mean, var: 0.9902 0.9015

math.comb-এর সূত্র আর scipy-র pmf চার দশমিক ঘর পর্যন্ত হুবহু এক, আর প্রথম তিনটি সংখ্যা ওপরের হাতের হিসাবের সঙ্গেও মেলে। “৩ বা বেশি ফেরত” = 1 − cdf(2) = sf(2) = 0.0702, মানে প্রায় ১৪ দিনে একবার। ppf(0.95) = 3.0: ৯৫% দিনে ফেরত ৩টি বা কম। Discrete-এ ppf এমন সবচেয়ে ছোট k দেয়, যেখানে cdf অন্তত 0.95 (cdf(2) = 0.9298, cdf(3) ≈ 0.9872). ১০,০০০টি simulate করা দিনের কম্পাঙ্ক তত্ত্বের কাছাকাছি কিন্তু হুবহু নয় (0.353 বনাম 0.3487); ছবিতে দুই রঙের দণ্ড প্রায় সমান উচ্চতার। Simulation-এর গড় 0.9902 আর variance 0.9015, তত্ত্বের 1 আর 0.9-এর কাছে। হাতের হিসাবে 0.910 = 0.34867844…; শেষ অঙ্কে অমিল দেখলে আগে দেখুন কোন ধাপে round হয়েছে।

৫ · Poisson আর exponential — ঘণ্টায় কয়টি অর্ডার, পরেরটি কখন

Binomial-এ n জানা ছিল: দিনে ১০টি অর্ডার। কিন্তু “আগামী এক ঘণ্টায় কয়টি অর্ডার আসবে” প্রশ্নে n কী? বাজারঘরের লাখো সম্ভাব্য ক্রেতা, প্রত্যেকের এই ঘণ্টায় অর্ডার দেওয়ার সম্ভাবনা খুব ছোট। জানা শুধু গড় হার: ঘণ্টায় গড়ে ৩টি। এমন “অনেক সুযোগ, প্রতিটি বিরল, জানা গড় হার” পরিস্থিতির মডেল Poisson distribution, যার একটিমাত্র parameter λ (গ্রিক “ল্যাম্বডা”): একটি নির্দিষ্ট সময় বা জায়গায় ঘটনার গড় সংখ্যা।

P(X = k) = e−λ · λk / k!

e ≈ 2.718 (স্বাভাবিক logarithm-এর ভিত্তি), আর k! = 1 × 2 × … × k (০! = ১)। λ = 3 হলে: P(X = 0) = e−3 ≈ 0.0498, মানে প্রায় ৫% ঘণ্টায় একটিও অর্ডার আসে না; P(X = 3) = e−3 × 27 / 6 ≈ 0.2240. Poisson-এর একটি বিশেষ বৈশিষ্ট্য: গড় আর variance দুটিই λ। বাস্তব ডেটায় variance গড়ের চেয়ে অনেক বেশি হলে (ঈদের আগে, বিজ্ঞাপনের পরে হঠাৎ ভিড়) Poisson ঠিক মডেল নয়; একে overdispersion বলে, আর তখন negative binomial-এর মতো মডেল লাগে।

Binomial-এর সীমা হিসেবে Poisson

Poisson আসলে binomial থেকেই আসে। ধরুন এক ঘণ্টাকে n-টি ছোট টুকরায় ভাগ করলেন, প্রতিটি টুকরায় একটি অর্ডার আসার সম্ভাবনা p = λ/n. n বড় আর p ছোট হতে থাকলে, কিন্তু গুণফল np = λ স্থির রাখলে, binomial(n, λ/n)-এর PMF Poisson(λ)-এর দিকে যায়। ব্যবহারিক নিয়ম: n বড় আর p ছোট হলে binomial-এর জায়গায় Poisson দিয়ে হিসাব করা যায়, যা সহজ। অংশ ৬-এর কোডে n = 10 থেকে 1,00,000 পর্যন্ত দুটির PMF-এর সবচেয়ে বড় পার্থক্য সত্যিই মাপা হয়েছে।

Exponential (সংক্ষেপে) — পরের অর্ডার পর্যন্ত অপেক্ষা

অর্ডারগুলো যদি Poisson-এর নিয়মে আসে (ঘণ্টায় গড়ে λ = 3টি), তাহলে দুটি পরপর অর্ডারের মাঝের সময় T একটি continuous random variable, যার distribution exponential: গড় অপেক্ষা 1/λ = ⅓ ঘণ্টা = ২০ মিনিট, আর P(T > t) = e−λt. আধা ঘণ্টায় একটিও অর্ডার না আসার সম্ভাবনা e−1.5 ≈ 0.2231. একই প্রশ্ন Poisson দিয়েও করা যায় (আধা ঘণ্টায় গড় 1.5টি, শূন্যটি আসার সম্ভাবনা e−1.5): দুটি মডেল একই ঘটনার দুই দিক।

Exponential-এর একটি অদ্ভুত বৈশিষ্ট্য memorylessness (স্মৃতিহীনতা): ১০ মিনিট ধরে কোনো অর্ডার আসেনি, তাতে পরের ৩০ মিনিটে না আসার সম্ভাবনা বদলায় না; P(T > 40 মিনিট | T > 10 মিনিট) = P(T > 30 মিনিট)। সূত্রে: e−λ·40 / e−λ·10 = e−λ·30. “এতক্ষণ আসেনি, এবার নিশ্চয়ই আসবে” ভাবনাটি এই মডেলে ভুল। পুরোনো যন্ত্রের নষ্ট হওয়ার মতো অপেক্ষা স্মৃতিহীন নয়; সেখানে exponential ভুল মডেল।

৬ · Uniform আর normal — μ, σ, ৬৮–৯৫–৯৯.৭ আর z-score

Uniform: একটি পরিসরের সব মান সমান সম্ভব। Discrete uniform-এর উদাহরণ ছক্কা; continuous uniform-এর উদাহরণ rng.random(), যা [0, 1)-এর যেকোনো জায়গায় সমান ঘনত্বে পড়ে। [a, b]-এ গড় (a + b)/2, variance (b − a)2/12. scipy-তে একটি ফাঁদ: stats.uniform(loc, scale)-এর পরিসর [loc, loc + scale], [loc, scale] নয়; stats.uniform(2, 4) মানে [2, 6]. অংশ ৯-এর π-এর অনুমান পুরোটাই uniform বিন্দুর ওপর দাঁড়িয়ে।

Normal (Gaussian বা “ঘণ্টার মতো” বক্ররেখা) দুটি parameter দিয়ে পুরো ঠিক হয়: μ (কেন্দ্র, যেখানে চূড়া) আর σ (ছড়ানো, চূড়া থেকে বাঁকের জায়গা পর্যন্ত দূরত্ব)। বক্ররেখা μ-এর দুই পাশে সমান (symmetric), আর দুই দিকে লেজ অনন্ত পর্যন্ত যায়, যদিও খুব দ্রুত সরু হয়। অনেক ছোট স্বাধীন প্রভাবের যোগফল প্রায়ই normal-এর মতো হয়; এর গাণিতিক রূপ Central Limit Theorem, পর্ব ৩৭-এর বিষয়।

Normal-এর সবচেয়ে কাজের নিয়ম ৬৮–৯৫–৯৯.৭ নিয়ম: মানগুলোর প্রায় ৬৮% থাকে μ ± 1σ-এর মধ্যে, প্রায় ৯৫% থাকে μ ± 2σ-এর মধ্যে, আর প্রায় ৯৯.৭% থাকে μ ± 3σ-এর মধ্যে। বাজারঘরের ঢাকা শাখায় দৈনিক অর্ডার যদি মোটামুটি normal হয়, μ = 500, σ = 40, তাহলে প্রায় ৯৫% দিনে অর্ডার 420 থেকে 580-এর মধ্যে।

z-score — যেকোনো normal-কে একটি মাপকাঠিতে আনা

৫৬০টি অর্ডারের দিন কতটা অস্বাভাবিক? উত্তর নির্ভর করে σ-এর ওপর। z-score বলে একটি মান গড় থেকে কত σ দূরে:

z = (x − μ) / σ

z = 1.5 মানে “গড়ের দেড় σ ওপরে”। X normal হলে z-ও normal, μ = 0 আর σ = 1, যাকে standard normal বলে। তাই যেকোনো normal-এর সম্ভাবনা একটি টেবিল বা একটি function (stats.norm.cdf) দিয়েই পাওয়া যায়। ধাপে ধাপে দেখুন।

z-score আর normal-এর ক্ষেত্রফল 420460500540580 z=-2-1012 μ = 500, σ = 40
  1. প্রশ্ন। ঢাকার দৈনিক অর্ডার মোটামুটি normal, μ = 500, σ = 40. কত ভাগ দিনে ৫৬০-এর বেশি অর্ডার আসে? মাঝের ড্যাশ রেখা গড়, নিচে দুই সারি: অর্ডার আর z.
  2. z বের করা। z = (560 − 500) / 40 = 60 / 40 = 1.5. লাল রেখাটি গড় থেকে দেড় σ ডানে। এখন প্রশ্নটি হয়ে গেল: standard normal-এ P(Z > 1.5) কত?
  3. বাঁয়ের ক্ষেত্রফল। CDF দেয় রেখার বাঁ দিকের পুরো ক্ষেত্রফল: stats.norm.cdf(1.5) = 0.9332, মানে প্রায় ৯৩% দিনে ৫৬০ বা কম। একই উত্তর stats.norm(500, 40).cdf(560) দিয়েও, z বের না করেই।
  4. ডানের লেজ। মোট ক্ষেত্রফল 1, তাই P(X > 560) = 1 − 0.9332 = 0.0668, প্রায় ৬.৭% দিন, মোটামুটি ১৫ দিনে একবার। sf এই বিয়োগ সরাসরি করে, আর খুব ছোট লেজে বিয়োগের চেয়ে নির্ভুলও থাকে।
  5. উল্টো প্রশ্ন, ppf. “গুদামের ক্ষমতা কত হলে ৯৫% দিন সামলানো যাবে?” এবার সম্ভাবনা জানা, মান খুঁজছি: stats.norm.ppf(0.95) = 1.645, তাই x = 500 + 1.645 × 40 ≈ 565.8, মানে প্রায় ৫৬৬টি অর্ডার। লক্ষ করুন, এটি ৯৫%-এর এক দিকের সীমা; ৬৮–৯৫–৯৯.৭-এর “৯৫% ভেতরে” (দুই দিক মিলিয়ে) নিয়মের z প্রায় 1.96, 1.645 নয়।

এবার তিনটি দাবি একসঙ্গে যাচাই: Poisson সত্যিই binomial-এর সীমা কি না, ৬৮–৯৫–৯৯.৭ নিয়মের আসল সংখ্যা, আর exponential-এর স্মৃতিহীনতা।

import numpy as np
from scipy import stats

lam = 3                                   # ঘণ্টায় গড়ে ৩টি অর্ডার
k = np.arange(0, 9)
P = stats.poisson(lam)
print("Poisson(3) pmf:", P.pmf(k).round(4))
print("P(X=0):", round(P.pmf(0), 4), "| e^-3:", round(np.exp(-3), 4), "| mean, var:", P.mean(), P.var())

for n in (10, 100, 1000, 100_000):        # n*p = 3 স্থির রেখে n বাড়ানো
    B = stats.binom(n, lam / n)
    gap = np.abs(B.pmf(k) - P.pmf(k)).max()
    print(f"n={n:>7,}  p={lam / n:.5f}  max|binom - poisson| = {gap:.6f}")

Z = stats.norm(0, 1)
for z in (1, 2, 3):
    print(f"P(|Z| < {z}) = {Z.cdf(z) - Z.cdf(-z):.4f}")
print("one-sided 95%:", round(Z.ppf(0.95), 4), "| two-sided 95%:", round(Z.ppf(0.975), 4))

rng = np.random.default_rng(42)
x = stats.norm(500, 40).rvs(size=100_000, random_state=rng)   # দৈনিক অর্ডার
print("simulated within 1, 2, 3 sd:",
      [round(float(np.mean(np.abs(x - 500) < z * 40)), 4) for z in (1, 2, 3)])

T = stats.expon(scale=1 / lam)            # অর্ডারের মাঝের সময়, ঘণ্টায়
print("P(T > 30 min):", round(T.sf(0.5), 4), "| mean wait (min):", round(T.mean() * 60, 1))
print("P(T > 40 | T > 10):", round(T.sf(40 / 60) / T.sf(10 / 60), 4))

আসল আউটপুট:

Poisson(3) pmf: [0.0498 0.1494 0.224  0.224  0.168  0.1008 0.0504 0.0216 0.0081]
P(X=0): 0.0498 | e^-3: 0.0498 | mean, var: 3.0 3.0
n=     10  p=0.30000  max|binom - poisson| = 0.042786
n=    100  p=0.03000  max|binom - poisson| = 0.003432
n=  1,000  p=0.00300  max|binom - poisson| = 0.000337
n=100,000  p=0.00003  max|binom - poisson| = 0.000003
P(|Z| < 1) = 0.6827
P(|Z| < 2) = 0.9545
P(|Z| < 3) = 0.9973
one-sided 95%: 1.6449 | two-sided 95%: 1.96
simulated within 1, 2, 3 sd: [0.6817, 0.9536, 0.997]
P(T > 30 min): 0.2231 | mean wait (min): 20.0
P(T > 40 | T > 10): 0.2231

তিনটি দাবিই মিলেছে। Poisson: P(X = 0) সূত্রের e−3-এর সমান, গড় আর variance দুটিই 3.0, আর ২ ও ৩-এর সম্ভাবনা সমান (0.224), কারণ λ পূর্ণসংখ্যা হলে λ − 1 আর λ-এর PMF সমান হয়। সীমা: np = 3 স্থির রেখে n = 10-এ সবচেয়ে বড় পার্থক্য 0.043, যা বড় ভুল; n = 100-এ 0.0034, n = 1,000-এ 0.00034, n = 1,00,000-এ 0.000003. n প্রতি ১০ গুণে পার্থক্য প্রায় ১০ ভাগের ১ ভাগ। ৬৮–৯৫–৯৯.৭: আসল সংখ্যা 0.6827, 0.9545, 0.9973; “৯৫%”-এর সঠিক দুই দিকের z হলো 1.96, আর এক দিকের 1.6449. ১,০০,০০০টি simulate করা দিনে ভাগগুলো 0.6817, 0.9536, 0.997, তত্ত্বের খুব কাছে। Exponential: গড় অপেক্ষা 20.0 মিনিট, আধা ঘণ্টায় কোনো অর্ডার না আসার সম্ভাবনা 0.2231, আর “১০ মিনিট পেরিয়ে গেছে” শর্তে আরও ৩০ মিনিটের সম্ভাবনাও 0.2231: স্মৃতিহীনতা সংখ্যায়।

৭ · যখন ডেটা normal নয় — skew, log-normal আর ভারী লেজ

Normal এত পরিচিত যে অনেকে ধরে নেন সব ডেটাই normal. বাজারঘরের অর্ডারের মূল্য (order value) দেখলেই ভুলটি ধরা পড়ে। বেশির ভাগ অর্ডার ৩০০ থেকে ১,৫০০ টাকার, কিন্তু মাঝে মাঝে কেউ ফ্রিজ বা ল্যাপটপ কেনেন, ৬০,০০০ টাকার। মূল্য কখনো শূন্যের নিচে যায় না, অথচ ওপরের দিকে লম্বা লেজ। এমন ডেটাকে বলে ডান দিকে skewed (right-skewed). এর লক্ষণ: গড় median-এর চেয়ে অনেক বেশি, কারণ কয়েকটি বড় মান গড়কে টেনে নেয় (পর্ব ১৬-এর outlier-এর আলোচনা)।

Skewed ডেটায় normal-এর মডেল বসালে দুটি ক্ষতি হয়। এক, মডেল ঋণাত্মক মূল্য বা ঋণাত্মক সময়কে সম্ভব বলে। দুই, ওপরের লেজকে মডেল অনেক ছোট ধরে, তাই “৫০,০০০ টাকার বেশি অর্ডার প্রায় অসম্ভব” বলে, অথচ সেগুলো নিয়মিত আসে।

Log-normal, একটি নোট। যদি log(মূল্য) মোটামুটি normal হয়, তাহলে মূল্যের distribution-কে log-normal বলে। অন্তর্দৃষ্টি: normal আসে অনেক ছোট প্রভাবের যোগফল থেকে, log-normal আসে অনেক প্রভাবের গুণফল থেকে (দাম × পরিমাণ × ছাড়ের হার)। ছবি ৩৬.১-এর ডেলিভারির বক্ররেখাটি একটি log-normal (median ২ দিন), যার গড় প্রায় ২.২৭ দিন, median-এর চেয়ে বেশি। ব্যবহারিক কৌশল: মূল্যের মতো ডেটা np.log দিয়ে রূপান্তর করে বিশ্লেষণ, আর chart-এ log axis (পর্ব ২৯)। তবে log-normal-ও একটি ধারণা মাত্র; ডেটা দেখে মেলাতে হয়।

ভারী লেজ — যখন চরম মানই আসল খবর

কিছু distribution-এর লেজ normal তো বটেই, log-normal-এর চেয়েও মোটা: চরম মান অনেক বেশি ঘন ঘন আসে। এদের বলে heavy-tailed. এমন ডেটায় কয়েকটি বড় মান মোট যোগফলের বড় অংশ নিতে পারে, আর নমুনার গড় খুব ধীরে স্থির হয়; কিছু চরম ক্ষেত্রে (তাত্ত্বিক Cauchy distribution) গড়ই সংজ্ঞায়িত নয়, তাই law of large numbers কাজ করে না। কোন বাস্তব ডেটা কতটা ভারী লেজের, তা নিয়ে বিতর্ক আছে (ভাবনার প্রশ্ন ৫)। ব্যবহারিক শিক্ষাটি হলো: শুধু গড় আর σ দিয়ে ঝুঁকি মাপবেন না; লেজ আলাদা করে দেখুন, যেমন সর্বোচ্চ ১%-এর মান, আর পর্ব ৩০-এর histogram বা ECDF.

বাজারঘরের প্রশ্নপ্রথম চেষ্টার মডেলকখন ভাঙে
১০টি অর্ডারে কয়টি ফেরতbinomial(n, p)একই ক্রেতার অর্ডার, পণ্যভেদে p আলাদা
ঘণ্টায় কয়টি অর্ডারPoisson(λ)ভিড়ের সময়, variance গড়ের চেয়ে বেশি
দুই অর্ডারের মাঝের সময়exponential(λ)দিনের সময়ভেদে হার বদলায়
ভালো দিনের মোট অর্ডারnormal(μ, σ)উৎসব, ছুটি, ছোট সংখ্যা
অর্ডারের মূল্যlog-normalখুব বড় পাইকারি অর্ডার, ভারী লেজ

৮ · Sampling — population, নমুনা, stratified আর পক্ষপাত

এ পর্যন্ত distribution জানা ছিল, আর আমরা তা থেকে সংখ্যা তুলেছি। বাস্তবে উল্টো: distribution অজানা, হাতে শুধু কিছু ডেটা। Population হলো যাদের নিয়ে প্রশ্ন, তাদের সবাই: বাজারঘরের এ বছরের সব অর্ডার। নমুনা (sample) হলো তাদের যে অংশটি আসলে দেখা হয়: ২০০টি অর্ডারের ক্রেতাকে ফোন করে সন্তুষ্টির জরিপ। নমুনা থেকে population সম্পর্কে বলতে হলে নমুনাটি population-এর ছোট কিন্তু সৎ প্রতিচ্ছবি হতে হবে।

রান্নার সময় তরকারির লবণ চাখতে পুরো হাঁড়ি খেতে হয় না, এক চামচই যথেষ্ট, কিন্তু শর্ত একটি: আগে ভালো করে নাড়তে হবে। না নেড়ে ওপর থেকে চামচ তুললে শুধু ঝোল আসবে, তলার মসলা আসবে না। Sampling-এর পুরো বিদ্যা এই “নাড়া”-র নিয়ম।

  • Simple random sampling: population-এর প্রতিটি সদস্যের বাছাই হওয়ার সম্ভাবনা সমান, আর বাছাই random. pandas-এ orders.sample(n=200, random_state=rng). সহজ আর পক্ষপাতহীন, কিন্তু ছোট নমুনায় ছোট দলগুলো দৈবাৎ কম বা বেশি আসতে পারে।
  • Stratified sampling: population-কে আগে স্তরে (stratum, বহুবচনে strata) ভাগ করে, যেমন জেলা, তারপর প্রতিটি স্তর থেকে আলাদাভাবে random নমুনা, সাধারণত স্তরের আকারের অনুপাতে। তাহলে বরিশালের ৩% অর্ডার নমুনাতেও প্রায় ৩%. pandas-এ orders.groupby("district").sample(frac=0.02, random_state=...): পর্ব ২৪-এর split-apply-combine, যেখানে “apply” ধাপটি নমুনা তোলা। মডেলের train/test ভাগে class imbalance থাকলে একই ভাবনা (stratified split) লাগে।

নিচের কোডে ১০,০০০টি অর্ডারের একটি কাল্পনিক population, ছয়টি জেলায়। দুই পদ্ধতিতে ২০০টি করে নমুনা ১০০ বার তোলা হয়েছে, আর প্রতিবার মাপা হয়েছে: নমুনায় কোনো জেলার ভাগ population-এর ভাগ থেকে সবচেয়ে বেশি কতটা সরে গেছে।

import numpy as np
import pandas as pd

rng = np.random.default_rng(42)
share = {"ঢাকা": 0.50, "চট্টগ্রাম": 0.20, "খুলনা": 0.12,
         "রাজশাহী": 0.10, "সিলেট": 0.05, "বরিশাল": 0.03}
orders = pd.DataFrame({"district": rng.choice(list(share), size=10_000,
                                              p=list(share.values()))})
true = orders["district"].value_counts(normalize=True)
print(true.round(4).to_string())

def worst_share_error(sample):
    s = sample["district"].value_counts(normalize=True)
    return (s.reindex(true.index, fill_value=0) - true).abs().max()

simple, strat = [], []
for i in range(100):                             # ১০০ বার নমুনা তোলা
    a = orders.sample(n=200, random_state=i)     # simple random
    b = orders.groupby("district").sample(frac=0.02, random_state=i)
    simple.append(worst_share_error(a))
    strat.append(worst_share_error(b))
print("simple random: mean", round(np.mean(simple), 4), "| worst", round(np.max(simple), 4))
print("stratified   : mean", round(np.mean(strat), 4), "| worst", round(np.max(strat), 4))
print("stratified sample size:", len(b))
print(b["district"].value_counts().to_dict())

আসল আউটপুট:

district
ঢাকা         0.5015
চট্টগ্রাম    0.2043
খুলনা        0.1180
রাজশাহী      0.0977
সিলেট        0.0480
বরিশাল       0.0305
simple random: mean 0.0395 | worst 0.1035
stratified   : mean 0.004 | worst 0.004
stratified sample size: 201
{'ঢাকা': 100, 'চট্টগ্রাম': 41, 'খুলনা': 24, 'রাজশাহী': 20, 'সিলেট': 10, 'বরিশাল': 6}

Population-এর ভাগগুলো choice-এর p-এর কাছাকাছি, হুবহু নয় (ঢাকা 0.5015). Simple random-এ ২০০টি অর্ডারের নমুনায় কোনো একটি জেলার ভাগ গড়ে প্রায় ৪ শতাংশ বিন্দু সরে গেছে, আর সবচেয়ে খারাপ বারে ১০ শতাংশ বিন্দুর বেশি: ঢাকার ৫০%-কে ৪০% বা ৬০% দেখানোর মতো ভুল। Stratified-এ ভুল প্রতিবার 0.004, কারণ প্রতিটি জেলা থেকে ঠিক ২%: ঢাকার ৫,০১৫টি থেকে ১০০টি, বরিশালের ৩০৫টি থেকে ৬টি। যে ছোট ভুল রয়ে গেছে, তা শুধু round করার (৩০৫ × 0.02 = 6.1 থেকে 6), তাই নমুনার আকারও 200 নয়, 201. মনে রাখুন, stratification শুধু স্তরের ভাগ ঠিক রাখে; প্রতিটি জেলার ভেতরে সন্তুষ্টি বা মূল্যের অনুমানে random ভুল থাকেই, তবে সাধারণত simple random-এর চেয়ে কম, বিশেষ করে যখন জেলাগুলো আলাদা আচরণ করে।

Sampling bias — বড় নমুনাও বাঁচায় না

Random না হলে নমুনা যত বড়ই হোক, ভুল দিকে নিখুঁত হয়। একে বলে sampling bias: নমুনায় ঢোকার সম্ভাবনা নিজেই এমন কিছুর ওপর নির্ভর করে, যা আমরা মাপতে চাই। একটি হাতে হিসাবের উদাহরণ। ধরুন বাজারঘরের সব ক্রেতার সত্যিকারের রেটিং এমন: ১★ ১০%, ২★ ১০%, ৩★ ২০%, ৪★ ৩০%, ৫★ ৩০%; সত্যিকারের গড় 0.1 + 0.2 + 0.6 + 1.2 + 1.5 = 3.6. কিন্তু review লেখেন বেশি খুশিরা: ১★ আর ২★ ক্রেতার ৫%, ৩★-এর ১০%, ৪★-এর ২০%, ৫★-এর ৪০%. তাহলে review-এর মধ্যে ভাগ হয় 0.005, 0.005, 0.02, 0.06, 0.12 (মোট 0.21), আর review-এর গড় (0.005 + 0.01 + 0.06 + 0.24 + 0.60) / 0.21 = 0.915 / 0.21 ≈ 4.36. দশ লাখ review হলেও গড় 4.36-এর কাছেই থাকবে, 3.6-এর দিকে যাবে না। বাস্তবে অসন্তুষ্টরাও অনেক সময় বেশি লেখেন; মূল কথা, কারা নমুনায় ঢুকছে তা random নয়।

পক্ষপাতের পরিচিত কয়েকটি রূপ:

  • Survivorship bias: শুধু যারা “টিকে আছে” তাদের দেখা। “বাজারঘরে ৫ বছর ধরে যে বিক্রেতারা আছেন, তাঁদের সবার রেটিং ভালো, তাই আমাদের প্ল্যাটফর্মে সবাই সফল” — অথচ যাঁরা টেকেননি, তাঁরা ডেটাতেই নেই।
  • সুবিধার নমুনা (convenience sample): শুধু ঢাকার ক্রেতাকে ফোন, কারণ তাঁদের নম্বর হাতের কাছে।
  • উত্তর না দেওয়া (non-response): ১,০০০ জনকে জরিপ পাঠানো হলো, ১৫০ জন উত্তর দিলেন; যাঁরা দিলেন না, তাঁরা হয়তো সবচেয়ে ব্যস্ত বা সবচেয়ে বিরক্ত।

AI-এর জন্য এটি সরাসরি প্রাসঙ্গিক: একটি মডেল তার training ডেটার distribution শেখে। ডেটা যদি একটি পক্ষপাতদুষ্ট নমুনা হয় (শুধু শহরের ক্রেতা, শুধু ইংরেজি review), মডেল বাকিদের জন্য খারাপ কাজ করতে পারে, আর একই রকম test ডেটায় মাপলে কেউ টের পায় না।

৯ · Monte Carlo আর বড় সংখ্যার নিয়ম — π, ক্ষমতা ছাড়ানো আর 1/√n

পর্ব ১৬-এ Monte Carlo দিয়ে দেরিতে ডেলিভারির সম্ভাবনা অনুমান করেছেন: অনেকবার random ঘটনা ঘটিয়ে “হ্যাঁ”-এর ভাগ গোনা। এখানে দুটি নতুন প্রয়োগ আর তার পেছনের নিয়ম। প্রথমটি বিখ্যাত খেলনা-সমস্যা: π-এর অনুমান। এক বাহুর একটি বর্গের ভেতরে uniform random বিন্দু ফেলুন। বর্গের এক কোণকে কেন্দ্র করে ব্যাসার্ধ ১-এর একটি পোয়া বৃত্ত আঁকা; তার ক্ষেত্রফল π/4, বর্গের ক্ষেত্রফল ১। তাই বিন্দুর মোটামুটি π/4 ভাগ বৃত্তের ভেতরে পড়বে, আর

π ≈ 4 × (বৃত্তের ভেতরের বিন্দু) / (মোট বিন্দু)

একটি বিন্দু (x, y) ভেতরে কি না, তা পরীক্ষা x2 + y2 ≤ 1. নিচে লেখকের যন্ত্রে default_rng(42) দিয়ে একটি run, ধাপে ধাপে বাড়ানো (NumPy 2.5.1).

Monte Carlo দিয়ে π n ভেতরে অনুমান |ভুল|
  1. নকশা। বর্গের প্রতিটি বিন্দুর সম্ভাবনা সমান (uniform). পোয়া বৃত্তের ক্ষেত্রফল π/4 ≈ 0.785, তাই একটি বিন্দু ভেতরে পড়ার সম্ভাবনা p = π/4. বিন্দুগুলো একেকটি Bernoulli পরীক্ষা।
  2. ১০টি বিন্দু। ৬টি ভেতরে (সবুজ), ৪টি বাইরে (লাল)। অনুমান 4 × 6/10 = 2.4, আসল π থেকে 0.742 দূরে। দশটি বিন্দু প্রায় কিছুই বলে না।
  3. ১০০টি বিন্দু। ৭৬টি ভেতরে, অনুমান 3.04. ভুল 0.102.
  4. ১,০০০টি। ৭৭১টি ভেতরে, অনুমান 3.084, ভুল 0.058. প্রত্যাশিত ভুল (নিচে) প্রায় 0.052, তাই এটি স্বাভাবিক।
  5. ১০,০০০টি। অনুমান 3.16, ভুল 0.018: আগের ধাপের চেয়ে কম, কিন্তু অনুমানটি এবার π-এর ওপরে চলে গেছে। একটি run-এর ভুল ওঠানামা করে; শুধু তার প্রবণতা নিয়ম মানে।
  6. ১,০০,০০০টি। অনুমান 3.15008, ভুল 0.0085, প্রত্যাশিত 0.0052-এর দেড় গুণের কিছু বেশি; এমন হওয়া অস্বাভাবিক নয়। এক লাখ বিন্দুতেও দ্বিতীয় দশমিক ঘর মেলেনি: অনুমান 3.15, আর π প্রায় 3.14.
  7. নিয়ম। প্রতিটি বিন্দু Bernoulli(p), তাই অনুমানের standard deviation 4 × √(p(1 − p)/n) ≈ 1.64/√n. নমুনা ১০০ গুণ হলে ভুল ১০ ভাগের ১ ভাগ। এক দশমিক ঘর বেশি নির্ভুলতার দাম ১০০ গুণ কাজ।

দ্বিতীয় প্রয়োগটি ব্যবসার: বাজারঘরের গুদাম দিনে ৫২০টি অর্ডার প্যাক করতে পারে, আর দৈনিক অর্ডার মোটামুটি Poisson, λ = 480. কোনো দিন ক্ষমতা ছাড়ানোর সম্ভাবনা কত? এখানে সঠিক উত্তর stats.poisson(480).sf(520) দিয়েই পাওয়া যায়, আর ঠিক সেই কারণেই উদাহরণটি ভালো: Monte Carlo-র ভুল সত্যিই মাপা যায়। মডেল জটিল হলে সূত্র থাকে না, কিন্তু simulation একই রকম লেখা যায়।

নিচের কোড প্রতিটি n-এ অনুমানটি ৩০ বার চালিয়ে ভুলের RMS (বর্গের গড়ের বর্গমূল, মানে একটি সাধারণ run কতটা দূরে) মেপেছে, তারপর log-log ছবিতে এঁকেছে: দুই অক্ষেই log স্কেল (log scale), যেখানে ভুল = c/√n একটি ঢাল −½-এর সরলরেখা। ডানের ছবিতে law of large numbers: একটি run-এর চলতি অনুমান (running estimate) কীভাবে π-এর দিকে স্থির হয়।

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

rng = np.random.default_rng(42)
ns = np.array([100, 1_000, 10_000, 100_000])
cap_exact = stats.poisson(480).sf(520)          # P(দিনের অর্ডার > 520)
pi_err, cap_err = [], []
for n in ns:
    e1, e2 = [], []
    for _ in range(30):                         # প্রতিটি n-এ ৩০টি run
        xy = rng.random((n, 2))
        e1.append(4 * np.mean((xy**2).sum(axis=1) <= 1) - np.pi)
        e2.append(np.mean(rng.poisson(480, size=n) > 520) - cap_exact)
    pi_err.append(np.sqrt(np.mean(np.square(e1))))   # RMS ভুল
    cap_err.append(np.sqrt(np.mean(np.square(e2))))
    print(f"n={n:>7,}  pi RMS err={pi_err[-1]:.4f}  overflow RMS err={cap_err[-1]:.5f}")
print("exact P(orders > 520) =", round(cap_exact, 4))
print("log-log slope:", np.polyfit(np.log10(ns), np.log10(pi_err), 1)[0].round(3),
      np.polyfit(np.log10(ns), np.log10(cap_err), 1)[0].round(3))

xy = rng.random((5_000, 2))
running = 4 * np.cumsum((xy**2).sum(axis=1) <= 1) / np.arange(1, 5_001)
print("running estimate at n = 10, 100, 1000, 5000:", running[[9, 99, 999, 4999]].round(4))
fig, (a1, a2) = plt.subplots(1, 2, figsize=(7, 3.2), layout="constrained")
a1.loglog(ns, pi_err, "o-", label="pi")
a1.loglog(ns, cap_err, "s-", label="P(overflow)")
a1.loglog(ns, 1.64 / np.sqrt(ns), "k--", label="1.64/sqrt(n)")
a1.set_xlabel("n (samples)"); a1.set_ylabel("RMS error"); a1.legend(fontsize=8)
a2.plot(np.arange(1, 5_001), running); a2.axhline(np.pi, color="k", ls="--")
a2.set_xscale("log"); a2.set_xlabel("n"); a2.set_ylabel("running estimate of pi")
a2.set_title("Law of large numbers")
plt.show()

আসল আউটপুট:

n=    100  pi RMS err=0.1539  overflow RMS err=0.02363
n=  1,000  pi RMS err=0.0485  overflow RMS err=0.00522
n= 10,000  pi RMS err=0.0157  overflow RMS err=0.00191
n=100,000  pi RMS err=0.0064  overflow RMS err=0.00045
exact P(orders > 520) = 0.0336
log-log slope: -0.464 -0.559
running estimate at n = 10, 100, 1000, 5000: [3.2    3.08   3.168  3.1432]

π-এর RMS ভুল 0.1539, 0.0485, 0.0157, 0.0064; তত্ত্বের 1.64/√n দেয় 0.164, 0.052, 0.016, 0.0052. প্রতিটি ধাপে n ১০ গুণ, আর ভুল প্রায় √10 ≈ 3.2 গুণ কম। log-log ছবিতে তিনটি রেখাই প্রায় সমান্তরাল, আর মাপা ঢাল −0.464 আর −0.559, তত্ত্বের −0.5-এর কাছে; ৩০টি run-এর গড় বলে ঢাল ঠিক −0.5 আসেনি। ক্ষমতা ছাড়ানোর সঠিক সম্ভাবনা 0.0336, মানে প্রায় ৩০ দিনে একবার; তার RMS ভুল 0.0236 থেকে 0.00045, তত্ত্বের √(0.0336 × 0.9664/n) ≈ 0.18/√n-এর (0.018, 0.0057, 0.0018, 0.00057) কাছাকাছি। লক্ষ করুন, n = 100-এ ভুল (0.024) উত্তরের (0.034) প্রায় সমান: বিরল ঘটনার সম্ভাবনা মাপতে অনেক বেশি নমুনা লাগে। ডানের ছবিতে চলতি অনুমান শুরুতে লাফায় (n = 10-এ 3.2), তারপর π-এর ড্যাশ রেখার চারপাশে ক্রমশ সরু হয়ে স্থির হয় (n = 5,000-এ 3.1432). অন্য seed-এ সংখ্যা বদলাবে, প্রবণতা নয়।

Law of large numbers সহজ ভাষায়: একই distribution থেকে স্বাধীন নমুনা যত বাড়ে, নমুনার গড় তত distribution-এর expected value-এর কাছে যায় (যদি expected value থাকে; অংশ ৭-এর ভারী লেজের সতর্কতা মনে রাখুন)। এটি বলে না যে ভুলগুলো “শোধ” হয়: ১০টি বিন্দুর পর অনুমান কম ছিল বলে পরের বিন্দুগুলো ভেতরে পড়ার সম্ভাবনা বাড়ে না, যা জুয়াড়ির ভুল ধারণা (gambler's fallacy). আগের ভুল শুধু অনেক নতুন নমুনায় “পাতলা” হয়ে যায়। আর নমুনার গড় কতটা ছড়ায় ও কেন তার distribution প্রায় normal হয়, সেই Central Limit Theorem আসবে পর্ব ৩৭-এ।

পুনরুৎপাদনের নিয়ম পর্ব ১৬-এর মতোই: একটি rng = np.random.default_rng(seed) বানিয়ে সব জায়গায় সেটিই পাঠান, scipy-র rvs-এ random_state=rng, আর pandas-এর sample-এও একটি পূর্ণসংখ্যা বা Generator. Seed-এর পাশে NumPy আর SciPy-র version লিখে রাখুন (পর্ব ১২), আর একটি seed-এর ফল নয়, কয়েকটি seed-এ ফলের ছড়ানো রিপোর্ট করুন।

আরও গভীরে। Poisson যে binomial-এর সীমা, তার প্রমাণ কয়েক লাইনের: C(n, k)(λ/n)k(1 − λ/n)n − k-এ n → ∞ হলে C(n, k)/nk → 1/k!, (1 − λ/n)n → e−λ, আর (1 − λ/n)−k → 1; গুণ করলে e−λλk/k!. পার্থক্য কত ছোট, তার একটি সীমাও জানা (Le Cam-এর অসমতা: মোট পার্থক্য np2-এর সমানুপাতিক সীমার মধ্যে)। আরেকটি কৌশল inverse transform: U uniform হলে ppf(U)-এর distribution ঠিক সেই distribution, মানে ppf দিয়ে যেকোনো distribution থেকে নমুনা তোলা যায়।

পরীক্ষা ও ইন্টারভিউতে (বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় এ ধরনের প্রশ্ন সাধারণ):

  • n = 10, p = 0.1 binomial-এ P(X = 0) কত? 0.910 ≈ 0.3487; গড় np = 1, variance np(1 − p) = 0.9.
  • Poisson(λ = 3)-এ P(X = 0)? e−3 ≈ 0.0498; Poisson-এর গড় আর variance দুটিই λ.
  • Continuous X-এ P(X = 2) কত, আর PDF-এর মান 1-এর বেশি হতে পারে কি? 0; হ্যাঁ, কারণ PDF ঘনত্ব, সম্ভাবনা নয়, শুধু মোট ক্ষেত্রফল 1.
  • μ = 500, σ = 40-এর normal-এ P(X > 580)? z = 2, তাই 1 − 0.9772 ≈ 0.0228, প্রায় ২.৩%.
  • Stratified sampling কখন simple random-এর চেয়ে ভালো? যখন স্তরগুলো আলাদা আচরণ করে বা কিছু স্তর ছোট; প্রতিটি স্তরের ভাগ নিশ্চিত থাকে, অনুমানের ছড়ানো কমে।

১০ · AI-এর যুগে — distribution আর simulation-এর কোড যাচাই

“অর্ডারের ডেটা থেকে একটি distribution fit করো” বা “ক্ষমতা ছাড়ানোর সম্ভাবনা simulate করো” লিখলে AI সহকারী দ্রুত কোড আর আত্মবিশ্বাসী সংখ্যা দেবে। এই বিষয়ে তাদের সাধারণ ভুলগুলো:

  • পুরোনো বা বানানো API: np.random.seed আর np.random.poisson-এর global পথ; NumPy 2-এ সরানো np.float; pandas-এর সরানো append; আর এমন parameter যা নেই, যেমন stats.norm(mean=500, sd=40) (আসল নাম loc আর scale). stats.uniform(a, b)-কে [a, b] ভাবা আরেকটি পরিচিত ভুল।
  • Parameter-এর সংজ্ঞা গুলিয়ে ফেলা: exponential-এ scale=λ লেখা, অথচ scale = 1/λ; geometric শুরু 0 না 1 থেকে, তা না দেখা।
  • সব কিছুকে normal ধরা: skewed মূল্যের ডেটায় μ ± 2σ দিয়ে “সীমা” বলা, ঋণাত্মক সময় বা দামকে সম্ভব বানানো।
  • Plausible কিন্তু ভুল পরিসংখ্যান: continuous-এ pdf(x)-কে সম্ভাবনা বলা; এক দিকের আর দুই দিকের ৯৫% (1.645 বনাম 1.96) গুলিয়ে ফেলা; অল্প trial-এর Monte Carlo ফল ভুলের মাপ ছাড়া দেওয়া।
  • Sampling-এ ফাঁক: পুরো ডেটা দেখে distribution বা scaling ঠিক করে তারপর train/test ভাগ (data leakage), train ডেটাতেই মাপা ফল দেখানো, আর পক্ষপাতদুষ্ট নমুনা থেকে population-এর দাবি।

প্রশ্ন করার সময় মডেল, parameter-এর অর্থ আর যাচাইয়ের উপায় নিজেই বলে দিন। নিচের প্রম্পটে আসল ক্রেতার ডেটা নেই।

আমি Python 3.14, NumPy 2.x আর SciPy 1.18 ব্যবহার করছি। বাজারঘর নামের একটি কাল্পনিক দোকানে দৈনিক অর্ডার মোটামুটি Poisson, গড় 480; গুদামের ক্ষমতা দিনে 520. ১. scipy.stats দিয়ে P(অর্ডার > 520)-এর সঠিক মান বের করো। কোন method (cdf, sf, ppf) কেন, এক লাইনে বলো। ২. একই সম্ভাবনা Monte Carlo দিয়ে অনুমান করো: np.random.default_rng(42) একবার বানিয়ে সব জায়গায় পাঠাবে, legacy np.random.seed নয়। ৩. n = 1,000, 10,000, 100,000-এ অনুমান, সঠিক মান থেকে দূরত্ব আর standard error √(p(1−p)/n) ছাপাও। ৪. ধরে নেওয়া প্রতিটি শর্ত (স্বাধীনতা, স্থির হার) আলাদা করে লেখো, আর কোন বাস্তব অবস্থায় এগুলো ভাঙতে পারে বলো। ৫. কোনো parameter-এর নাম বা অর্থ নিয়ে নিশ্চিত না হলে বলো, বানিয়ে লিখবে না। কোনো warning চাপা দেবে না।

AI-এর কোড হাতে পেলে — যাচাইয়ের চেকলিস্ট

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

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

প্র ০১Normal distribution-কে “normal” বলা হয় কেন, আর এই নামটি কীভাবে বিভ্রান্ত করতে পারে?

বক্ররেখাটির ইতিহাস শুরু হয় জুয়ার হিসাব থেকে। ১৭৩৩ সালের দিকে Abraham de Moivre দেখান, অনেকবার মুদ্রা ছুড়লে মাথার সংখ্যার binomial সম্ভাবনাগুলো একটি মসৃণ ঘণ্টার মতো বক্ররেখার খুব কাছে থাকে। উনিশ শতকের শুরুতে Carl Friedrich Gauss জ্যোতির্বিজ্ঞানের মাপের ভুল বিশ্লেষণে একই বক্ররেখা ব্যবহার করেন (তাঁর ১৮০৯ সালের একটি বিখ্যাত কাজে), আর Pierre-Simon Laplace দেখান যে অনেক ছোট স্বাধীন ভুলের যোগফল এই আকার নেয়, যা পরে Central Limit Theorem নামে পরিচিত হয়। তাই একে Gaussian distribution-ও বলে।

“Normal” নামটি জনপ্রিয় হয় উনিশ শতকের শেষে; Francis Galton আর Karl Pearson-এর লেখায় শব্দটি প্রচলিত হয় বলে সাধারণত উল্লেখ করা হয়, যদিও প্রথম কে ব্যবহার করেন, তা নিয়ে সূত্রভেদে মত আলাদা। তার আগে Adolphe Quetelet মানুষের উচ্চতা আর বুকের মাপের মতো ডেটায় এই বক্ররেখা দেখে “গড় মানুষ” (l'homme moyen) ধারণা প্রচার করেন, যেন গড় থেকে সরে যাওয়া একরকম “ভুল”। নামটির দাম এখানেই: এটি বোঝায় যেন এই আকারই স্বাভাবিক, আর বাকি সব অস্বাভাবিক। Pearson নিজেও পরে লিখেছিলেন (বহুল উদ্ধৃত, তবে উদ্ধৃতির ভাষা উৎসভেদে একটু আলাদা) যে নামটির অসুবিধা হলো মানুষ ধরে নেয় অন্য distribution “abnormal”.

বাস্তবে অর্ডারের মূল্য, ডেলিভারির সময়, আয়, ওয়েবসাইটে কাটানো সময় সবই প্রায়ই skewed, আর অংশ ৭-এ দেখেছেন normal ধরলে লেজের ঝুঁকি কত কম দেখায়। আবার normal-এর কদরও যুক্তিসংগত: অনেক স্বাধীন প্রভাবের যোগফল বা গড় প্রায়ই normal-এর কাছে থাকে (পর্ব ৩৭-এ CLT), আর তার গণিত সহজ। তাই নিয়মটি “সব normal” নয়, “গড় আর যোগফল প্রায়ই normal-এর কাছে, একক মাপগুলো প্রায়ই নয়”।

মূল উপলব্ধি: Normal একটি দরকারি মডেল, প্রকৃতির নিয়ম নয়; নামটি “স্বাভাবিক” বললেও প্রতিটি ডেটায় আগে আকার দেখে তবেই তাকে বসাতে হয়।

প্র ০২ঘোড়ার লাথিতে সৈন্যের মৃত্যু থেকে টেলিফোন এক্সচেঞ্জ: Poisson distribution কীভাবে এত কাজের হলো, আর তার সীমা কোথায়?

Siméon Denis Poisson ১৮৩৭ সালে আদালতের রায়ের সম্ভাবনা নিয়ে একটি বইয়ে binomial-এর সীমা হিসেবে এই distribution বের করেন, অংশ ৫-এ যে যুক্তি দেখেছেন। কয়েক দশক এটি তেমন ব্যবহার হয়নি। এর খ্যাতি আসে ১৮৯৮ সালে, যখন Ladislaus Bortkiewicz “ছোট সংখ্যার নিয়ম” (Das Gesetz der kleinen Zahlen) নামে একটি বইয়ে দেখান, প্রুশিয়ান সেনাবাহিনীর কয়েকটি অশ্বারোহী দলে প্রায় ২০ বছরে ঘোড়ার লাথিতে বছরে মৃত্যুর সংখ্যা Poisson-এর সঙ্গে চমৎকার মেলে। প্রতিটি সৈন্যের জন্য ঘটনাটি অত্যন্ত বিরল, কিন্তু সৈন্য অনেক: ঠিক “অনেক সুযোগ, প্রতিটি বিরল” পরিস্থিতি।

বিশ শতকের শুরুতে ডেনমার্কের প্রকৌশলী A. K. Erlang টেলিফোন এক্সচেঞ্জে কতগুলো লাইন লাগবে, তা হিসাব করতে কলের আগমনকে Poisson আর কলের দৈর্ঘ্যকে exponential ধরেন। সেখান থেকে queueing theory-র জন্ম, যা আজও কল সেন্টারের কর্মী সংখ্যা, সার্ভারের ক্ষমতা আর ব্যাংকের কাউন্টারের পরিকল্পনায় ব্যবহার হয়। বাজারঘরের গুদামের ক্ষমতার প্রশ্নও (অংশ ৯) একই পরিবারের।

সীমা দুটি বড়। এক, হার স্থির ধরা: বাস্তবে অর্ডারের হার সকালে কম, রাতে বেশি, ঈদের আগে বহু গুণ। সমাধান হলো সময় ভাগ করে আলাদা λ, বা হার নিজেই সময়ের function (non-homogeneous Poisson). দুই, স্বাধীনতা: একটি ভাইরাল পোস্টের পর অর্ডারগুলো একে অন্যকে টেনে আনে, তখন variance গড়ের অনেক বেশি (overdispersion). তখন Poisson ভিড়ের দিনগুলোকে প্রায় অসম্ভব বলবে, আর গুদাম প্রস্তুত থাকবে না। যাচাইয়ের সহজ উপায়: ডেটার গড় আর variance পাশাপাশি দেখা।

মূল উপলব্ধি: Poisson “বিরল কিন্তু অনেক সুযোগ” ঘটনার শক্তিশালী মডেল; তবে তার এক parameter (λ) গড় আর variance দুটিই বেঁধে দেয়, তাই ডেটায় variance গড়ের চেয়ে অনেক বড় হলে তা ভুল সংকেত।

প্র ০৩২৪ লাখ উত্তরের একটি জরিপ ভুল আর অনেক ছোট একটি জরিপ ঠিক: নমুনার আকার আর নমুনার সততার মধ্যে কোনটি বেশি জরুরি?

১৯৩৬ সালের মার্কিন প্রেসিডেন্ট নির্বাচনের আগে Literary Digest পত্রিকা প্রায় এক কোটি মানুষকে ভোটের কার্ড পাঠায় আর প্রায় ২৪ লাখ উত্তর পায়। পূর্বাভাস ছিল Alf Landon জিতবেন। ফল হলো উল্টো: Franklin D. Roosevelt বিপুল ব্যবধানে জেতেন। একই সময়ে George Gallup-এর মতো জরিপকারীরা অনেক ছোট কিন্তু পরিকল্পিত নমুনা দিয়ে Roosevelt-এর জয় ঠিকভাবে বলেছিলেন বলে সাধারণত উল্লেখ করা হয়।

কেন বড় জরিপটি ভুল? প্রচলিত ব্যাখ্যা: ঠিকানার তালিকা নেওয়া হয়েছিল টেলিফোন বই, গাড়ির নিবন্ধন আর পত্রিকার গ্রাহক থেকে, মহামন্দার সময়ে যাঁরা তুলনামূলক সচ্ছল ছিলেন। পরের কিছু বিশ্লেষণ বলে, বড় কারণ ছিল non-response: যাঁরা কার্ড ফেরত দিয়েছেন, তাঁরা Landon-এর সমর্থকদের মধ্যে বেশি ছিলেন। কোন কারণ কতটা দায়ী, তা নিয়ে গবেষকদের মধ্যে আলোচনা আছে; তবে মূল শিক্ষায় সবাই একমত।

দ্বিতীয় বিশ্বযুদ্ধের একটি গল্পও প্রায়ই বলা হয়: গণিতবিদ Abraham Wald নাকি দেখান, ফিরে আসা যুদ্ধবিমানের যেখানে গুলির দাগ কম, সেখানেই বর্ম দরকার, কারণ সেখানে গুলি খাওয়া বিমানগুলো ফেরেনি। Wald সত্যিই Statistical Research Group-এ বিমানের ক্ষতি নিয়ে বিশ্লেষণ লিখেছিলেন, তবে জনপ্রিয় গল্পের নাটকীয় খুঁটিনাটি পরে অনেকটা অলংকৃত হয়েছে বলে ইতিহাসবিদরা সতর্ক করেন। Survivorship bias-এর ধারণাটি তবু খাঁটি।

গাণিতিক কারণটি সহজ। Random নমুনার ভুল কমে 1/√n হারে, কিন্তু পক্ষপাত (bias) n-এর সঙ্গে কমে না। অংশ ৮-এর review-এর উদাহরণে দশ লাখ review-এর গড়ও 4.36-এই থাকে, 3.6-এ নামে না। বড় পক্ষপাতদুষ্ট নমুনা শুধু ভুল উত্তরকে আরও আত্মবিশ্বাসী করে। “বড় ডেটা”-র যুগে এটি আরও জরুরি: অ্যাপের লগ বা ক্লিকের ডেটা বিশাল, কিন্তু কারা সেখানে আছেন, তা random নয়।

মূল উপলব্ধি: নমুনার আকার শুধু random ভুল কমায়; নমুনায় কে ঢুকল, সেই প্রক্রিয়ার পক্ষপাত কোনো আকারেই দূর হয় না, তাই আগে “কীভাবে নমুনা তোলা হলো” প্রশ্নটি করুন।

প্র ০৪সুঁই ফেলে π মাপা থেকে আধুনিক simulation: Monte Carlo-র ফল কখন বিশ্বাস করবেন, আর কখন সন্দেহ?

Random পরীক্ষা দিয়ে π অনুমানের সবচেয়ে পুরোনো পরিচিত উদাহরণ Buffon-এর সুঁই। Comte de Buffon আঠারো শতকে প্রশ্ন তোলেন: সমান্তরাল রেখা টানা মেঝেতে একটি সুঁই ফেললে তা কোনো রেখা ছোঁয়ার সম্ভাবনা কত (প্রশ্নটি ১৭৩৩ সালে উত্থাপিত আর সমাধান ১৭৭৭ সালে প্রকাশিত বলে সাধারণত উল্লেখ করা হয়)। উত্তরে π থাকে, তাই অনেকবার সুঁই ফেলে উল্টো দিকে π অনুমান করা যায়। ১৯০১ সালে Mario Lazzarini নামের একজন ইতালীয় গণিতবিদ প্রায় ৩,৪০০ বার সুঁই ফেলে π-এর মান 355/113 (ছয় দশমিক ঘর পর্যন্ত ঠিক) পেয়েছেন বলে দাবি করেন। পরের বিশ্লেষকরা দেখান, এত কম চেষ্টায় এমন নির্ভুলতা 1/√n নিয়মে প্রায় অসম্ভব, আর সুঁইয়ের দৈর্ঘ্য ও থামার মুহূর্ত বেছে নিলে ফলটি সাজানো যায়। ঠিক কী হয়েছিল, তা অনিশ্চিত।

আধুনিক Monte Carlo-র জন্ম ১৯৪০-এর দশকে Los Alamos-এ, Ulam, von Neumann আর Metropolis-এর কাজে (পর্ব ১৬-এর ভাবনার প্রশ্নে বিস্তারিত)।

বিশ্বাসের তিনটি শর্ত। এক, ভুলের মাপ: ফলের সঙ্গে n আর standard error, আর পারলে কয়েকটি seed-এ ছড়ানো; অংশ ৯-এ ১০,০০০ বিন্দুর একটি run ৩.১৬ দিয়েছে, আর একটি run দেখে তৃতীয় দশমিক ঘরে ভরসা করা যায় না। দুই, যাচাইযোগ্য ছোট ক্ষেত্র: যেখানে সঠিক উত্তর জানা (Poisson-এর sf), সেখানে simulation মেলে কি না; না মিললে বাগ। তিন, মডেলের শর্ত: simulation শুধু হিসাবের ভুল কমায়। অর্ডার যদি আসলে Poisson না হয়, এক কোটি নমুনাও ভুল প্রশ্নের নিখুঁত উত্তর দেবে। Lazzarini-র ঘটনা আরেকটি সতর্কতা যোগ করে: কখন থামবেন, তা ফল দেখে ঠিক করলে ফল সাজানো হয়ে যায়।

মূল উপলব্ধি: Monte Carlo-র ফল একটি অনুমান, যার বিশ্বাসযোগ্যতা আসে ভুলের মাপ, জানা উত্তরের সঙ্গে যাচাই আর আগে থেকে ঠিক করা n থেকে; “দারুণ মিলে গেছে” ফল অল্প নমুনায় এলে বরং সন্দেহ করুন।

প্র ০৫ভারী লেজের distribution-এ গড় আর standard deviation কেন বিভ্রান্ত করে, আর ঝুঁকির হিসাবে এর মানে কী?

উনিশ শতকের শেষে Vilfredo Pareto সম্পদের বণ্টন নিয়ে কাজ করতে গিয়ে লক্ষ করেন, অল্প কিছু মানুষের হাতে মোট সম্পদের বড় অংশ, আর বণ্টনের ওপরের দিকটি একটি নির্দিষ্ট গাণিতিক আকার (power law) মেনে চলে। এই ধরনের distribution-এ লেজ normal-এর মতো দ্রুত সরু হয় না; চরম মান “প্রায় অসম্ভব” নয়, নিয়মিত। ১৯৬৩ সালে Benoit Mandelbrot তুলার দামের পরিবর্তন নিয়ে একটি প্রবন্ধে যুক্তি দেন যে দামের পরিবর্তনের লেজ normal-এর চেয়ে অনেক ভারী। তারপর থেকে আর্থিক ডেটার লেজ কতটা ভারী, কোন মডেল ঠিক, তা নিয়ে গবেষণা আর বিতর্ক চলছে; এই পর্ব সেখানে কোনো সংখ্যা দাবি করে না।

গড় আর σ কেন বিভ্রান্ত করে? normal-এ ৩σ-এর বাইরে প্রায় ০.৩% মান, আর ৫σ-এর বাইরে প্রায় ১৭ লাখ ভাগের এক ভাগ। ভারী লেজের ডেটায় একই σ দিয়ে হিসাব করলে চরম ঘটনাকে বহু গুণ কম সম্ভব দেখায়। দ্বিতীয় সমস্যা, নমুনার σ নিজেই অস্থির: একটি বড় মান এলেই σ লাফিয়ে বাড়ে, তাই “গত এক বছরের σ” পরের বছরের ঝুঁকি ভালো বলে না। চরম ক্ষেত্রে (তাত্ত্বিক Cauchy distribution) গড়ই সংজ্ঞায়িত নয়: নমুনা যত বাড়ুক, নমুনার গড় স্থির হয় না, মানে law of large numbers কাজ করে না, আর Monte Carlo-র 1/√n নিয়মও না।

বাজারঘরের মতো ব্যবসায় এর ব্যবহারিক রূপ: মাসের মোট বিক্রির বড় অংশ হয়তো কয়েকটি পাইকারি অর্ডার থেকে, তাই “গড় অর্ডার মূল্য” বাড়ল কি কমল, তা একটি-দুটি অর্ডারেই উল্টে যেতে পারে। সৎ অভ্যাস: median আর উচ্চ percentile (৯৫, ৯৯) আলাদা করে দেখা, চরম মান বাদ না দিয়ে আলাদা বিশ্লেষণ, আর “normal ধরে নিলাম” কথাটি স্পষ্ট লেখা।

মূল উপলব্ধি: ভারী লেজে চরম মানই গল্পের বড় অংশ; গড় আর σ সেখানে ঝুঁকি কম দেখায়, তাই লেজকে আলাদা করে মাপুন আর normal-এর ধারণা প্রকাশ্যে লিখুন।

অনুশীলন

প্রথমটি হাতে হিসাবের, দ্বিতীয়টি আউটপুট অনুমানের, তৃতীয়টি নকশা ও সমালোচনার, শেষটি কোড লিখে simulation-এর।

  1. হাতে হিসাব: (ক) একটি দিনে ফেরত আসা অর্ডার X-এর PMF: P(0) = 0.5, P(1) = 0.3, P(2) = 0.2. E[X], Var(X) আর σ বের করুন। (খ) ৫টি অর্ডারের প্রতিটি ০.২ সম্ভাবনায় ফেরত আসে (স্বাধীনভাবে); ঠিক ২টি ফেরত আসার সম্ভাবনা? (গ) ঘণ্টায় অর্ডার Poisson, λ = 2; এক ঘণ্টায় ১টি বা তার কম অর্ডারের সম্ভাবনা? (ঘ) ডেলিভারির সময় normal, μ = 48 ঘণ্টা, σ = 8; ৪০ ঘণ্টার কম লাগার সম্ভাবনা?

    (ক) E[X] = 0 × 0.5 + 1 × 0.3 + 2 × 0.2 = 0.7. E[X2] = 0 + 0.3 + 0.8 = 1.1, তাই Var = 1.1 − 0.49 = 0.61, σ = √0.61 ≈ 0.781.

    (খ) C(5, 2) × 0.22 × 0.83 = 10 × 0.04 × 0.512 = 0.2048.

    (গ) P(0) + P(1) = e−2(1 + 2) = 3 × 0.1353 ≈ 0.4060.

    (ঘ) z = (40 − 48)/8 = −1, তাই P = Φ(−1) ≈ 0.1587, মানে প্রায় ১৬%. লক্ষ করুন, ৬৮–৯৫–৯৯.৭ নিয়ম থেকেও আসে: ±1σ-এর বাইরে ৩২%, তার অর্ধেক নিচের দিকে।

    লেখকের যন্ত্রে SciPy 1.18.0 দিয়ে মেলানো: binom(5, 0.2).pmf(2) = 0.2048, poisson(2).cdf(1) ≈ 0.4060, norm(48, 8).cdf(40) ≈ 0.1587.

  2. আউটপুট অনুমান করুন: চালানোর আগে প্রতিটি লাইনের আউটপুট লিখুন, তারপর যেকোনো ব্লকে বসিয়ে মিলিয়ে দেখুন।
    from scipy import stats
    B = stats.binom(4, 0.5)
    print(B.pmf(2), B.cdf(1), stats.norm.cdf(0), stats.norm.ppf(0.5))
    print(stats.poisson(2).var(), stats.expon(scale=5).mean(), stats.uniform(2, 4).mean())
    0.375 0.3125 0.5 0.0
    2.0 5.0 4.0

    প্রথম লাইন: C(4, 2)/16 = 6/16 = 0.375; cdf(1) = (1 + 4)/16 = 0.3125; standard normal-এর অর্ধেক ক্ষেত্রফল ০-এর বাঁয়ে, তাই 0.5, আর তার উল্টো ppf(0.5) = 0.0. দ্বিতীয় লাইন: Poisson-এর variance = λ = 2.0; expon(scale=5)-এর গড় 5.0, কারণ scale = 1/λ, মানে গড় অপেক্ষা; আর uniform(2, 4) হলো [2, 6], তাই গড় 4.0, 3.0 নয়। শেষ দুটি ফাঁদ AI সহকারীর কোডেও প্রায়ই দেখা যায় (লেখকের যন্ত্রে মেলানো, SciPy 1.18.0).

  3. নকশা ও সমালোচনা: বাজারঘরের মার্কেটিং দল একটি রিপোর্টে লিখেছে: “আমাদের অ্যাপের ১২,০০০ review-এর গড় রেটিং ৪.৬, তাই ৯০%-এর বেশি ক্রেতা সন্তুষ্ট। নতুন ডেলিভারি নিয়মটি যাচাই করতে আমরা ঢাকার সবচেয়ে সক্রিয় ১০০ জন ক্রেতাকে ফোন করব।” অন্তত চারটি সমস্যা চিহ্নিত করে একটি ভালো জরিপের নকশা দিন।
    • Sampling bias: review লেখেন একটি নিজে-বাছা দল (self-selection); অংশ ৮-এর হিসাবে দেখেছেন, সত্যিকারের গড় 3.6 হলেও review-এর গড় 4.36 হতে পারে। ১২,০০০ সংখ্যাটি পক্ষপাত কমায় না।
    • ভুল উপসংহার: “গড় ৪.৬” থেকে “৯০% সন্তুষ্ট” আসে না; গড় আর ভাগ দুটি আলাদা সারাংশ, আর রেটিং skewed হতে পারে। পুরো distribution (১★ থেকে ৫★-এর ভাগ) দেখান।
    • Survivorship: যাঁরা অসন্তুষ্ট হয়ে অ্যাপ মুছে ফেলেছেন, তাঁরা review দেননি, ফোনের তালিকাতেও নেই।
    • সুবিধার নমুনা: শুধু ঢাকা, শুধু সবচেয়ে সক্রিয় ক্রেতা; নতুন নিয়ম যাঁদের সবচেয়ে বেশি প্রভাবিত করবে (দূরের জেলা), তাঁরা বাদ।
    • আকার আর ভুলের মাপ নেই: ১০০ জনে একটি অনুপাতের standard error প্রায় √(0.5 × 0.5/100) = 0.05, মানে ±১০ শতাংশ বিন্দুর মতো অনিশ্চয়তা।

    ভালো নকশা: population = গত তিন মাসে অর্ডার দেওয়া সব ক্রেতা (review দিন বা না দিন)। জেলা দিয়ে stratify করে প্রতিটি জেলা থেকে অনুপাতে random নমুনা (groupby("district").sample(frac=..., random_state=rng)), ছোট জেলায় প্রয়োজনে একটু বেশি (তখন বিশ্লেষণে ওজন দিয়ে ঠিক করা)। যাঁরা উত্তর দেননি, তাঁদের সংখ্যা আর বৈশিষ্ট্য রিপোর্টে রাখা; ফলাফল দিন অনুপাত আর তার standard error সহ, আর প্রশ্ন ও বিশ্লেষণের পরিকল্পনা জরিপের আগেই লিখে রাখুন।

  4. কোড লিখে simulation: বাজারঘরের দৈনিক অর্ডার ঢাকায় Poisson(300) আর চট্টগ্রামে Poisson(120), দুটি স্বাধীন; একটি যৌথ গুদাম দিনে ৪৫০টি সামলাতে পারে। default_rng(42) দিয়ে ২,০০,০০০টি দিন simulate করে মোট অর্ডার ৪৫০ ছাড়ানোর সম্ভাবনা অনুমান করুন, standard error সহ। তুলনার জন্য: স্বাধীন দুটি Poisson-এর যোগ নিজেও Poisson, λ = 300 + 120 = 420.
    import math
    import numpy as np
    from scipy import stats
    rng = np.random.default_rng(42)
    n = 200_000
    total = rng.poisson(300, size=n) + rng.poisson(120, size=n)
    p_hat = np.mean(total > 450)
    exact = stats.poisson(420).sf(450)
    se = math.sqrt(exact * (1 - exact) / n)
    print(round(float(p_hat), 4), round(float(exact), 4), round(se, 4))

    লেখকের যন্ত্রে সত্যিকারের run (Python 3.14.4, NumPy 2.5.1, SciPy 1.18.0): 0.0697 0.0696 0.0006. অনুমান 0.0697 আর সঠিক মান 0.0696, পার্থক্য 0.0001, যা SE 0.0006-এর অনেক ভেতরে। sf(450) মানে P(মোট > 450), কারণ sf(x) = 1 − cdf(x) = P(X > x); “৪৫০ বা বেশি” চাইলে sf(449). মডেলের সতর্কতা: দুই জেলার অর্ডার একই দিনে একসঙ্গে বাড়ে (ছুটি, বৃষ্টি), তাই বাস্তবে তারা পুরো স্বাধীন নয়, আর তখন ক্ষমতা ছাড়ানোর সম্ভাবনা এর চেয়ে বেশি হতে পারে।

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

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

ক্রমগুদামের ক্ষমতা ছাড়ানোর সম্ভাবনা simulation দিয়ে অনুমানের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. 🎯 প্রশ্ন আর মডেল ঠিক করা: দৈনিক অর্ডার Poisson(λ), ক্ষমতা কত, “ছাড়ানো” মানে > না ≥
  2. 🌱 একবার rng = np.random.default_rng(seed) বানানো
  3. 🎲 X.rvs(size=n, random_state=rng) দিয়ে n-টি কাল্পনিক দিন তোলা
  4. ⚖️ প্রতিটি দিন ক্ষমতার সঙ্গে তুলনা করে True/False আর তাদের গড়
  5. 📏 √(p(1 − p)/n) দিয়ে ভুলের মাপ আর সম্ভব হলে sf দিয়ে সঠিক মানের সঙ্গে মেলানো
  6. 📝 অনুমান, n, ভুলের মাপ, seed, version আর মডেলের শর্ত একসঙ্গে রিপোর্ট করা

ডেলিভারির সময় T একটি continuous random variable, যার PDF-এর মান t = 2 দিনে 0.45. P(T = 2) কত?

  • 0.45
  • 0.55
  • 0
  • জানা যাবে না, CDF লাগবে

একটি দিনে ২০টি অর্ডার, প্রতিটি আলাদাভাবে ০.১ সম্ভাবনায় ফেরত আসে। ফেরত আসা অর্ডারের সংখ্যার গড় আর variance কত?

  • গড় 2, variance 2
  • গড় 2, variance 1.8
  • গড় 2, variance 1.34
  • গড় 0.1, variance 0.09

কোন অবস্থায় binomial(n, p)-এর বদলে Poisson(λ = np) দিয়ে হিসাব করা সবচেয়ে নিরাপদ?

  • n ছোট, p প্রায় 0.5
  • n বড়, p প্রায় 0.5
  • n ছোট, p ছোট
  • n বড়, p ছোট

scipy.stats-এ stats.norm(500, 40).ppf(0.95) কী দেয়?

  • যে মানের নিচে ৯৫% দিন পড়ে, প্রায় 565.8
  • x = 0.95-এ PDF-এর উচ্চতা
  • P(X ≤ 0.95)
  • ৯৫% দিন যে পরিসরে, 420 থেকে 580

দৈনিক অর্ডার normal, μ = 60, σ = 5. কোনো দিন ৭০-এর বেশি অর্ডার আসার সম্ভাবনা মোটামুটি কত?

  • প্রায় 0.16
  • প্রায় 0.05
  • প্রায় 0.023
  • প্রায় 0.0013

একটি অনলাইন দোকান শুধু যে বিক্রেতারা ৫ বছর ধরে টিকে আছেন, তাঁদের ডেটা দেখে বলল “আমাদের প্ল্যাটফর্মে বিক্রেতারা গড়ে খুব সফল”। এখানে প্রধান সমস্যাটি কী?

  • নমুনা ছোট, তাই random ভুল বেশি
  • Survivorship bias: ব্যর্থ বিক্রেতারা ডেটা থেকে বাদ
  • সাফল্যের ডেটা normal নয়
  • Random seed দেওয়া হয়নি

শব্দকোষ

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

মনে রাখুন

  1. Discrete-এ সম্ভাবনা PMF-এর প্রতিটি মানে, continuous-এ PDF-এর নিচের ক্ষেত্রফলে; continuous-এ ঠিক একটি মানের সম্ভাবনা ০, আর CDF = P(X ≤ x) দুই ধরনেই কাজ করে।
  2. E[X] = ∑ x·P(x), Var(X) = E[X2] − μ2; হাতে হিসাব করুন, তারপর simulation দিয়ে মেলান।
  3. Binomial = n-এর মধ্যে কয়টি হ্যাঁ (np, np(1 − p)); Poisson = হারে ঘটনা (গড় = variance = λ), n বড় আর p ছোট হলে binomial-এর জায়গায়; exponential = অপেক্ষা, স্মৃতিহীন।
  4. Normal-এ z = (x − μ)/σ, ৬৮–৯৫–৯৯.৭ নিয়ম, cdf/sf/ppf; কিন্তু মূল্য আর সময়ের মতো ডেটা প্রায়ই skewed বা ভারী লেজের, তাই আগে ডেটার আকার দেখুন।
  5. নমুনার সততা আকারের চেয়ে জরুরি: stratified sampling স্তরের ভাগ ঠিক রাখে, পক্ষপাত n বাড়ালেও কমে না; Monte Carlo-র ভুল কমে 1/√n হারে, তাই ফলের সঙ্গে n, SE আর seed দিন।

পরের পর্বে: ডেটার পরিসংখ্যান। Mean, variance আর correlation দিয়ে ডেটার সারাংশ, standard error, আর Central Limit Theorem: কেন নমুনার গড় প্রায় normal হয়, এমনকি ডেটা skewed হলেও; তারপর confidence interval আর p-value সহজ ভাষায়, তাদের সাধারণ ভুল ব্যাখ্যাসহ।

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

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