Skip to content

সমাধান — অধ্যায় ১.৩ · Distributions & Visualization

এই ফাইলে ১.৩ অধ্যায়ের সব অনুশীলনীর পূর্ণ সমাধান। কোড-প্রশ্নে seed fixed থাকায় নিচের সংখ্যা হুবহু পুনরুৎপাদনযোগ্য; প্রকৃত output দেওয়া আছে।


Conceptual

সমাধান ১ — histogram বনাম bar chart [easy]

দুটি মৌলিক পার্থক্য:

  • x-অক্ষের data-ধরন: histogram-এর x-অক্ষ continuous সংখ্যা (একটি পরিসরকে bin-এ ভাগ করা হয়), যেমন উচ্চতা বা আয়। bar chart-এর x-অক্ষ categorical (আলাদা, অ-সংখ্যাগত বিভাগ), যেমন browser-এর নাম বা রং।
  • বারের মাঝের ফাঁক: histogram-এ বারগুলো লাগোয়া (no gap), কারণ bin-গুলো সংখ্যারেখার ধারাবাহিক টুকরো — একটি bin শেষ হলেই পরেরটি শুরু। bar chart-এ বারগুলোর মাঝে ফাঁক রাখা হয়, কারণ বিভাগগুলো পরস্পর সম্পর্কহীন/অসংলগ্ন।

উপযুক্ত উদাহরণ: histogram — ৫০০ জন প্রাপ্তবয়স্কের উচ্চতা (continuous)। bar chart — ৫০০ জন কোন মোবাইল-ব্র্যান্ড ব্যবহার করে (categorical)।

সমাধান ২ — mean = 50, median = 38 [easy]

  • (ক) skew-এর দিক: \(\text{mean}=50 > \text{median}=38\), অর্থাৎ right-skewed (ধনাত্মক skew)। নিয়ম: mean \(>\) median হলে লেজ ডানে (§২.৭, §৪.৩)।
  • (খ) লেজ: histogram-এর ডান দিকে লম্বা, পাতলা লেজ — কারণ অল্প কিছু বড় মান mean-কে median-এর ডানে টেনেছে।
  • (গ) বাস্তব উদাহরণ: আয়/বেতন, বাড়ির দাম, শহরের জনসংখ্যা, ওয়েবসাইটে সেশন-সময় — এসবই সাধারণত right-skewed (বেশির ভাগ মান ছোট, কিছু মান অনেক বড়)।

সমাধান ৩ — KDE bandwidth ও smoothing trade-off [medium]

  • \(h\) খুব ছোট (under-smoothing): প্রতিটি data-বিন্দুর ঢিবি সরু হয়, ফলে curve কাঁটাকাঁটা ও কোলাহলপূর্ণ — random ওঠানামাকে ভুল করে "গঠন" ভেবে নেওয়ার ঝুঁকি (যেমন একটি unimodal data-তে বহু ভুয়া ছোট চূড়া)।
  • \(h\) খুব বড় (over-smoothing): ঢিবি চওড়া হয়ে সব মিলেমিশে যায়, curve অতিমসৃণ — আসল বৈশিষ্ট্য (যেমন bimodality বা skew) ধুয়ে মুছে যায়।
  • equivalent (সমতুল্য) প্যারামিটার: histogram-এর bin-প্রস্থ (বা bin-সংখ্যা) হলো \(h\)-এর equivalent। দুটোই একটি smoothing trade-off: কম smoothing (সরু bin / ছোট \(h\)) → বেশি variance, বেশি noise; বেশি smoothing (চওড়া bin / বড় \(h\)) → বেশি bias, আসল গঠন-হানি। লক্ষ্য — এমন একটি মধ্যপন্থা যা noise দমন করে অথচ প্রকৃত আকৃতি ধরে রাখে (Silverman-এর মতো থাম্ব-রুল এই ভারসাম্যের একটি স্বয়ংক্রিয় চেষ্টা)।

সমাধান ৪ — boxplot না violin (চারটি কারখানা) [medium]

