এই পর্বে যা শিখবেন
- Multivariate Gaussian-এর density সূত্রের প্রতিটি পদের মানে, আর হাতে একটি বিন্দুতে হিসাব
- Covariance-এর eigen-decomposition থেকে উপবৃত্তাকার contour, whitening, আর Mahalanobis দূরত্বের χ² বণ্টন দিয়ে outlier ধরা
- Marginal আর conditional Gaussian-এর সূত্র (Schur complement), আর কেন conditional গড় ঠিক regression রেখা
- ডেটা থেকে μ আর Σ-এর MLE, n বনাম n − ১, আর parameter-এর সংখ্যা কত দ্রুত বাড়ে
- LDA আর QDA-কে generative classifier হিসেবে নিজে লেখা, scikit-learn দিয়ে যাচাই, আর Ledoit–Wolf shrinkage কখন লাগে
AI-এর ভিত্তি কোর্সের পর্ব ৩৬-এ এক মাত্রার normal distribution আর Monte Carlo, পর্ব ৩৭-এ covariance, correlation আর z-score এসেছে। এই কোর্সের পর্ব ০৮ প্রতিসম matrix-এর eigen-decomposition দেখিয়েছে, আর পর্ব ১০ দেখিয়েছে covariance কেন PSD, Cholesky দিয়ে x = μ + Lz নমুনা কীভাবে বানাতে হয়, আর Mahalanobis দূরত্বের প্রথম পরিচয়। এই পর্ব সেই টুকরোগুলো জুড়ে পুরো ছবি আঁকে: একসঙ্গে অনেকগুলো সংখ্যার অনিশ্চয়তা কীভাবে একটি বণ্টনে ধরা যায়, আর তা দিয়ে outlier ধরা, অনুমান আর classification কীভাবে হয়। চালানো যায় এমন চারটি ব্লক পাতাতেই চলে (ব্রাউজারের Python: NumPy, SciPy, matplotlib আর scikit-learn); প্রথমবার প্যাকেজ নামতে কয়েক সেকেন্ড লাগে, scikit-learn-এ প্রায় ১০ সেকেন্ড।
১ · এক মাত্রার ঘণ্টা থেকে d মাত্রার পাহাড় — density সূত্র পদে পদে
ঢাকার একটি মানচিত্রে বাজারঘরের হাজারটি ডেলিভারিকে বিন্দু হিসেবে বসান, অক্ষ দুটি “দূরত্ব” আর “সময়”। বিন্দুগুলো একটি হেলানো মেঘ বানাবে: দূরের অর্ডারে সময়ও বেশি। এবার মেঘের ঘনত্বকে উচ্চতা ভাবুন। মাঝখানে উঁচু একটি টিলা, চারদিকে ঢাল, আর সমান উচ্চতার রেখাগুলো হেলানো উপবৃত্ত। এক মাত্রার ঘণ্টা-আকারের normal বক্ররেখা যেন এই টিলার একটি ফালি। Multivariate Gaussian হলো পুরো টিলার একটি সূত্র।
এক মাত্রায় normal distribution-এর density p(x) = (1/(σ√(2π))) · exp(−(x − μ)²/(2σ²)). এখানে μ গড়, σ standard deviation, আর (x − μ)/σ হলো z-score. d মাত্রায় x একটি vector (দৈর্ঘ্য d), μ গড় vector, আর σ²-এর জায়গায় বসে d × d covariance matrix Σ. সূত্রটি:
p(x) = (2π)−d/2 · (det Σ)−1/2 · exp(−½ (x − μ)ᵀ Σ−1 (x − μ))
তিনটি অংশ আলাদা করে পড়ুন। (১) সূচকের ভেতরের রাশি d² = (x − μ)ᵀΣ−1(x − μ) একটি quadratic form, আর এটিই Mahalanobis দূরত্ব-এর বর্গ। এক মাত্রায় এটি ঠিক z² = (x − μ)²/σ². Σ−1-কে বলে precision matrix: covariance যত বড়, ঘনত্ব তত ধীরে কমে। (২) det Σ হলো মেঘের “আয়তনের” মাপ। মেঘ যত ছড়ানো, মোট সম্ভাবনা ১ রাখতে চূড়া তত নিচু হতে হয়, তাই det Σ-এর বর্গমূল দিয়ে ভাগ। (৩) (2π)d/2 শুধু একটি ধ্রুবক, যাতে পুরো জায়গায় ঘনত্বের integral ঠিক ১ হয়। সূত্রটি অর্থবহ হতে Σ-কে positive definite হতে হবে (পর্ব ১০-এর ভাষায়), নইলে Σ−1 আর √det Σ সংজ্ঞায়িত নয়।
পর্ব ১০-এর বাজারঘরের ডেলিভারি আবার নিই: x = (সময়, দূরত্ব), μ = (৩৫ মিনিট, ৬ km), সময়ের standard deviation ১০, দূরত্বের ৩, correlation ০.৭, তাই Σ = [[100, 21], [21, 9]]. একটি অর্ডার (৪৫ মিনিট, ৮ km)-এ density কত?
| ধাপ | |
| হিসাব | |
| সংখ্যায় | |
| মানে |
- সরণ। x − μ = (১০, ২): অর্ডারটি গড়ের চেয়ে ১০ মিনিট ধীর আর ২ km দূরে। দুটিই একই দিকে, যা correlation ০.৭-এর সঙ্গে মানানসই।
- Determinant. ২ × ২-এ ad − bc = ৯০০ − ৪৪১ = ৪৫৯. Correlation না থাকলে এটি ৯০০ হতো; correlation মেঘকে সরু করে আয়তন কমায়।
- Precision matrix. ২ × ২-এর inverse: কর্ণ অদলবদল, বাইরের ঘরের চিহ্ন উল্টো, তারপর det দিয়ে ভাগ। বাইরের ঘর ঋণাত্মক (−০.০৪৫৮), এর মানে পরে অংশ ৪-এ পরিষ্কার হবে।
- সূচক। d² = ৯·১০০ − ২·২১·২০ + ১০০·৪ = ৯০০ − ৮৪০ + ৪০০ = ৪৬০, ভাগ ৪৫৯, ফল ১.০০২. মাঝের −৮৪০ পদটি বলে: দুটি সরণ একই দিকে হওয়ায় “অস্বাভাবিকতা” অনেকটা কাটা গেল।
- ধ্রুবক। d = ২ হলে (2π)1 = ৬.২৮৩২, √৪৫৯ = ২১.৪২৪, গুণফল ১৩৪.৬১. এর উল্টো ০.০০৭৪২৯ হলো চূড়ার উচ্চতা, যা x = μ-তে পাওয়া যায় (তখন exp(০) = ১)।
- ফল। exp(−০.৫০১) = ০.৬০৫৯, তাই p(x) = ০.০০৭৪২৯ × ০.৬০৫৯ = ০.০০৪৫০১. দুটি feature-কে স্বাধীন ধরে দুটি এক মাত্রার density গুণ করলে আসত ০.০২৪২ × ০.১০৬৫ = ০.০০২৫৮, প্রায় অর্ধেক: correlation বাদ দিলে এই “স্বাভাবিক” অর্ডারটিকে অকারণে বিরল মনে হয়।
দুটি সতর্কতা। প্রথমত, density সম্ভাবনা নয়: এর একক “প্রতি মিনিট প্রতি km”, আর ছোট Σ-এ এটি ১-এর বেশিও হতে পারে; সম্ভাবনা আসে কোনো এলাকার ওপর integral থেকে (AI-এর ভিত্তি কোর্সের পর্ব ৩৬-এর PDF-এর মতো)। দ্বিতীয়ত, বড় d-তে det Σ খুব ছোট বা বড় হয়ে underflow বা overflow করতে পারে, তাই বাস্তব কোডে log-density হিসাব করা হয়: log p = −½(d log 2π + log det Σ + d²), আর log det Σ = ২∑ log Lii (Cholesky-র কর্ণ থেকে, পর্ব ১০)।
Gaussian-এর একটি বিশেষ গুণ মনে রাখুন: যৌথভাবে Gaussian হলে correlation শূন্য মানেই স্বাধীন. Σ কর্ণ-matrix হলে exp-এর ভেতরের যোগফল আলাদা আলাদা পদে ভাগ হয়, আর density এক মাত্রার density-গুলোর গুণফল। অন্য বণ্টনে এটি সত্য নয়: x আর x² correlation-হীন হতে পারে, অথচ একটি জানলে অন্যটি পুরো জানা যায়।
২ · Contour মানে উপবৃত্ত — অক্ষ আসে Σ-এর eigenvector থেকে
Density একই থাকে যেখানে d² একই। তাই সমান-উচ্চতার রেখা (contour) হলো d² = c² সমীকরণের সমাধান। পর্ব ০৮-এর spectral theorem অনুযায়ী Σ = VΛVᵀ, যেখানে V-এর কলামগুলো পরস্পর লম্ব একক eigenvector আর Λ-এর কর্ণে eigenvalue λ1, λ2, …. তাহলে Σ−1 = VΛ−1Vᵀ, আর y = Vᵀ(x − μ) লিখলে:
d² = y1²/λ1 + y2²/λ2 + … + yd²/λd
এটি অক্ষ-বরাবর একটি উপবৃত্তের সমীকরণ। y হলো eigenvector-গুলোর দিকে মাপা স্থানাঙ্ক, তাই উপবৃত্তের অক্ষগুলো eigenvector বরাবর, আর d = c রেখায় i-তম অর্ধ-অক্ষের দৈর্ঘ্য c√λi. বড় eigenvalue মানে সেই দিকে ডেটা বেশি ছড়ানো, অক্ষ লম্বা। আরও এক ধাপ: zi = yi/√λi নিলে d² = ‖z‖², সাধারণ দৈর্ঘ্যের বর্গ। এই রূপান্তর z = Λ−1/2Vᵀ(x − μ)-কে বলে whitening: হেলানো উপবৃত্তকে ঘুরিয়ে, প্রতিটি অক্ষ বরাবর চেপে বা টেনে, একটি গোল বৃত্ত বানানো। Mahalanobis দূরত্ব আসলে whitened জগতের সাধারণ দূরত্ব। (পর্ব ১০-এ Cholesky দিয়ে Ly = x − μ আরেক রকম whitening, যার ঘোরানোর ধাপ আলাদা কিন্তু দৈর্ঘ্য একই।)
হেলানো উপবৃত্ত থেকে গোল বৃত্ত — whitening
Σ = [[100, 21], [21, 9]]: λ = 104.6 আর 4.39, তাই √λ = 10.2 আর 2.1 (ছবি মাপমতো নয়)
উপবৃত্তের ভেতরে কত সম্ভাবনা? z-এর উপাদানগুলো স্বাধীন standard normal, তাই d² = z1² + … + zd², যার বণ্টনকে বলে d degree of freedom-এর chi-square, χ²d. ২ মাত্রায় এর একটি সহজ বন্ধ রূপ আছে: P(d² ≤ c²) = 1 − e−c²/2. নিচের ব্লক density সূত্র নিজে লিখে SciPy-র multivariate_normal.pdf-এর সঙ্গে মেলায়, তারপর eigenvector থেকে তিনটি উপবৃত্ত আঁকে।
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
mu = np.array([35.0, 6.0]) # গড়: ৩৫ মিনিট, ৬ km
Sigma = np.array([[100.0, 21.0], [21.0, 9.0]])
def gauss_pdf(x, mu, Sigma): # সূত্রটি হুবহু, পদে পদে
d = len(mu)
diff = x - mu
m2 = diff @ np.linalg.solve(Sigma, diff) # Mahalanobis²
norm = (2 * np.pi) ** (d / 2) * np.sqrt(np.linalg.det(Sigma))
return np.exp(-0.5 * m2) / norm, m2
for x in ([45.0, 8.0], [35.0, 6.0], [55.0, 3.0]):
p, m2 = gauss_pdf(np.array(x), mu, Sigma)
q = multivariate_normal.pdf(x, mean=mu, cov=Sigma)
print(f"x={x}: d²={m2:6.3f} formula={p:.6f} scipy={q:.6f}")
lam, V = np.linalg.eigh(Sigma) # ছোট থেকে বড় eigenvalue
print("eigenvalues:", lam.round(3), "| sqrt:", np.sqrt(lam).round(3))
print("long axis direction:", V[:, 1].round(3))
t = np.linspace(0, 2 * np.pi, 200)
circle = np.stack([np.cos(t), np.sin(t)]) # একক বৃত্ত
fig, ax = plt.subplots(figsize=(6, 4), layout="constrained")
for c in (1, 2, 3): # d = c রেখা: অক্ষ c·√λ
ell = mu[:, None] + V @ (c * np.sqrt(lam)[:, None] * circle)
inside = 1 - np.exp(-c * c / 2) # ২ মাত্রায় ভেতরের সম্ভাবনা
ax.plot(ell[1], ell[0], lw=1.5, label=f"Mahalanobis {c}: {inside:.1%} inside")
for k in (0, 1): # অক্ষ: ±2√λ · eigenvector
a = 2 * np.sqrt(lam[k]) * V[:, k]
ax.plot([mu[1] - a[1], mu[1] + a[1]], [mu[0] - a[0], mu[0] + a[0]], "k--", lw=1)
ax.plot([8, 6, 3], [45, 35, 55], "rx")
ax.set_xlabel("distance (km)"); ax.set_ylabel("delivery time (min)")
ax.set_title("Contours of N(mu, Sigma)"); ax.legend(fontsize=8, loc="lower right")
plt.show()আসল আউটপুট (ব্রাউজারের Python):
x=[45.0, 8.0]: d²= 1.002 formula=0.004501 scipy=0.004501
x=[35.0, 6.0]: d²= 0.000 formula=0.007429 scipy=0.007429
x=[55.0, 3.0]: d²=15.294 formula=0.000004 scipy=0.000004
eigenvalues: [ 4.388 104.612] | sqrt: [ 2.095 10.228]
long axis direction: [-0.977 -0.215]
প্রথম তিন লাইন: নিজের লেখা সূত্র আর SciPy ছয় দশমিক পর্যন্ত হুবহু এক। (৪৫, ৮)-এর উত্তর stepper-এর ০.০০৪৫০১. গড় বিন্দুতে d² = ০ আর density ০.০০৭৪২৯, অর্থাৎ চূড়া। পর্ব ১০-এর “কাছে অথচ ৫৫ মিনিট” অর্ডার (৫৫, ৩)-এর d² = ১৫.২৯, অর্থাৎ d = ৩.৯১, আর density প্রায় শূন্য। Eigenvalue: ৪.৩৮৮ আর ১০৪.৬১২, যোগফল ১০৯ = ১০০ + ৯ (trace), গুণফল ৪৫৯ = det Σ. লম্বা অক্ষের দিক (−০.৯৭৭, −০.২১৫): মূলত সময়ের দিকে, একটু দূরত্বের দিকে হেলানো (চিহ্ন উল্টালেও একই দিক)। ছবিতে তিনটি উপবৃত্তের ভেতরে ৩৯.৩%, ৮৬.৫% আর ৯৮.৯%. ড্যাশ দেওয়া অক্ষ দুটি ছবিতে লম্ব দেখায় না, কারণ দুই অক্ষের একক আলাদা (মিনিট বনাম km); একই মাপে আঁকলে লম্ব। np.linalg.solve দিয়ে d² বের করা হয়েছে, inverse বানিয়ে নয় (পর্ব ১০-এর পরামর্শ)।
৩ · Mahalanobis দূরত্ব আর χ² — কোন অর্ডার সত্যিই অস্বাভাবিক
বাজারঘরের অপারেশন দল প্রতিদিন কয়েকশো অর্ডারের মধ্যে সন্দেহজনকগুলো আলাদা করতে চায়: হয়তো রাইডার ভুল ঠিকানায় গিয়েছিলেন, হয়তো ডেটা এন্ট্রিতে ভুল। প্রচলিত সরল নিয়ম: প্রতিটি feature-এর z-score দেখুন, কোনোটি ৩-এর বেশি হলে চিহ্নিত করুন। এই নিয়ম প্রতিটি feature আলাদা করে দেখে, তাই “কাছে অথচ অনেক দেরি” ধরনের outlier ধরতে পারে না, কারণ সময় আর দূরত্ব দুটিই আলাদাভাবে সাধারণ পরিসরে।
Mahalanobis দূরত্বের সুবিধা: d² = ‖z‖² (অংশ ২), আর ডেটা Gaussian হলে d² ~ χ²d, যার গড় d আর variance 2d. তাই একটি নির্দিষ্ট সম্ভাবনার সীমা টানা যায়, যেমন “সাধারণ অর্ডারের মাত্র ১% এর বাইরে যাবে”। কয়েকটি সীমা (scipy.stats.chi2.ppf থেকে):
| Feature সংখ্যা d | ৯৫% সীমা (d²) | ৯৯% সীমা (d²) | ৯৯% সীমা (d) |
|---|---|---|---|
| ১ | ৩.৮৪ | ৬.৬৩ | ২.৫৮ (z-score-এর পরিচিত সীমা) |
| ২ | ৫.৯৯ | ৯.২১ | ৩.০৩ |
| ৩ | ৭.৮১ | ১১.৩৪ | ৩.৩৭ |
লক্ষ করুন, d বাড়লে সীমাও বাড়ে: তিন মাত্রায় গড় থেকে ৩.৩৭ “Mahalanobis একক” দূরে থাকাও ৯৯% ক্ষেত্রে স্বাভাবিক। প্রতিটি feature-এ ৩ σ নিয়ম এই বৃদ্ধি মানে না। নিচের ব্লকে ৪০০টি কাল্পনিক সাধারণ অর্ডার (সময়, দূরত্ব, ওজন) আর চারটি বিশেষ অর্ডার।
import numpy as np
from scipy.stats import chi2
rng = np.random.default_rng(42) # কাল্পনিক বাজারঘর: ৪০০টি সাধারণ অর্ডার
sd = np.array([10.0, 3.0, 1.5]) # সময় (মিনিট), দূরত্ব (km), ওজন (kg)
R = np.array([[1.0, 0.7, 0.3], [0.7, 1.0, 0.1], [0.3, 0.1, 1.0]])
X = rng.multivariate_normal([35, 6, 3], R * np.outer(sd, sd), size=400)
odd = np.array([[55, 2, 2.5], # A: কাছে, অথচ অনেক দেরি
[20, 12, 3], # B: দূরে, অথচ খুব দ্রুত
[68, 15, 4], # C: দূরে আর ধীর (সামঞ্জস্যপূর্ণ)
[40, 6, 8]]) # D: খুব ভারী পার্সেল
X = np.vstack([X, odd])
mu = X.mean(axis=0)
S = np.cov(X, rowvar=False) # অনুমান করা Σ (n − 1 দিয়ে ভাগ)
D = X - mu
d2 = np.einsum("ij,ij->i", D @ np.linalg.inv(S), D) # প্রতিটি সারির d²
z = np.abs(D / X.std(axis=0, ddof=1)) # feature ধরে আলাদা z-score
cut = chi2.ppf(0.99, df=3) # χ²(3)-এর ৯৯% সীমা
print(f"chi2 99% cutoff for d² (df=3): {cut:.2f}")
print("order d² max|z| Mahalanobis z>3")
for name, i in zip("ABCD", range(400, 404)):
print(f" {name} {d2[i]:6.2f} {z[i].max():5.2f} "
f"{'flag' if d2[i] > cut else '-':^11} {'flag' if z[i].max() > 3 else '-'}")
normal = slice(0, 400)
print("normal orders flagged:", (d2[normal] > cut).sum(), "by d²,",
(z[normal].max(axis=1) > 3).sum(), "by z")
for q in (0.5, 0.9, 0.99): # d²-এর quantile বনাম χ²(3)
print(f"quantile {q}: data {np.quantile(d2[normal], q):5.2f}"
f" | chi2 {chi2.ppf(q, 3):5.2f}")আসল আউটপুট (ব্রাউজারের Python):
chi2 99% cutoff for d² (df=3): 11.34
order d² max|z| Mahalanobis z>3
A 22.12 1.92 flag -
B 22.22 1.88 flag -
C 10.63 3.16 - flag
D 12.05 3.42 flag flag
normal orders flagged: 5 by d², 4 by z
quantile 0.5: data 2.12 | chi2 2.37
quantile 0.9: data 6.09 | chi2 6.25
quantile 0.99: data 12.02 | chi2 11.34
A আর B: প্রতিটি feature-এর z-score ২-এর নিচে (১.৯২ আর ১.৮৮), তাই z-score নিয়মে দুটিই “স্বাভাবিক”; অথচ d² ২২-এর বেশি, সীমার প্রায় দ্বিগুণ। এরা সময় আর দূরত্বের সম্পর্ক ভেঙেছে, অর্থাৎ সরেছে সেই দিকে যেদিকে ডেটা প্রায় নড়ে না (ছোট eigenvalue-এর দিক)। C: উল্টো ঘটনা। দেরি আর দূরত্ব দুটিই বড় (সর্বোচ্চ z = ৩.১৬), কিন্তু একসঙ্গে বড়, যা correlation অনুযায়ী প্রত্যাশিত; d² = ১০.৬৩, সীমার নিচে। z-score নিয়ম একে অকারণে চিহ্নিত করে। D: ওজন একাই চরম, দুই নিয়মই ধরে। সাধারণ অর্ডার: ৪০০-এর ১% মানে প্রত্যাশা ৪টি; d² নিয়মে এসেছে ৫টি। শেষ তিন লাইনে ডেটার d²-এর quantile আর χ²(3)-এর quantile প্রায় মেলে (২.১২ বনাম ২.৩৭, ৬.০৯ বনাম ৬.২৫): Gaussian অনুমান যাচাইয়ের একটি সহজ পরীক্ষা, যা Q-Q plot-এর সংখ্যা-রূপ।
তিনটি ফাঁদ। (১) Masking: μ আর Σ একই ডেটা থেকে অনুমান করা হয়েছে, যেখানে outlier-ও আছে। অনেকগুলো outlier একসঙ্গে থাকলে তারা Σ-কে ফুলিয়ে নিজেদের d² কমিয়ে দেয়, ফলে লুকিয়ে যায়। প্রতিকার robust অনুমান, যেমন Rousseeuw-এর Minimum Covariance Determinant (scikit-learn-এ MinCovDet), যা সবচেয়ে “আঁটসাঁট” অর্ধেক ডেটা থেকে μ আর Σ নেয়। (২) χ² সীমা হুবহু সঠিক শুধু যখন μ আর Σ জানা; অনুমান করলে n ছোট হলে আসল বণ্টন একটু আলাদা (Beta বা F-ভিত্তিক), যদিও কয়েকশো সারিতে পার্থক্য সামান্য। (৩) আসল ডেলিভারি সময় সাধারণত ডানে বাঁকা (দীর্ঘ লেজ), Gaussian নয়; তখন ৯৯% সীমা আসলে অনেক বেশি “মিথ্যা সতর্কতা” দেয়। log রূপান্তর সাহায্য করতে পারে, আর Gaussian ছাড়া পদ্ধতি (isolation forest, LOF) পর্ব ৪৩ (Anomaly detection — isolation forest, LOF আর one-class SVM)-এ আসবে।
৪ · Marginal আর conditional — একটি অংশ জানলে বাকিটা কী
একজন গ্রাহক ফোন করে জানতে চাইলেন, তাঁর পার্সেল কখন আসবে। কিছু না জেনে বলা যায় “গড়ে ৩৫ মিনিট, তবে ১৫ থেকে ৫৫-এর মধ্যে যেকোনো সময়”। কিন্তু অ্যাপে দূরত্ব দেখা যাচ্ছে: ১০ km. এখন উত্তর হবে বেশি (কারণ দূরে), আর পরিসর সরু (কারণ একটি তথ্য জানা)। আবহাওয়ার পূর্বাভাসও তাই করে: আজ সকালের মেঘ জানা থাকলে বিকেলের বৃষ্টির অনুমান বদলায় আর নিশ্চয়তা বাড়ে।
x-কে দুই ভাগে ভাগ করুন: xa (যা জানতে চাই) আর xb (যা জানা)। μ আর Σ-ও একইভাবে ভাগ হয়: μ = (μa, μb), আর Σ-এর চারটি ব্লক Σaa, Σab, Σba, Σbb. Gaussian-এর দুটি চমৎকার গুণ:
Marginal: শুধু মুছে ফেলুন
xb-কে উপেক্ষা করলে xa ~ N(μa, Σaa). অর্থাৎ marginal distribution পেতে μ আর Σ থেকে অপ্রয়োজনীয় সারি-কলাম মুছে ফেলাই যথেষ্ট; কোনো integral লাগে না।
Conditional: সরলরেখা আর সংকোচন
xb জানা থাকলে xa | xb ~ N(μa|b, Σa|b), আবার Gaussian. গড় xb-এর রৈখিক function, আর covariance xb-এর মানের ওপর নির্ভর করে না।
μa|b = μa + Σab Σbb−1 (xb − μb)
Σa|b = Σaa − Σab Σbb−1 Σba
দ্বিতীয় রাশিটির নাম Schur complement. যা বিয়োগ হচ্ছে, ΣabΣbb−1Σba, তা PSD, তাই শর্ত দিলে variance কখনো বাড়ে না: তথ্য পেলে অনিশ্চয়তা কমে বা একই থাকে। দুই মাত্রায় (a = সময় t, b = দূরত্ব) সূত্র দুটি হয় পরিচিত রূপে: গড় = μt + ρ(σt/σd)(xd − μd), আর variance = σt²(1 − ρ²)।
- ভাগ করা। সময় t হলো অজানা অংশ, দূরত্ব d জানা অংশ। Σ-এর চারটি ঘরই এখানে একেকটি ১ × ১ ব্লক: Σtt = ১০০, Σtd = ২১, Σdd = ৯.
- জানা মান। দূরত্ব ১০ km, গড়ের চেয়ে ৪ km বেশি, অর্থাৎ ১.৩৩ standard deviation ওপরে।
- ঢাল। ΣtdΣdd−1 = ২১/৯ = ২.৩৩৩: প্রতি অতিরিক্ত km-এ গড়ে ২.৩৩ মিনিট বেশি। এটি ρσt/σd-এর সমান।
- শর্তসাপেক্ষ গড়। ৩৫ + ২.৩৩৩ × ৪ = ৪৪.৩৩ মিনিট। Standard এককে দূরত্ব ১.৩৩ sd ওপরে, কিন্তু অনুমিত সময় মাত্র ০.৯৩ sd ওপরে (ρ গুণ): এটিই “গড়ের দিকে ফেরা”, অংশ ৫-এ।
- শর্তসাপেক্ষ variance. ১০০ − ৪৪১/৯ = ১০০ − ৪৯ = ৫১, sd ৭.১৪. এটি σt²(১ − ρ²)-এর সমান, আর দূরত্ব ১০ হোক বা ৩, একই থাকে।
- ফল। সময় | দূরত্ব = ১০ ~ N(৪৪.৩৩, ৫১). প্রায় ৯৫% পরিসর [৩০.১, ৫৮.৬], যেখানে দূরত্ব না জানলে [১৫, ৫৫]: কেন্দ্র সরল, আর প্রস্থ ৪০ থেকে ২৮.৬ মিনিটে নামল।
সূত্রটি কি সত্যিই ঠিক? নিচের ব্লক Cholesky দিয়ে (পর্ব ১০-এর x = μ + Lz) দুই লাখ জোড়া বানায়, তারপর দূরত্ব d0-এর ±০.১ km-এর একটি সরু ফালি কেটে শুধু সেই অর্ডারগুলোর সময়ের গড় আর variance মাপে: “শর্ত দেওয়া”-র আক্ষরিক মানে।
import numpy as np
import matplotlib.pyplot as plt
mu = np.array([35.0, 6.0]) # (সময় মিনিট, দূরত্ব km)
Sigma = np.array([[100.0, 21.0], [21.0, 9.0]])
L = np.linalg.cholesky(Sigma)
rng = np.random.default_rng(42)
X = mu + rng.standard_normal((200_000, 2)) @ L.T # x = μ + Lz
def cond_time(d0): # সূত্র: সময় | দূরত্ব = d0
m = mu[0] + Sigma[0, 1] / Sigma[1, 1] * (d0 - mu[1])
v = Sigma[0, 0] - Sigma[0, 1] ** 2 / Sigma[1, 1]
return m, v
for d0 in (3.0, 6.0, 10.0):
m, v = cond_time(d0)
band = X[np.abs(X[:, 1] - d0) < 0.1, 0] # সরু ফালি
print(f"d0={d0:4.1f} formula: mean {m:5.2f} var {v:4.1f} | "
f"slice n={band.size}: mean {band.mean():5.2f} var {band.var(ddof=1):4.1f}")
slope, icpt = np.polyfit(X[:, 1], X[:, 0], 1) # least-squares রেখা
print(f"regression line: time = {icpt:.2f} + {slope:.3f} * distance")
print(f"formula line: time = {mu[0] - 21 / 9 * mu[1]:.2f} + {21 / 9:.3f} * distance")
fig, ax = plt.subplots(figsize=(6, 4), layout="constrained")
ax.scatter(X[:3000, 1], X[:3000, 0], s=3, alpha=0.3, label="samples")
g = np.linspace(-2, 14, 50)
m, v = cond_time(g)
ax.plot(g, m, "r", label="E[time | distance]")
ax.plot(g, m + 2 * np.sqrt(v), "r--", lw=1, label="mean ± 2 sd")
ax.plot(g, m - 2 * np.sqrt(v), "r--", lw=1)
ax.axvspan(9.9, 10.1, color="orange", alpha=0.5, label="slice at 10 km")
ax.set_xlabel("distance (km)"); ax.set_ylabel("delivery time (min)")
ax.legend(fontsize=8); plt.show()আসল আউটপুট (ব্রাউজারের Python):
d0= 3.0 formula: mean 28.00 var 51.0 | slice n=3304: mean 28.26 var 49.4
d0= 6.0 formula: mean 35.00 var 51.0 | slice n=5090: mean 35.09 var 51.5
d0=10.0 formula: mean 44.33 var 51.0 | slice n=2212: mean 44.55 var 48.6
regression line: time = 21.08 + 2.318 * distance
formula line: time = 21.00 + 2.333 * distance
তিনটি দূরত্বেই সূত্র আর ফালি কাছাকাছি: ১০ km-এ গড় ৪৪.৩৩ বনাম ৪৪.৫৫, variance ৫১ বনাম ৪৮.৬. পার্থক্যের কারণ নমুনার এলোমেলোতা (ফালিতে মাত্র ২,২১২টি সারি) আর ফালির ০.২ km প্রস্থ। Variance তিন জায়গাতেই প্রায় ৫১, দূরত্ব যা-ই হোক। পুরো নমুনার least-squares রেখা (২১.০৮ + ২.৩১৮ × দূরত্ব) সূত্রের রেখার (২১.০০ + ২.৩৩৩ × দূরত্ব) প্রায় হুবহু: শর্তসাপেক্ষ গড়ই regression রেখা, যা অংশ ৫-এর বিষয়। ছবিতে একটি অস্বস্তিকর সত্যও আছে: কিছু নমুনার দূরত্ব ঋণাত্মক। Gaussian model দূরত্বকে শূন্যের নিচে যেতে দেয়, যা বাস্তবে অসম্ভব; ভাবনার প্রশ্ন ৪-এ এই সীমাবদ্ধতা নিয়ে আলোচনা আছে।
Precision matrix-এর একটি গোপন অর্থ। Σ−1-এর বাইরের কোনো ঘর শূন্য হলে সেই দুটি feature বাকি সবকিছু জানা থাকলে স্বাধীন (conditional independence). Σ-এর ঘর শূন্য হওয়া আর Σ−1-এর ঘর শূন্য হওয়া আলাদা কথা: প্রথমটি “একা দেখলে সম্পর্কহীন”, দ্বিতীয়টি “বাকিদের প্রভাব সরালে সম্পর্কহীন”। Gaussian graphical model আর graphical lasso এই ধারণার ওপর দাঁড়ানো। অংশ ১-এর stepper-এ Σ−1-এর বাইরের ঘর ঋণাত্মক ছিল, কারণ ২ মাত্রায় সেটি −ρ-এর সমানুপাতিক: correlation যত বেশি, যৌথ সরণ তত “ক্ষমা” পায়।
৫ · Conditional গড় মানেই regression রেখা — আর “গড়ের দিকে ফেরা”
অংশ ৪-এর শর্তসাপেক্ষ গড় E[সময় | দূরত্ব] = ২১ + ২.৩৩৩ × দূরত্ব, একটি সরলরেখা। এর ঢাল Cov(t, d)/Var(d), যা হুবহু least squares-এর ঢাল (AI-এর ভিত্তি কোর্সের পর্ব ৫৮)। তাই বলা যায়: ডেটা যৌথভাবে Gaussian হলে linear regression কোনো অনুমান নয়, সঠিক model; শর্তসাপেক্ষ গড় সত্যিই রৈখিক, আর ভুল (residual) Gaussian, যার variance σt²(1 − ρ²) সব x-এ এক। R² এখানে ρ² = ০.৪৯: দূরত্ব সময়ের variance-এর ৪৯% ব্যাখ্যা করে, বাকি ৫১ (মিনিট²) থেকে যায়। একাধিক feature হলে ΣabΣbb−1 হলো সব coefficient-এর vector, যা normal equations-এর (XᵀX)−1Xᵀy-এর জনসংখ্যা-রূপ।
উল্টো দিকও খেয়াল করুন: বাস্তব ডেটা Gaussian না হলে E[y | x] বাঁকা হতে পারে, আর তখন সরলরেখা শুধু “সবচেয়ে ভালো রৈখিক অনুমান”, সত্যিকারের শর্তসাপেক্ষ গড় নয়। আর variance x-এর সঙ্গে বদলালে (দূরের অর্ডারে অনিশ্চয়তা বেশি) সব x-এ এক পরিসর দেওয়া ভুল হবে।
Regression to the mean: standard এককে অনুমান সবসময় ρ গুণ, তাই |ρ| < ১ হলে অনুমান গড়ের দিকে টানা থাকে। দূরত্ব ১.৩৩ sd বেশি হলে সময়ের অনুমান মাত্র ০.৯৩ sd বেশি। এটি কোনো কারণগত শক্তি নয়, শুধু অসম্পূর্ণ correlation-এর গাণিতিক ফল। একই কারণে খুব খারাপ মাসের পর বাজারঘরের যেকোনো “সংস্কার”-এর পরের মাস ভালো দেখাতে পারে, সংস্কার কাজ না করলেও। ভাবনার প্রশ্ন ২-এ এর ইতিহাস আর ফাঁদ।
ইতিহাস: “Regression” শব্দটি এসেছে Francis Galton-এর কাজ থেকে। ১৮৮০-এর দশকে তিনি বাবা-মা আর সন্তানের উচ্চতার তথ্যে দেখেন, খুব লম্বা বাবা-মায়ের সন্তান গড়ে কম লম্বা হয়, আর ১৮৮৬ সালের প্রবন্ধে একে বলেন “regression towards mediocrity”. প্রচলিত বিবরণ অনুযায়ী, তিনি তথ্যের টেবিলে সমান-ঘনত্বের রেখাগুলো উপবৃত্তের মতো দেখেন, আর গণিতবিদ J. D. Hamilton Dickson সেই পর্যবেক্ষণ থেকে দুই মাত্রার normal-এর সূত্র মেলান। অর্থাৎ অংশ ২-এর উপবৃত্ত আর অংশ ৫-এর regression রেখা ইতিহাসে একসঙ্গে জন্মেছিল।
ML-এ এই সূত্র অনেক জায়গায় ফিরে আসে। পর্ব ৪৫ (Bayesian linear regression)-এ posterior আর predictive বণ্টন, পর্ব ৪৬ (Gaussian process)-এ কিছু বিন্দুর মান জানা থাকলে নতুন বিন্দুর অনুমান, দুটিই আসলে এই conditional Gaussian সূত্র। Kalman filter (১৯৬০) প্রতিটি নতুন মাপে একই হিসাব বারবার চালায়, আর Gaussian mixture-এর EM (পর্ব ৩৯) প্রতিটি উপাদানের জন্য এই পর্বের density ব্যবহার করে।
৬ · ডেটা থেকে μ আর Σ — MLE, n বনাম n − ১, আর parameter-এর হিসাব
বাস্তবে μ আর Σ জানা থাকে না; n-টি সারি x1, …, xn থেকে অনুমান করতে হয়। Maximum likelihood (পর্ব ১৮, Maximum likelihood আর MAP-এ বিস্তারিত) মানে log-likelihood সবচেয়ে বড় করা:
ℓ(μ, Σ) = −(n/2)·log det Σ − ½ ∑i (xi − μ)ᵀΣ−1(xi − μ) − (nd/2)·log 2π
μ-এর সাপেক্ষে gradient শূন্য করলে Σ−1∑(xi − μ) = ০, তাই μ̂ = নমুনার গড়. Σ-এর সাপেক্ষে (পর্ব ১১-এর দুটি সূত্র লাগে: ∂ log det Σ/∂Σ = Σ−1, আর trace-এর কৌশল) পাওয়া যায় Σ̂ = (1/n)∑(xi − μ̂)(xi − μ̂)ᵀ. এখানে n দিয়ে ভাগ, n − ১ নয়: MLE একটু biased, কারণ μ̂ নিজেই ডেটা থেকে এসেছে আর ডেটার দিকে টানা। n − ১ দিয়ে ভাগ করলে unbiased. NumPy-র np.cov ডিফল্টভাবে n − ১ নেয় (bias=True দিলে n), scikit-learn-এর EmpiricalCovariance আর LDA-র ভেতরের হিসাব n নেয়। n বড় হলে পার্থক্য তুচ্ছ, কিন্তু ছোট n-এ আর লাইব্রেরির ফল মেলাতে গেলে গুরুত্বপূর্ণ (অংশ ৭-এর ব্লকে দুটিই আছে)।
Parameter কত দ্রুত বাড়ে। μ-তে d-টি সংখ্যা, আর প্রতিসম Σ-এ d(d + ১)/২টি। d = ৩-এ মোট ৯, d = ৪০-এ ৪০ + ৮২০ = ৮৬০, d = ১,০০০-এ পাঁচ লাখের বেশি। তার ওপর Σ̂-এর rank সর্বোচ্চ n − ১, তাই n ≤ d হলে Σ̂ singular: inverse নেই, density নেই, Mahalanobis নেই। অংশ ৮ এই সমস্যার একটি নীতিগত সমাধান দেবে।
উল্টো দিক, নমুনা বানানো। পর্ব ১০-এ দেখেছি Σ = LLᵀ হলে x = μ + Lz ~ N(μ, Σ). NumPy-র rng.multivariate_normal(mean, cov) একই কাজ করে, তবে ডিফল্টভাবে SVD দিয়ে (method="svd"), যা singular Σ-ও সামলায়; method="cholesky" দ্রুত। আর SciPy-র multivariate_normal(mean, cov).rvs(size, random_state=...) একটি বণ্টন-object দেয়, যার pdf, logpdf আর cdf-ও আছে। লক্ষ করুন, একই seed হলেও এই তিনটি পথ আলাদা সংখ্যা দেয়, কারণ ভেতরের বর্গমূল-matrix আলাদা।
৭ · Gaussian দিয়ে classification — LDA আর QDA
ধরুন বাজারঘর জানতে চায় কোন অর্ডার ফেরত আসতে পারে। দুটি feature: ডেলিভারির দেরি (মিনিট) আর ছাড় (%). একটি পথ হলো logistic regression, যা সরাসরি P(ফেরত | x) শেখে, একটি discriminative model (AI-এর ভিত্তি কোর্সের পর্ব ৫৯)। অন্য পথ generative model: প্রতিটি শ্রেণির ডেটা কেমন দেখতে, তা শেখা। শ্রেণি k-এর জন্য ধরা হয় x | y = k ~ N(μk, Σk), আর শ্রেণির অনুপাত πk (prior). তারপর Bayes-এর নিয়ম (AI-এর ভিত্তি কোর্সের পর্ব ৫০): P(y = k | x) ∝ πk·N(x; μk, Σk). log নিলে প্রতিটি শ্রেণির discriminant function:
δk(x) = −½ log det Σk − ½ (x − μk)ᵀΣk−1(x − μk) + log πk
যে শ্রেণির δ বড়, সেটিই অনুমান। প্রতিটি শ্রেণির নিজের Σk থাকলে এর নাম QDA (Quadratic Discriminant Analysis), কারণ দুই শ্রেণির সীমারেখা δ1 = δ0 একটি দ্বিঘাত বক্ররেখা (উপবৃত্ত, পরাবৃত্ত বা অধিবৃত্ত)। সব শ্রেণির জন্য একটিই Σ (pooled covariance) ধরলে xᵀΣ−1x পদটি দুই দিকে সমান হয়ে কেটে যায়, থাকে শুধু রৈখিক অংশ। সেটিই LDA (Linear Discriminant Analysis):
log [P(1 | x) / P(0 | x)] = wᵀ(x − m) + log(π1/π0), w = Σ−1(μ1 − μ0), m = (μ0 + μ1)/2
লক্ষ করুন, এটি হুবহু logistic regression-এর আকার: P(1 | x) = σ(wᵀx + b). পার্থক্য শুধু w আর b কীভাবে আসে: LDA গড় আর covariance থেকে বন্ধ সূত্রে, logistic regression সরাসরি log loss কমিয়ে। আর সমান prior হলে LDA মানে “Mahalanobis দূরত্বে যে শ্রেণির গড় কাছে, সেটি”। Σk-কে কর্ণ-matrix ধরলে পাওয়া যায় Gaussian Naive Bayes (AI-এর ভিত্তি কোর্সের পর্ব ৫১)। নিচের stepper একটি অর্ডারের LDA সিদ্ধান্ত হাতে করে, প্যারামিটারগুলো পরের ব্লকের অনুমান থেকে গোল করে নেওয়া।
| ধাপ | |
| হিসাব | |
| সংখ্যায় | |
| মানে |
- প্যারামিটার। রাখা অর্ডারের গড় (৩৫ মিনিট, ১০%), ফেরতের (৫১, ১৯). Pooled Σ প্রায় কর্ণ-matrix: দেরির variance ১২৮, ছাড়ের ৩০. নতুন অর্ডার: ৬০ মিনিট দেরি, ১২% ছাড়।
- দিক w. Σ কর্ণ বলে inverse সহজ: (৫১ − ৩৫)/১২৮ = ০.১২৫, (১৯ − ১০)/৩০ = ০.৩. ছাড়ের ব্যবধান ছোট হলেও তার variance কম, তাই প্রতি একক ছাড়ের ওজন বেশি।
- মাঝবিন্দু। m = (৪৩, ১৪.৫). অর্ডারটি দেরিতে মাঝবিন্দুর ১৭ মিনিট ওপরে, কিন্তু ছাড়ে ২.৫ নিচে।
- দূরত্বের অংশ। ০.১২৫ × ১৭ = ২.১২৫ ফেরতের পক্ষে, ০.৩ × (−২.৫) = −০.৭৫ বিপক্ষে; মোট ১.৩৭৫. দুই শ্রেণি সমান সাধারণ হলে P(ফেরত) = σ(১.৩৭৫) = ০.৭৯৮.
- Prior. ফেরত মাত্র ২৫%, তাই log(০.২৫/০.৭৫) = −১.০৯৯ যোগ হয়। Score নামে ০.২৭৬-এ।
- সিদ্ধান্ত। Score ধনাত্মক, তাই ফেরত (শ্রেণি ১), কিন্তু P = σ(০.২৭৬) = ০.৫৬৯, অল্প ব্যবধানে। সীমারেখা ০.১২৫x₁ + ০.৩x₂ = ৯.৭২৫ + ১.০৯৯ = ১০.৮২, একটি সরলরেখা।
এবার পুরো ডেটায়: ৪৫০টি রাখা আর ১৫০টি ফেরত অর্ডার (কাল্পনিক), ফেরতগুলোর দেরিতে ছড়ানো বেশি, তাই দুই শ্রেণির Σ আলাদা। LDA আর QDA নিজে লিখে scikit-learn-এর LinearDiscriminantAnalysis আর QuadraticDiscriminantAnalysis-এর সঙ্গে মেলানো হলো, ৭০/৩০ ভাগে, test set আলাদা রেখে।
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.discriminant_analysis import (LinearDiscriminantAnalysis,
QuadraticDiscriminantAnalysis)
rng = np.random.default_rng(42) # (দেরি মিনিট, ছাড় %); 0 = রাখা, 1 = ফেরত
X0 = rng.multivariate_normal([35, 10], [[100, 15], [15, 25]], size=450)
X1 = rng.multivariate_normal([50, 18], [[225, -20], [-20, 49]], size=150)
X = np.vstack([X0, X1]); y = np.repeat([0, 1], [450, 150])
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, stratify=y, random_state=42)
pri = np.array([np.mean(ytr == k) for k in (0, 1)]) # π_k
mus = np.array([Xtr[ytr == k].mean(axis=0) for k in (0, 1)]) # μ_k
covs = [np.cov(Xtr[ytr == k], rowvar=False) for k in (0, 1)] # Σ_k (n_k − 1)
pooled = sum(p * np.cov(Xtr[ytr == k], rowvar=False, bias=True)
for k, p in enumerate(pri)) # এক Σ সবার
def lda_score(x, k): # রেখা: x-এ রৈখিক
a = np.linalg.solve(pooled, mus[k])
return x @ a - 0.5 * mus[k] @ a + np.log(pri[k])
def qda_score(x, k): # বক্ররেখা: x-এ দ্বিঘাত
D = x - mus[k]
m2 = np.einsum("ij,ij->i", D @ np.linalg.inv(covs[k]), D)
return -0.5 * np.linalg.slogdet(covs[k])[1] - 0.5 * m2 + np.log(pri[k])
w = np.linalg.solve(pooled, mus[1] - mus[0])
b = lda_score(np.zeros(2), 1) - lda_score(np.zeros(2), 0)
lda = LinearDiscriminantAnalysis(solver="lsqr").fit(Xtr, ytr)
qda = QuadraticDiscriminantAnalysis().fit(Xtr, ytr)
print("w, b scratch:", w.round(4), round(b, 3))
print("w, b sklearn:", lda.coef_[0].round(4), lda.intercept_.round(3))
for name, f, model in (("LDA", lda_score, lda), ("QDA", qda_score, qda)):
mine = (f(Xte, 1) > f(Xte, 0)).astype(int)
print(f"{name}: agrees with sklearn on {np.mean(mine == model.predict(Xte)):.0%}"
f" | test accuracy {np.mean(mine == yte):.3f}")
print("always 'kept' baseline accuracy:", round(np.mean(yte == 0), 3))আসল আউটপুট (ব্রাউজারের Python):
w, b scratch: [0.1269 0.314 ] -11.075
w, b sklearn: [0.1269 0.314 ] [-11.075]
LDA: agrees with sklearn on 100% | test accuracy 0.856
QDA: agrees with sklearn on 100% | test accuracy 0.878
always 'kept' baseline accuracy: 0.75
নিজের লেখা w আর b, scikit-learn-এর coef_ আর intercept_-এর সঙ্গে দেখানো সব দশমিক পর্যন্ত এক, আর test set-এর প্রতিটি সারিতে দুই পদ্ধতির অনুমান এক (১০০%). হুবহু মেলাতে একটি খুঁটিনাটি জরুরি: solver="lsqr"-এর LDA pooled covariance বানায় প্রতিটি শ্রেণির nk দিয়ে ভাগ করা covariance-এর prior-ওজনের গড় থেকে (তাই bias=True), আর QDA প্রতিটি শ্রেণিতে nk − ১ দিয়ে ভাগ করে (np.cov-এর ডিফল্ট)। দুটি উল্টে দিলে একটি ডেস্কটপ run-এ w হয় (০.১২৬৪, ০.৩১২৩) আর b −১১.০২৫, যদিও এই ডেটায় কোনো অনুমান বদলায়নি। Accuracy: QDA ০.৮৭৮, LDA ০.৮৫৬, আর সবসময় “রাখা” বলা baseline ০.৭৫. QDA একটু ভালো, কারণ ফেরত অর্ডারের covariance এখানে সত্যিই আলাদা করে বানানো। তবে ১৮০টি test সারিতে পার্থক্য মাত্র ৪টি সারি, তাই কয়েকটি seed বা fold-এ যাচাই ছাড়া QDA-কে “ভালো” বলা যায় না (পর্ব ২২, Model তুলনার পরিসংখ্যান)। আর ফেরত মাত্র ২৫% বলে accuracy একা যথেষ্ট নয়; recall আর calibration-ও দেখা দরকার।
ইতিহাস: R. A. Fisher ১৯৩৬ সালে “The use of multiple measurements in taxonomic problems” প্রবন্ধে দুটি প্রজাতি আলাদা করার সবচেয়ে ভালো রৈখিক মিশ্রণ খোঁজেন: যে দিক বরাবর দুই গড়ের ব্যবধান শ্রেণির ভেতরের ছড়ানোর তুলনায় সবচেয়ে বড়। উত্তর হলো w ∝ Σ−1(μ1 − μ0), এই অংশের LDA-র দিকই, যদিও Fisher Gaussian ধরে নেননি। সেই প্রবন্ধের ফুলের মাপের ডেটাই (Edgar Anderson-এর সংগ্রহ) আজকের বিখ্যাত Iris dataset. একই বছরে মহলানবিশের সাধারণীকৃত দূরত্বের প্রবন্ধও প্রকাশিত হয় (পর্ব ১০-এর ইতিহাস দেখুন)।
৮ · অল্প ডেটায় বড় Σ — Ledoit–Wolf shrinkage
অংশ ৬-এর সমস্যায় ফিরি। বাজারঘর ৪০টি feature (প্রতিটি পণ্য-বিভাগে খরচ ইত্যাদি) দিয়ে LDA চালাতে চায়, কিন্তু একটি নতুন জেলায় প্রতি শ্রেণিতে মাত্র ২৫টি অর্ডার। Σ-এ ৮২০টি অজানা, ডেটায় ৫০টি সারি। নমুনার covariance S এখানে শুধু অনিশ্চিত নয়, পদ্ধতিগতভাবে বিকৃত: তার বড় eigenvalue-গুলো আসলের চেয়ে বড়, ছোটগুলো আসলের চেয়ে ছোট (n ≤ d হলে একেবারে শূন্য)। আর Σ−1 ঠিক এই ছোট eigenvalue-গুলোকে উল্টে বিশাল বানায়, তাই Mahalanobis দূরত্ব, density আর LDA-র w সবই ভুল দিকে ফুলে ওঠে।
Shrinkage-এর ধারণা: S-কে একটি সরল, স্থিতিশীল লক্ষ্যের দিকে একটু টানুন।
Σ̂ = (1 − α)·S + α·(tr S / d)·I, ০ ≤ α ≤ ১
লক্ষ্য (tr S/d)·I হলো “সব feature-এর variance সমান, কোনো correlation নেই”। α = ০ মানে শুধু ডেটা, α = ১ মানে শুধু লক্ষ্য। ফল: সব eigenvalue গড়ের দিকে সরে, ক্ষুদ্রতমটি আর শূন্য থাকে না, Σ̂ সবসময় invertible. এটি পর্ব ১৭-এর ridge-এর আত্মীয়: একটু bias মেনে অনেক variance কমানো। কিন্তু α কত? Olivier Ledoit আর Michael Wolf (২০০৪) একটি সূত্র দেন, যা ডেটা থেকেই α হিসাব করে, Frobenius দূরত্বে (সব ঘরের বর্গ-ভুলের যোগ) প্রত্যাশিত ভুল প্রায় সবচেয়ে কম রাখতে; কোনো cross-validation লাগে না। scikit-learn-এ sklearn.covariance.LedoitWolf, আর LDA-তে solver="lsqr" বা "eigen"-এর সঙ্গে shrinkage="auto".
নিচের পরীক্ষাটি একটু বড় (৪০ feature, ২০টি seed, কয়েক হাজার test সারি), তাই এটি ডেস্কটপে চালানো হয়েছে। সত্যিকারের run: Python 3.14.4, NumPy 2.5.4, scikit-learn 1.9.1 (লেখার সময়ের সর্বশেষ stable). আসল Σ জানা: Σij = ০.৬|i − j|. প্রতিটি n-এ ২০টি seed-এর গড় আপেক্ষিক ভুল ‖Σ̂ − Σ‖/‖Σ‖, গড় α, আর শেষ seed-এর condition number; তারপর দুই শ্রেণির LDA (প্রথম ৫টি feature-এ গড় ১ করে সরানো), প্রতি শ্রেণিতে ২৫টি training সারি, ১০টি seed.
~/bazarghar-ml$ python ledoit_wolf.py
numpy 2.5.4 | scikit-learn 1.9.1
n err(sample) err(LW) shrinkage cond(sample) cond(LW)
20 0.975 0.591 0.609 1.17e+18 5.31
50 0.629 0.479 0.423 875 7.39
200 0.320 0.294 0.162 40.3 14.6
1000 0.140 0.137 0.037 19.3 16.3
LDA shrinkage=None test accuracy mean 0.599 sd 0.033 over 10 seeds
LDA shrinkage='auto' test accuracy mean 0.710 sd 0.020 over 10 seeds
পড়ুন সারি ধরে। n = ২০ (feature-এর অর্ধেক): নমুনার S-এর ভুল প্রায় ১০০% (০.৯৭৫), আর condition number ১০১৮: কার্যত singular, কারণ rank সর্বোচ্চ ১৯. Ledoit–Wolf গড়ে α = ০.৬১ বেছে নেয়, ভুল নামে ০.৫৯-এ, condition number ৫.৩. n = ৫০-এ α = ০.৪২, n = ২০০-এ ০.১৬, n = ১,০০০-এ ০.০৪: ডেটা যত বাড়ে, সূত্র তত কম টানে, আর দুই অনুমান প্রায় এক হয়ে যায়। এটিই ভালো shrinkage-এর আচরণ। LDA: ৫০টি training সারিতে ৪০ মাত্রার Σ, shrinkage ছাড়া test accuracy গড়ে ০.৫৯৯, shrinkage-সহ ০.৭১০, আর seed-ভেদে ছড়ানোও কম (sd ০.০৩৩ বনাম ০.০২০)। এই কাল্পনিক ডেটায় আসল Σ জানা থাকলে সর্বোচ্চ সম্ভব accuracy প্রায় ০.৭৯ (হিসাব করা Bayes accuracy), তাই shrinkage ফাঁকের অনেকটা পূরণ করেছে। এগুলো একটি local run-এর সংখ্যা, সাধারণ ফল নয়।
Ledoit–Wolf একমাত্র পথ নয়: OAS (Oracle Approximating Shrinkage) Gaussian ডেটায় প্রায়ই একটু ভালো, GraphicalLasso Σ−1-এ শূন্য খোঁজে (অংশ ৪-এর precision matrix), আর লেখার সময়ের scikit-learn-এ (1.8 থেকে) QuadraticDiscriminantAnalysis-এও solver আর shrinkage parameter আছে; পুরোনো version-এ শুধু reg_param ছিল। আপনার version-এর docs দেখে নিন।
আরও গভীরে: নমুনার covariance-এর eigenvalue কেন ছড়িয়ে যায়, তার সীমা-রূপ Marchenko আর Pastur (১৯৬৭)-এর random matrix theory দেয়: d/n অনুপাত স্থির রেখে দুটিই বড় করলে আসল Σ = I হলেও নমুনার eigenvalue (1 − √(d/n))² থেকে (1 + √(d/n))² পর্যন্ত ছড়ায়। Shrinkage-এর মূলে আছে Charles Stein-এর ১৯৫৬ সালের ফল: তিন বা বেশি মাত্রায় নমুনার গড়ও “admissible” নয়, একটি সাধারণ বিন্দুর দিকে টানলে মোট বর্গ-ভুল কমে (James–Stein estimator, ১৯৬১)। Ledoit আর Wolf পরে nonlinear shrinkage-এর পদ্ধতিও দেন, যা প্রতিটি eigenvalue আলাদা পরিমাণে টানে।
পরীক্ষা ও ইন্টারভিউতে: এই ধরনের প্রশ্ন বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় প্রায়ই আসে।
- Σ = [[4, 2], [2, 3]], μ = (1, 2) হলে x1 | x2 = 4-এর বণ্টন? গড় ১ + (২/৩)(২) = ২.৩৩৩, variance ৪ − ৪/৩ = ২.৬৬৭.
- Gaussian ডেটায় Mahalanobis d²-এর বণ্টন? χ²d; গড় d, variance 2d.
- Correlation শূন্য মানেই কি স্বাধীন? যৌথ Gaussian হলে হ্যাঁ, সাধারণভাবে না।
- LDA আর QDA-র পার্থক্য? LDA সব শ্রেণির এক Σ ধরে, সীমা রৈখিক; QDA প্রতিটির আলাদা Σ, সীমা দ্বিঘাত, parameter অনেক বেশি।
- Σ-এর MLE n দিয়ে ভাগ করে কেন biased? μ̂ ডেটা থেকে অনুমিত, তাই বিচ্যুতি কম দেখায়; n − ১ দিয়ে ভাগ করলে unbiased.
৯ · AI-এর যুগে — Gaussian-এর সূত্র আর কোড যাচাই
AI assistant এই বিষয়ের সূত্র প্রায়ই নির্ভুল ছাপে, কিন্তু ভুল হয় মাত্রায়, ভাগে আর অনুমানে। নিচের ভুলগুলো বারবার দেখা যায়:
| AI প্রায়ই যা করে | কেন ভুল | কীভাবে ধরবেন |
|---|---|---|
| Density-তে (2π)d/2-এর বদলে 2π, বা √det Σ-এর বদলে det Σ লেখে | d ≠ ২ বা Σ ≠ I হলে উত্তর ভুল | SciPy-র multivariate_normal.pdf-এর সঙ্গে ২-৩টি বিন্দুতে মেলান |
| Mahalanobis-এ Σ-এর বদলে correlation matrix বা কর্ণ-Σ ব্যবহার করে | মাপ বা correlation বাদ পড়ে | এক মাত্রায় z²-এ নামে কি না দেখুন |
| Outlier-এর সীমা হিসেবে d > 3 ধরে নেয়, মাত্রা যা-ই হোক | সীমা d (feature সংখ্যা)-এর ওপর নির্ভর করে | chi2.ppf(0.99, df=d) ব্যবহার করুন |
| Conditional variance-এ xb-এর মান ঢুকিয়ে দেয় | Gaussian-এ এটি xb-নিরপেক্ষ | সরু ফালির নমুনা দিয়ে যাচাই করুন |
np.cov আর EmpiricalCovariance-এর ফল না মেলায় “bug” বলে | একটি n − ১, অন্যটি n দিয়ে ভাগ করে | bias=True দিয়ে মিলিয়ে দেখুন |
পুরোনো বা বানানো parameter দেয় (যেমন LDA-তে shrinkage সহ solver="svd") | svd solver shrinkage নেয় না, error দেয় | নিজের version-এর scikit-learn docs পড়ুন, চালিয়ে দেখুন |
| পুরো ডেটায় Σ অনুমান করে তারপর train/test ভাগ করে | Test-এর তথ্য model-এ ঢোকে (leakage) | আগে ভাগ, তারপর শুধু training অংশে fit |
উত্তরের সঙ্গে যাচাইয়ের কোড চেয়ে নিন; নিজে চালানো অংশটিই আসল পরীক্ষা।
AI-এর দেওয়া Gaussian বা LDA কোড হাতে পেলে — যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১১৯৩৬ সালে মহলানবিশ আর Fisher প্রায় একই প্রশ্নে দুটি ভিন্ন দিক থেকে পৌঁছেছিলেন। দুটি কাজ কীভাবে আজকের ML-এ একসঙ্গে মেলে?
প্রশান্তচন্দ্র মহলানবিশ কলকাতায় নৃতাত্ত্বিক মাপের ডেটা নিয়ে কাজ করছিলেন: বিভিন্ন জনগোষ্ঠীর মাথার খুলি, উচ্চতা ইত্যাদির অনেকগুলো মাপ। প্রশ্ন ছিল, দুটি জনগোষ্ঠী সামগ্রিকভাবে কতটা আলাদা? প্রতিটি মাপ আলাদা করে তুলনা করলে একই তথ্য বারবার গোনা হয়, কারণ মাপগুলো পরস্পর সম্পর্কিত (লম্বা মানুষের হাতও লম্বা)। তাঁর সমাধান: covariance-এর inverse দিয়ে ওজন দেওয়া দূরত্ব, যা correlation-এর দ্বিগুণ গোনা বাদ দেয়। ১৯৩৬ সালে “On the generalised distance in statistics” প্রবন্ধে এর সাধারণ রূপ প্রকাশিত হয়।
একই বছর ইংল্যান্ডে R. A. Fisher “The use of multiple measurements in taxonomic problems” প্রবন্ধে ভিন্ন প্রশ্ন করেন: কয়েকটি মাপ থেকে একটি সংখ্যা বানাতে চাই, যা দুটি প্রজাতিকে সবচেয়ে ভালো আলাদা করে। তিনি এমন দিক w খোঁজেন যেখানে দুই গড়ের ব্যবধানের বর্গ, শ্রেণির ভেতরের variance-এর তুলনায় সবচেয়ে বড়। উত্তর w ∝ Σ−1(μ1 − μ0). আর মজার ব্যাপার, সেই দিক বরাবর দুই গড়ের ব্যবধানের বর্গ হলো (μ1 − μ0)ᵀΣ−1(μ1 − μ0), অর্থাৎ দুই গড়ের Mahalanobis দূরত্বের বর্গ।
তাই দুটি কাজ একই মুদ্রার দুই পিঠ। মহলানবিশের দূরত্ব বলে দুটি দল কতটা আলাদা; Fisher-এর দিক বলে কোন রৈখিক মিশ্রণে সেই পার্থক্য পুরোটা দেখা যায়। আজকের LDA-তে দুটিই আছে: সমান prior-এ সিদ্ধান্ত “Mahalanobis দূরত্বে যে গড় কাছে”, আর সীমারেখার দিক Fisher-এর w. এই পর্বের অংশ ৭-এর ব্লকে w ঠিক এভাবেই হিসাব হয়েছে।
একটি পার্থক্যও আছে, যা ব্যবহারিক গুরুত্ব রাখে। Fisher-এর যুক্তি Gaussian ধরে নেয় না; এটি শুধু গড় আর covariance-এর ওপর দাঁড়ানো একটি জ্যামিতিক মাপ। Gaussian ধরলে সেই একই দিক Bayes-এর নিয়মে সর্বোত্তমও হয়। তাই ডেটা Gaussian না হলেও LDA প্রায়ই যুক্তিসংগত কাজ করে, যদিও সম্ভাবনার মান তখন বিশ্বাসযোগ্য নয়।
মূল উপলব্ধি: Covariance-এর inverse দিয়ে মাপা দূরত্ব আর সবচেয়ে ভালো আলাদা করার দিক একই গণিত থেকে আসে; LDA সেই দুটিকে এক সূত্রে বাঁধে।
প্র ০২“গড়ের দিকে ফেরা” কীভাবে ভুল সিদ্ধান্তের জন্ম দেয়, আর বাজারঘরের দল তা কীভাবে এড়াবে?
অংশ ৪-এর stepper-এ দেখেছি, standard এককে শর্তসাপেক্ষ অনুমান সবসময় ρ গুণ। দুটি মাপ পুরোপুরি সম্পর্কিত না হলে (|ρ| < ১), একটিতে চরম মান পেলে অন্যটির অনুমান গড়ের কাছাকাছি হয়। এটি একই জিনিস দুবার মাপলেও ঘটে: এই মাসের বিক্রি আর পরের মাসের বিক্রির correlation ধরুন ০.৬. কোনো জেলার এই মাস খুব খারাপ গেলে (গড়ের ২ sd নিচে), কিছু না করলেও পরের মাসের প্রত্যাশা মাত্র ১.২ sd নিচে। উন্নতি “স্বাভাবিকভাবে” আসবে।
এখান থেকে ফাঁদ। ধরুন বাজারঘর সবচেয়ে খারাপ পাঁচটি জেলায় নতুন রাইডার-প্রশিক্ষণ চালু করল, আর পরের মাসে সেগুলোর ডেলিভারি সময় ভালো হলো। প্রশিক্ষণ কাজ করেছে? হয়তো, কিন্তু এই উন্নতির একটি অংশ শুধু গড়ের দিকে ফেরা। উল্টোটাও ঘটে: সবচেয়ে ভালো জেলার ব্যবস্থাপককে পুরস্কার দিলে পরের মাসে ফল একটু খারাপ হতে পারে, আর কেউ ভাবতে পারে পুরস্কার মানুষকে অলস করে। Daniel Kahneman তাঁর লেখায় বিমান প্রশিক্ষকদের একটি গল্প বলেছেন: প্রশিক্ষকেরা বিশ্বাস করতেন প্রশংসার পর পারফরম্যান্স খারাপ হয় আর বকুনির পর ভালো; আসলে খুব ভালো বা খুব খারাপ উড়ানের পর স্বাভাবিকভাবেই সাধারণ উড়ান আসে।
Galton নিজে প্রথমে এটিকে বংশগতির একটি জৈবিক নিয়ম ভেবেছিলেন বলে মনে করা হয়; পরে স্পষ্ট হয় যে এটি যেকোনো অসম্পূর্ণ correlation-এর পরিসংখ্যানিক ফল। এই ভুল ব্যাখ্যা “regression fallacy” নামে পরিচিত।
এড়ানোর উপায় পরিষ্কার: তুলনার জন্য একটি control দল রাখুন। খারাপ জেলাগুলোর মধ্যে এলোমেলোভাবে অর্ধেকে প্রশিক্ষণ দিন, অর্ধেকে না। দুই দলই গড়ের দিকে ফিরবে; পার্থক্যটুকুই প্রশিক্ষণের প্রভাব। এই নকশার বিস্তারিত পর্ব ৬২ (A/B test-এর পরিকল্পনা) আর পর্ব ৬৪ (Causal inference-এর পরিচয়)-এ আসবে। আর চরম মান দেখে দল বাছাই করলে সবসময় সন্দেহ করুন।
মূল উপলব্ধি: চরম মানের পর গড়ের কাছাকাছি মান আসা correlation < ১-এর গাণিতিক ফল, কোনো হস্তক্ষেপের প্রমাণ নয়; প্রভাব মাপতে এলোমেলো control দল লাগে।
প্র ০৩LDA (generative) আর logistic regression (discriminative) একই আকারের সীমারেখা দেয়। তাহলে কোনটি কখন বেছে নেবেন?
অংশ ৭-এ দেখেছি, LDA-র posterior P(1 | x) = σ(wᵀx + b), হুবহু logistic regression-এর আকার। পার্থক্য w আর b অনুমানের পথে। LDA পুরো যৌথ বণ্টন p(x, y) শেখে: শ্রেণির গড়, এক Σ আর prior. Logistic regression শুধু p(y | x) শেখে, x কোথা থেকে এল তা নিয়ে কিছু ধরে না। একটি পুরোনো তুলনা বলে, LDA-র অনুমান “সব ডেটা” ব্যবহার করে (সীমা থেকে দূরের বিন্দুও Σ-এর অনুমানে অংশ নেয়), তাই Gaussian অনুমান সত্য হলে কম ডেটায় বেশি দক্ষ।
২০০১ সালে Andrew Ng আর Michael Jordan-এর প্রবন্ধ (“On discriminative vs. generative classifiers”, NIPS) Naive Bayes আর logistic regression-এর জোড়া নিয়ে এই ধারণাকে স্পষ্ট রূপ দেয়: generative model নিজের (উচ্চতর) সীমায় দ্রুত পৌঁছায়, প্রায় log d-এর মতো সারিতে, আর discriminative model-এর সীমা নিচু (ভালো) কিন্তু সেখানে পৌঁছাতে প্রায় d-এর মতো সারি লাগে। ফল: অল্প ডেটায় generative প্রায়ই জেতে, বেশি ডেটায় discriminative. তবে এটি একটি প্রবণতা, সব ডেটায় নিয়ম নয়, আর পরের গবেষণা এর সীমাবদ্ধতাও দেখিয়েছে।
LDA-র দুর্বলতা হলো অনুমানের ওপর নির্ভরতা। শ্রেণির ভেতরে ডেটা বাঁকা বা বহু-চূড়াবিশিষ্ট হলে, বা outlier থাকলে, Σ-এর অনুমান বিকৃত হয়, আর logistic regression তুলনামূলক অক্ষত থাকে। অন্যদিকে LDA-র সুবিধা: বন্ধ সূত্রে দ্রুত, শ্রেণিগুলো পুরোপুরি আলাদা হলেও স্থিতিশীল (logistic regression তখন অসীম ওজনের দিকে যায়), missing feature সামলানো যায় (marginal নিয়ে), আর dimensionality কমানোর একটি স্বাভাবিক পদ্ধতি দেয়। বাজারঘরের মতো tabular ডেটায় বাস্তব পরামর্শ: দুটিই কয়েকটি seed বা fold-এ চালিয়ে তুলনা করুন, calibration দেখুন (পর্ব ২৬), আর ফল কাছাকাছি হলে সরলটি রাখুন।
মূল উপলব্ধি: Generative model অনুমান করে বেশি শেখে, তাই অনুমান সত্য হলে অল্প ডেটায় দক্ষ, মিথ্যা হলে পক্ষপাতদুষ্ট; discriminative model কম অনুমান করে বেশি ডেটা চায়। বাছাই হয় ডেটার পরিমাণ আর অনুমানের সত্যতা দেখে।
প্র ০৪বাস্তব ডেটা কি সত্যিই Gaussian? Gaussian অনুমান ভুল হলে কী কী ভেঙে পড়ে?
Gaussian জনপ্রিয় কয়েকটি ভালো কারণে: central limit theorem (অনেক ছোট স্বাধীন প্রভাবের যোগফল প্রায় normal), গাণিতিক সুবিধা (marginal, conditional আর রৈখিক রূপান্তর সব Gaussian থাকে), আর গড় ও covariance জানা থাকলে এটিই সবচেয়ে “কম অনুমান করা” বণ্টন (maximum entropy). কিন্তু বাস্তব ডেটা প্রায়ই অন্যরকম। ডেলিভারি সময় ঋণাত্মক হয় না আর ডানে লম্বা লেজ থাকে; অর্ডারের মূল্য আর আয় বাঁকা; ক্রয়ের সংখ্যা পূর্ণসংখ্যা। অংশ ৪-এর ছবিতেই দেখা গেছে, Gaussian model ঋণাত্মক দূরত্বও “সম্ভব” বলে।
অনুমান ভাঙলে প্রথম শিকার লেজের সম্ভাবনা। Gaussian-এর লেজ খুব দ্রুত পাতলা হয়, তাই চরম ঘটনাকে প্রায় অসম্ভব বলে। ২০০৮ সালের আর্থিক সংকটের পর অনেক বিশ্লেষক সমালোচনা করেছেন যে ঋণ-ঝুঁকির কিছু জনপ্রিয় মডেল (বিশেষত David Li-এর ২০০০ সালের Gaussian copula-ভিত্তিক পদ্ধতির ব্যবহার) একসঙ্গে অনেক ঋণখেলাপের সম্ভাবনা কম দেখিয়েছিল। সংকটের দায় কতটা এই মডেলের আর কতটা তার অপব্যবহারের, তা নিয়ে মতভেদ আছে; কিন্তু শিক্ষাটি পরিষ্কার: লেজের ঝুঁকিতে Gaussian-এর ওপর অন্ধ ভরসা বিপজ্জনক।
দ্বিতীয় শিকার এই পর্বের হিসাবগুলো। χ² সীমা ভুল সংখ্যক সতর্কতা দেয়; outlier Σ-কে ফুলিয়ে দেয়; LDA-র সম্ভাবনা অতিরিক্ত আত্মবিশ্বাসী হয়; আর বহু-চূড়ার ডেটায় (যেমন শহর আর গ্রামের অর্ডার মিশে) একটি Gaussian কোনো দলকেই ঠিকমতো বর্ণনা করে না।
করণীয়: আগে দেখুন (histogram, scatter, Q-Q plot). বাঁকা ধনাত্মক feature-এ log বা Box–Cox রূপান্তর প্রায়ই অনেকটা ঠিক করে। d²-এর quantile χ²-এর সঙ্গে মেলান (অংশ ৩-এর ব্লকের শেষ অংশের মতো)। দরকার হলে robust অনুমান (MinCovDet), ভারী লেজের বণ্টন (multivariate t), বা একাধিক Gaussian-এর মিশ্রণ (পর্ব ৩৯, Gaussian mixture আর EM) ব্যবহার করুন। আর Gaussian ছাড়া পদ্ধতিও আছে, যেমন পর্ব ৪০-এর KDE.
মূল উপলব্ধি: Gaussian একটি সুবিধাজনক প্রথম মডেল, প্রকৃতির নিয়ম নয়। এর হিসাবগুলো কেন্দ্রের কাছে প্রায়ই টেকে, লেজে আর বহু-চূড়ার ডেটায় ভাঙে; ব্যবহারের আগে আর পরে অনুমানটি যাচাই করুন।
প্র ০৫নমুনার covariance কেন বেশি feature-এ “অতি-আত্মবিশ্বাসী” ভুল করে, আর shrinkage কেন bias মেনে নিয়েও ভালো?
নমুনার covariance S প্রতিটি ঘরের জন্য unbiased (n − ১ দিয়ে ভাগ করলে)। তবু পুরো matrix হিসেবে এটি পদ্ধতিগতভাবে বিকৃত। কারণটি eigenvalue-তে। S-এর সবচেয়ে বড় eigenvalue হলো সেই দিক, যেখানে এই নমুনায় ছড়ানো সবচেয়ে বেশি; এলোমেলো ওঠানামা সেই দিক খোঁজায় সাহায্য করে, তাই বড়টি আসলের চেয়ে বড় আসে। একইভাবে ক্ষুদ্রতমটি আসলের চেয়ে ছোট। d/n অনুপাত যত বড়, এই ছড়ানো তত বেশি (Marchenko–Pastur). n ≤ d হলে ক্ষুদ্রতমগুলো শূন্য। আর ML-এ প্রায় সবসময় Σ−1 লাগে, যা ঠিক এই ক্ষুদ্রতম eigenvalue-গুলোকে উল্টে সবচেয়ে বড় বানায়। ফলে কিছু দিকে model “নিশ্চিত” হয়ে যায় যে ডেটা প্রায় নড়ে না, যা ভুল।
অর্থনীতিতে এর একটি পরিচিত রূপ আছে। Harry Markowitz-এর ১৯৫২ সালের portfolio তত্ত্বে বিনিয়োগের ভাগ ঠিক হয় Σ−1 দিয়ে। নমুনার Σ ব্যবহার করলে optimizer সেই সম্পদ-জোড়াগুলোতে বেশি ঝোঁকে যেগুলোর ঝুঁকি নমুনায় কাকতালীয়ভাবে কম দেখায়; Richard Michaud (১৯৮৯) একে বলেছিলেন “error maximization”. Ledoit আর Wolf-এর shrinkage-এর কাজের একটি বড় প্রেরণা ছিল এই সমস্যা।
Shrinkage কেন কাজ করে? মোট বর্গ-ভুল = bias² + variance. লক্ষ্য (tr S/d)·I-এর variance প্রায় শূন্য, কিন্তু bias বড়; S-এর bias ছোট, কিন্তু variance বিশাল। দুটির মিশ্রণে bias একটু বাড়ে, variance অনেক কমে, মোট ভুল কমে। Stein-এর ১৯৫৬ সালের বিস্ময়কর ফল এই যুক্তির মূলে: তিন বা বেশি মাত্রায় সবচেয়ে “স্বাভাবিক” অনুমানও একটি সাধারণ বিন্দুর দিকে টানলে ভালো হয়। অংশ ৮-এর run-এ n = ২০-এ ভুল ০.৯৭৫ থেকে ০.৫৯১-এ নেমেছে, আর n বাড়লে α নিজে থেকেই শূন্যের দিকে গেছে।
ML-এ এই ধারণা সর্বত্র: ridge (পর্ব ১৭), Bayesian prior (পর্ব ১৮), আর Gaussian process-এর jitter. সবগুলোর বক্তব্য একই: অল্প ডেটায় সরল কিছুর দিকে টানলে অনুমান স্থিতিশীল হয়।
মূল উপলব্ধি: বেশি মাত্রায় নমুনার covariance-এর eigenvalue ছড়িয়ে যায়, আর inverse সেই ভুল বড় করে। Shrinkage সামান্য bias দিয়ে অনেক variance কিনে নেয়, আর ডেটা বাড়লে নিজেই সরে দাঁড়ায়।
অনুশীলন
হিসাবগুলো খাতায় করুন, তারপর উত্তর মেলান। একটির জন্য কোড চালানো ঐচ্ছিক।
-
হাতের হিসাব: μ = (1, 2), Σ = [[4, 2], [2, 3]]. (ক) x = (3, 3)-এ Mahalanobis দূরত্ব আর density বের করুন। (খ) x1 | x2 = 4-এর গড় আর variance কত? (গ) d ≤ ১ উপবৃত্তের ভেতরে কত শতাংশ সম্ভাবনা?
(ক) x − μ = (২, ১). det Σ = ১২ − ৪ = ৮, Σ−1 = (১/৮)[[3, −2], [−2, 4]]. d² = (৩·৪ − ২·২·২·১ + ৪·১)/৮ = (১২ − ৮ + ৪)/৮ = ১, তাই d = ১. Density = e−1/2/(2π√৮) = ০.৬০৬৫ / ১৭.৭৭২ = ০.০৫৬২৭ × ০.৬০৬৫ ≈ ০.০৩৪১৩ (SciPy: 0.034129). (খ) গড় = ১ + (২/৩)(৪ − ২) = ২.৩৩৩; variance = ৪ − ২²/৩ = ৪ − ১.৩৩৩ = ২.৬৬৭. লক্ষ করুন x2-এর মান variance-এ ঢোকেনি। (গ) ২ মাত্রায় P(d² ≤ ১) = 1 − e−1/2 = ০.৩৯৩, অর্থাৎ প্রায় ৩৯.৩%. এক মাত্রায় ±১σ-এর ভেতরে ৬৮.৩% থাকে; মাত্রা বাড়লে “১ একক”-এর ভেতরে কম অংশ পড়ে।
-
সমালোচনা ও নকশা: বাজারঘরের একজন বিশ্লেষক জালিয়াতি সন্দেহের অর্ডার ধরতে ১২টি feature (অর্ডারের মূল্য, ছাড়, রাতের সময়, একই ফোনে অর্ডারের সংখ্যা ইত্যাদি) নিলেন, গত বছরের সব অর্ডার থেকে μ আর Σ হিসাব করলেন, আর d > ৩ হলে চিহ্নিত করার নিয়ম চালু করলেন। প্রথম সপ্তাহে প্রায় ১৫% অর্ডার চিহ্নিত হলো। কোথায় কোথায় সমস্যা, আর কীভাবে নতুন করে সাজাবেন?
সমস্যা: (১) সীমা ভুল: ১২ মাত্রায় d² ~ χ²12, যার গড়ই ১২, অর্থাৎ সাধারণ অর্ডারের d প্রায় √১২ ≈ ৩.৫. ডেটা সত্যিই Gaussian হলে d > ৩ (d² > ৯) নিয়মে প্রায় ৭০% সাধারণ অর্ডার চিহ্নিত হতো (χ²12-এ P(d² > ৯) ≈ ০.৭০); ৯৯% সীমা হওয়া উচিত d² ≈ ২৬.২. ১৫%-এর সংখ্যাটি তাই কোনো “মাপা” হার নয়, ভুল সীমা আর ভুল অনুমানের মিশ্র ফল। (২) মূল্য, ছাড়, অর্ডারের সংখ্যা বাঁকা আর পূর্ণসংখ্যা; Gaussian অনুমান খাটে না। (৩) পুরোনো ডেটায় জালিয়াতিও ছিল, তাই μ আর Σ দূষিত (masking). (৪) এক বছরের ডেটায় ঋতু আর উৎসবের প্রভাব মিশে গেছে; সময়ের সঙ্গে বণ্টন সরে (পর্ব ৫৯)। (৫) কোনো যাচাই নেই: চিহ্নিত অর্ডারের কতটা সত্যিই জালিয়াতি, জানা হয়নি।
নতুন নকশা: বাঁকা feature-এ log রূপান্তর; সীমা χ²12-এর উঁচু quantile থেকে, তারপর বাস্তব চিহ্নিত-হার দেখে সমন্বয়; MinCovDet দিয়ে robust μ, Σ; সাম্প্রতিক জানালা থেকে নিয়মিত হালনাগাদ; একটি ছোট লেবেল-করা নমুনায় precision মাপা; আর Gaussian ছাড়া পদ্ধতির সঙ্গে তুলনা (পর্ব ৪৩)।
-
আউটপুট অনুমান করুন: চালানোর আগে লিখে ফেলুন নিচের কোড কী ছাপবে।
import numpy as np S = np.array([[4., 2.], [2., 9.]]) mu = np.array([10., 20.]) x2 = 26. m = mu[0] + S[0, 1] / S[1, 1] * (x2 - mu[1]) v = S[0, 0] - S[0, 1] ** 2 / S[1, 1] print(round(m, 3), round(v, 3)) print(np.linalg.eigvalsh(S).round(3)) d = np.array([12., 26.]) - mu print(round(float(d @ np.linalg.solve(S, d)), 3))11.333 3.556 [3.298 9.702] 4.125শর্তসাপেক্ষ গড়: ১০ + (২/৯)(২৬ − ২০) = ১০ + ১.৩৩৩ = ১১.৩৩৩; variance: ৪ − ৪/৯ = ৩.৫৫৬. Eigenvalue: trace ১৩, det ৩২, তাই λ = (১৩ ± √(১৬৯ − ১২৮))/২ = (১৩ ± ৬.৪০৩)/২ = ৩.২৯৮ আর ৯.৭০২, ছোট থেকে বড় ক্রমে। শেষ লাইন: d = (২, ৬), Σ−1 = (১/৩২)[[9, −2], [−2, 4]], d² = (৯·৪ − ২·২·২·৬ + ৪·৩৬)/৩২ = (৩৬ − ৪৮ + ১৪৪)/৩২ = ১৩২/৩২ = ৪.১২৫. ছাপা ফরম্যাট একটি ডেস্কটপ run-এ যাচাই করা।
-
Parameter গোনা আর বাছাই: ৩টি শ্রেণি, ৩০টি feature, মোট ১৫০টি training সারি (প্রতি শ্রেণিতে ৫০)। (ক) LDA আর QDA-তে কতগুলো parameter অনুমান করতে হয় (গড়, covariance, prior)? (খ) কোনটি বেছে নেবেন, আর কেন? (গ) scikit-learn-এ কোন সেটিং চেষ্টা করবেন?
(ক) একটি ৩০ × ৩০ প্রতিসম Σ-এ ৩০·৩১/২ = ৪৬৫টি সংখ্যা। LDA: গড় ৩ × ৩০ = ৯০, এক Σ ৪৬৫, prior ২ (তিনটির যোগফল ১), মোট ৫৫৭. QDA: প্রতি শ্রেণিতে ৩০ + ৪৬৫ = ৪৯৫, তিনটিতে ১,৪৮৫, prior ২, মোট ১,৪৮৭. (খ) QDA-তে প্রতিটি Σk মাত্র ৫০টি সারি থেকে ৪৬৫টি সংখ্যা অনুমান করে; Σk invertible হলেও (৫০ − ১ = ৪৯ ≥ ৩০) তার ক্ষুদ্রতম eigenvalue অনেক ছোট আসবে, আর অনুমান খুব অস্থির। LDA তিন শ্রেণির ১৫০টি সারি মিলিয়ে একটি Σ অনুমান করে, অনেক স্থিতিশীল। তাই শুরু LDA দিয়ে। (গ)
LinearDiscriminantAnalysis(solver="lsqr", shrinkage="auto")(Ledoit–Wolf), আর QDA চাইলেreg_paramবা shrinkage-সহ; তারপর cross-validation-এ (পর্ব ০৪-এর মতো কয়েকটি seed-এ) তুলনা, সঙ্গে logistic regression আর একটি সরল baseline.
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমMahalanobis দূরত্ব দিয়ে outlier ধরার ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- Feature দেখে বাঁকা গুলোতে দরকারমতো log রূপান্তর
- μ আর Σ অনুমান (দরকার হলে MinCovDet-এর মতো robust পদ্ধতিতে)
- প্রতিটি সারির d² = (x − μ)ᵀΣ⁻¹(x − μ), solve বা Cholesky দিয়ে
- Feature সংখ্যা d অনুযায়ী χ²d-এর quantile থেকে সীমা
- সীমার ওপরের সারি চিহ্নিত করে কয়েকটি হাতে যাচাই
μ = (0, 0) আর Σ = [[4, 0], [0, 1]] হলে x = (2, 1) বিন্দুর Mahalanobis দূরত্ব কত?
- √5 ≈ 2.236
- √2 ≈ 1.414
- 2
- 1
দুই মাত্রার Gaussian-এ (x, y)-এর σy = 10 আর correlation ρ = 0.6. x জানা থাকলে y-এর শর্তসাপেক্ষ standard deviation কত?
- 10
- 6
- 64
- 8
তিনটি feature-এর Gaussian ডেটায় একটি বিন্দুর d² = 9. কোন সিদ্ধান্তটি সবচেয়ে সঠিক?
- ৯৫% সীমার বাইরে, কিন্তু ৯৯% সীমার ভেতরে
- d = 3, তাই নিশ্চিতভাবে চরম outlier
- একেবারে সাধারণ, কারণ গড় d² = 9
- Feature সংখ্যা জানা থাকলেও কিছু বলা যায় না
LDA-র সীমারেখা সরলরেখা (বা সমতল) হয় কেন?
- কারণ prior সমান ধরা হয়
- কারণ feature-গুলো স্বাধীন ধরা হয়
- কারণ সব শ্রেণির covariance এক ধরা হয়, তাই দ্বিঘাত পদ কেটে যায়
- কারণ এটি log loss কমিয়ে শেখে
৪০টি feature, ৩০টি সারি। নমুনার covariance S সম্পর্কে কোনটি সত্য?
- S-এর কিছু eigenvalue ঋণাত্মক
- S singular, তাই inverse নেই; shrinkage একটি invertible অনুমান দেয়
- n দিয়ে ভাগ করলে S invertible হয়
- S একটি নির্ভরযোগ্য অনুমান, কারণ unbiased
Σ = [[9, 0], [0, 1]]-এর একটি contour উপবৃত্তের লম্বা অক্ষ আর ছোট অক্ষের দৈর্ঘ্যের অনুপাত কত?
- 9
- 1
- 81
- 3
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- p(x) = (2π)−d/2(det Σ)−1/2exp(−½d²); d² = (x − μ)ᵀΣ−1(x − μ). বাস্তব কোডে log-density আর solve বা Cholesky.
- Contour উপবৃত্ত: অক্ষ Σ-এর eigenvector বরাবর, দৈর্ঘ্য c√λ; whitening করলে বৃত্ত, আর Mahalanobis = whitened দৈর্ঘ্য।
- Gaussian ডেটায় d² ~ χ²d: outlier-এর সীমা মাত্রার ওপর নির্ভর করে; masking আর বাঁকা ডেটা সাবধান।
- Marginal: সারি-কলাম মুছুন। Conditional: গড় μa + ΣabΣbb−1(xb − μb), একটি regression রেখা; covariance Schur complement, xb-নিরপেক্ষ।
- LDA (এক Σ, রৈখিক সীমা, logistic আকার) আর QDA (প্রতি শ্রেণির Σ, দ্বিঘাত সীমা); feature বেশি আর সারি কম হলে Ledoit–Wolf shrinkage.
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ২০ · Exponential family আর GLM — Poisson, binomial আর link functionপরবর্তী পর্বExponential family, link function, Poisson regression, IRLS আর overdispersion.
- মেশিন লার্নিং · কোর্স হোম৭৭টি পর্ব১৪টি মডিউলের পুরো রোডম্যাপ; পর্ব ২০ (Exponential family আর GLM) এখান থেকে খুলবেন।
- পর্ব ১০ · Positive definite matrix — quadratic form আর covarianceআগের পর্বCovariance কেন PSD, Cholesky আর x = μ + Lz দিয়ে নমুনা।
- পর্ব ০৮ · Eigenvalue আর eigenvectorআগের পর্বSpectral theorem আর PCA, যা থেকে উপবৃত্তের অক্ষ আসে।
- AI-এর ভিত্তি · পর্ব ৩৭ · ডেটার পরিসংখ্যানআগের ভিত্তিMean, variance, correlation, z-score আর CLT.
- AI-এর ভিত্তি · পর্ব ৫১ · Naive Bayesআগের ভিত্তিGenerative classifier-এর প্রথম পরিচয়, যার Gaussian রূপ কর্ণ-Σ-এর QDA.
- AI-এর ভিত্তি · পর্ব ৫৯ · Logistic regressionআগের ভিত্তিLDA-র discriminative যমজ: একই আকারের সীমা, ভিন্ন পথে শেখা।