Violin plot বেছে নেব। মূল কারণ modality: সন্দেহ হলো কোনো কারখানায় দুটি ভিন্ন মেশিন থেকে অংশ মিশছে, অর্থাৎ সেই কারখানার ওজন-distribution bimodal (দুই চূড়া) হবে। কিন্তু boxplot কেবল পাঁচ-সংখ্যা সারাংশ (min, \(Q_1\), median, \(Q_3\), max) দেখায় — একটি bimodal distribution আর একটি প্রশস্ত unimodal distribution-এর এই পাঁচটি সংখ্যা প্রায় একই হতে পারে, তাই boxplot দুই চূড়া পুরোপুরি লুকিয়ে ফেলবে। violin plot প্রতিটি দলের পূর্ণ density আঁকে, ফলে দুটি মেশিনের মিশ্রণ থাকলে সেই কারখানার violin-এ দুটি স্পষ্ট ফোলা অংশ দেখা যাবে। চারটি দল পাশাপাশি তুলনাও violin-এ সহজ। (§২.৪, §৬ Figure 2 এই পার্থক্যই দেখায়।)

সমাধান ৫ — ECDF কেন arbitrary নির্বাচন-মুক্ত [hard]

দাবির ব্যাখ্যা: histogram বানাতে আমাদের bin-সংখ্যা ও bin-সীমানা বেছে নিতে হয়; KDE বানাতে kernel ও bandwidth \(h\) বেছে নিতে হয়। এই নির্বাচনগুলো arbitrary — একই data ভিন্ন bin/bandwidth-এ ভিন্ন চেহারা দেখাতে পারে, এমনকি bin-সীমানা সামান্য সরালেই আকৃতি বদলায়। বিপরীতে ECDF-এর সংজ্ঞা \(\hat{F}_n(t)=\#\{x_i\le t\}/n\)-তে কোনো প্যারামিটার নেই: এটি সরাসরি প্রতিটি observation থেকে নির্ধারিত। প্রতিটি data-বিন্দু ঠিক \(1/n\) ভর হিসেবে নিজের মানে যোগ হয়, কোনো গড় বা গোষ্ঠীকরণ (grouping) হয় না — তাই কোনো তথ্য হারায় না এবং একই data সবসময় ঠিক একই ECDF দেয়। এই অর্থেই ECDF "পুরো data কোনো arbitrary নির্বাচন ছাড়াই" ধরে রাখে।

§৪.২-এর শর্ত (অ-হ্রাসমানতা, নিজের ভাষায়): \(t\) বাড়ালে "\(t\) বা তার চেয়ে ছোট" এমন observation-এর সংখ্যা কখনো কমতে পারে না — আগে যেসব বিন্দু গণনায় ছিল, \(t\) আরও বড় হলেও তারা গণনায় থাকেই, উপরন্তু নতুন বিন্দু যোগ হতে পারে। তাই count, এবং তাই \(\hat{F}_n(t)\), \(t\)-এর সাথে অ-হ্রাসমান। (বিকল্পে — সীমা: \(t\) যথেষ্ট ছোট হলে কোনো বিন্দুই \(\le t\) নয়, তাই \(\hat{F}_n=0\); \(t\) যথেষ্ট বড় হলে সব বিন্দু \(\le t\), তাই \(\hat{F}_n=1\)।)


Computational

সমাধান ৬ — হাতে \(\{1,2,2,3,3,3,4,9\}\) [easy]

\(n=8\)। sorted: \(1,2,2,3,3,3,4,9\)

(ক) frequency table (bin-প্রস্থ \(2\)):

bin count relative freq
\([0,2)\) 1 \(1/8 = 0.125\)
\([2,4)\) 5 \(5/8 = 0.625\)
\([4,6)\) 1 \(1/8 = 0.125\)
\([6,8)\) 0 \(0\)
\([8,10)\) 1 \(1/8 = 0.125\)

(মানগুলো: \(1\) পড়ে \([0,2)\)-তে; \(2,2,3,3,3\) পড়ে \([2,4)\)-তে; \(4\) পড়ে \([4,6)\)-তে; \(9\) পড়ে \([8,10)\)-তে। যোগফল \(=8\), relative-যোগফল \(=1\)।)

(খ) ECDF: $$ \hat{F}_n(3) = \frac{#{x_i\le 3}}{8} = \frac{6}{8} = 0.75, \qquad \hat{F}_n(4) = \frac{#{x_i\le 4}}{8} = \frac{7}{8} = 0.875 . $$

(গ) skew-এর দিক: mean \(=(1+2+2+3+3+3+4+9)/8 = 27/8 = 3.375\); median = মাঝের দুই মান \(x_{(4)}=3,\,x_{(5)}=3\)-এর গড় \(=3.0\)। mean \(=3.375 > \text{median}=3.0\)right-skewed (মানটি \(9\) ডানদিকে লেজ তৈরি করে mean-কে টেনেছে)।

সমাধান ৭ — gamma data ECDF ও skewness [medium]

import numpy as np
from scipy import stats

rng = np.random.default_rng(2025)
data = rng.gamma(shape=2.0, scale=10.0, size=200)

# from scratch ECDF
xs = np.sort(data)
ys = np.arange(1, data.size + 1) / data.size

q1, med, q3 = np.quantile(data, [0.25, 0.5, 0.75])
print(f"Q1={q1:.3f}  median={med:.3f}  Q3={q3:.3f}")

# skewness from scratch (population std, moment-সংজ্ঞা)
xbar = data.mean(); s = data.std(ddof=0)
g1 = ((data - xbar)**3).mean() / s**3
print(f"g1 scratch = {g1:.4f}   scipy.skew = {stats.skew(data):.4f}")

Output:

Q1=9.186  median=19.037  Q3=27.966
g1 scratch = 1.2249   scipy.skew = 1.2249

scratch ও scipy.stats.skew হুবহু মেলে (\(g_1 \approx 1.225\) — ধনাত্মক, gamma right-skewed)। ECDF থেকে median যাচাই: np.mean(data <= med) \(\approx 0.50\), অর্থাৎ \(\hat{F}_n(\text{median})=0.5\) — সংজ্ঞার সাথে সঙ্গতিপূর্ণ। (np.quantile-এর median আর np.median একই; \(Q_1,Q_3\) linear-interpolation default-এ গণিত।)

সমাধান ৮ — browser bar chart [medium]

(ক) proportion: মোট \(= 640+210+90+60 = 1000\)। $$ \text{Chrome} = \frac{640}{1000} = 0.64,\quad \text{Safari} = 0.21,\quad \text{Firefox} = 0.09,\quad \text{Edge} = 0.06 . $$ (যোগফল \(=1.00\)।)

(খ) কোড — count অনুসারে অবরোহী, বারের উপর label:

import matplotlib; matplotlib.use("Agg")
import numpy as np, matplotlib.pyplot as plt

names  = np.array(["Chrome", "Safari", "Firefox", "Edge"])
counts = np.array([640, 210, 90, 60])
order  = np.argsort(counts)[::-1]            # অবরোহী সাজানো
names, counts = names[order], counts[order]

fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.bar(names, counts, color="#1f77b4", alpha=0.85, edgecolor="white")
ax.bar_label(bars, padding=2)               # প্রতিটি বারের উপর count
ax.set_ylabel("Count"); ax.set_title("Browser usage")
ax.grid(True, axis="y", alpha=0.3); ax.grid(False, axis="x")
plt.tight_layout()
# plt.savefig("browser_bar.png", dpi=150)
এখানে data ইতিমধ্যেই অবরোহী, তবু argsort(...)[::-1] সাধারণ ক্ষেত্রে সঠিক ক্রম নিশ্চিত করে।

(গ) histogram কেন অর্থহীন: browser-এর নাম categorical — এদের কোনো সংখ্যাগত মান বা প্রাকৃতিক ক্রম নেই, তাই এদের "bin"-এ ভাগ করার ধারণাই অর্থহীন; count গুনে bar chart-ই সঠিক উপস্থাপন।

সমাধান ৯ — skewness ও log-রূপান্তর [hard]

import numpy as np
from scipy import stats

rng = np.random.default_rng(2025)
data = rng.gamma(shape=2.0, scale=10.0, size=200)

print(f"mean={data.mean():.3f}  median={np.median(data):.3f}  skew={stats.skew(data):.4f}")
logd = np.log(data)
print(f"after log: skew={stats.skew(logd):.4f}  mean={logd.mean():.3f}  median={np.median(logd):.3f}")

Output:

mean=20.621  median=19.037  skew=1.2249
after log: skew=-0.9726  mean=2.705  median=2.946

মূল gamma data দৃঢ়ভাবে right-skewed (\(g_1\approx +1.22\), এবং mean \(>\) median)। \(\log\) নেওয়ার পর skew কমে ঋণাত্মক দিকে চলে গেছে (\(\approx -0.97\), এবং এখন mean \(<\) median)।

ব্যাখ্যা: \(\log\) একটি concave (নিম্নমুখী-বক্র) রূপান্তর — এটি বড় মানগুলোকে অনেক বেশি সংকুচিত করে, ছোট মানগুলোকে অপেক্ষাকৃত ছড়িয়ে দেয়; তাই এটি ডান-লেজ টেনে ছোট করে এবং right-skew কমায়। এই প্রভাব এত শক্তিশালী যে এখানে এটি skew-কে শূন্য পেরিয়ে হালকা left-skew-এ নিয়ে গেছে — অর্থাৎ log একটু "অতি-সংশোধন" করেছে। মূল শিক্ষা: log-রূপান্তর right-skewed (বিশেষত গুণনাত্মক/lognormal-ধরনের) data-কে অনেক বেশি প্রতিসম করে তোলে — এজন্যই আয়, দাম ইত্যাদিকে প্রায়ই log-scale-এ বিশ্লেষণ করা হয়; তবে রূপান্তরের মাত্রা data-র উপর নির্ভর করে এবং কখনো সামান্য বিপরীত দিকেও যেতে পারে।

সমাধান ১০ — QQ-plot: normal বনাম exponential বনাম \(t\) [hard]

অনুমান (ছবি আঁকার আগে): - normal: বিন্দু সরল রেখায় লেপ্টে থাকবে (data সত্যিই normal)। - exponential (right-skewed): ডান প্রান্তে বিন্দু রেখার উপরে উঠে যাবে (লম্বা ডান-লেজ), বাঁ প্রান্ত মোটামুটি রেখায় — সামগ্রিকভাবে উপরে-বাঁকা (convex)। - Student-\(t\), df=3 (heavy-tailed, symmetric / প্রতিসম): উভয় প্রান্তেই বিন্দু রেখা থেকে সরে যাবে — বাঁ প্রান্ত রেখার নিচে, ডান প্রান্ত রেখার উপরে — অর্থাৎ একটি লম্বা-করা "S"/চাবুক আকৃতি, কারণ দুই দিকেই normal-এর চেয়ে ভারী লেজ।

কোড:

import matplotlib; matplotlib.use("Agg")
import numpy as np, matplotlib.pyplot as plt
from scipy import stats

rng = np.random.default_rng(99)
a = rng.normal(0, 1, 500)          # normal
b = rng.exponential(1.0, 500)      # right-skewed
c = rng.standard_t(df=3, size=500) # heavy-tailed

fig, axes = plt.subplots(1, 3, figsize=(15, 4.5))
for ax, d, title in [(axes[0], a, "normal"),
                     (axes[1], b, "exponential (right-skew)"),
                     (axes[2], c, "Student-t df=3 (heavy tail)")]:
    stats.probplot(d, dist="norm", plot=ax)
    ax.set_title(title)
plt.tight_layout()
# plt.savefig("qq_three.png", dpi=150)

যাচাইকারী পরিসংখ্যান (output):

normal   skew=-0.186  exkurt=+0.054   min=-3.16  max= 3.01
exp      skew=+2.206  exkurt=+9.561   min= 0.00  max= 9.82
t3       skew=+1.781  exkurt=+19.005  min=-5.44  max=15.17

ব্যাখ্যা ও মিল: - normal: skew \(\approx 0\), excess kurtosis \(\approx 0\) — QQ-plot-এ বিন্দু রেখায়, অনুমান নিশ্চিত। - exponential: skew \(\approx +2.2\) (দৃঢ় right-skew) এবং সব মান \(\ge 0\) — তাই QQ-plot-এ ডান প্রান্ত রেখার উপরে উঠে convex বাঁক; বাঁ প্রান্ত \(0\)-তে থেমে রেখার সামান্য উপরে। অনুমান নিশ্চিত। - \(t\), df=3: skew মাঝারি ধনাত্মক হলেও মূল গল্প প্রচণ্ড excess kurtosis (\(\approx +19\)) ও দুই দিকে চরম মান (min \(-5.44\), max \(+15.17\)) — তাই QQ-plot-এ উভয় প্রান্ত রেখা থেকে সরে যায় (দুই দিকেই ভারী লেজ), যা heavy-tailed-এর স্বাক্ষর। অনুমান নিশ্চিত।

মূল শিক্ষা: QQ-plot-এ বাঁক কোথায় ও কোন দিকে তা থেকেই skew (এক-প্রান্তের বাঁক) আর heavy-tail (দুই-প্রান্তের বাঁক) আলাদা করা যায় — কেবল একটিমাত্র সংখ্যার (যেমন skew) চেয়ে অনেক বেশি তথ্য চোখে