উদ্দেশ্য: ANOVA একেবারে শূন্য থেকে প্রো লেভেল পর্যন্ত — কি, কেন, কিভাবে, ম্যানুয়াল হিসাব, CRD/RCBD ডিজাইন, Contrasts & Orthogonal Contrasts, One-Way Fixed-Effect ANOVA, Power/Sample Size — সবকিছু বাংলায় এবং ধাপে-ধাপে
Note: কোডগুলো বেস R-এ চলবে। যে অংশগুলোতে extra প্যাকেজ দরকার (যেমন car, multcomp, pwr) — সেগুলো ইনস্টল না থাকলে নীচের নির্দেশনা অনুযায়ী আগে ইনস্টল করে নিন।


1 1) ANOVA কী এবং কেন?

ANalysis Of VAriance (ANOVA) = ভ্যারিয়েন্স বিশ্লেষণ। লক্ষ্য: একাধিক গ্রুপের গড় (means) সমান কি না পরীক্ষা করা।
- শূন্য অনুমান (H₀): সব গ্রুপের গড় সমান \(\mu_1=\mu_2=\cdots=\mu_k\)
- বিকল্প (H₁): অন্তত একটি গড় আলাদা

কেন “ভ্যারিয়েন্স” দেখে “গড়” বিচার?
গ্রুপগুলোর গড় সত্যিই আলাদা হলে গ্রুপের মধ্যে (Between) ভ্যারিয়েন্স বাড়ে। আমরা BetweenWithin ভ্যারিয়েন্সের অনুপাত দেখি:
\(F = \dfrac{MS_{Between}}{MS_{Within}} = \dfrac{SS_B/(k-1)}{SS_W/(N-k)}\)

Assumptions:
1) Observations independent; 2) Errors are normal; 3) Group variances equal (homoscedastic).

চিত্র: F-বিতরণ ও ক্রিটিকাল অঞ্চল

curve(df(x, df1=2, df2=12), from=0, to=8, xlab="F", ylab="Density", main="F-বিতরণ (df1=2, df2=12)")
abline(v=qf(.95,2,12), lty=2)
text(qf(.95,2,12), 0.05, labels="Critical value (α=0.05)", pos=4, cex=.8)


2 2) One-Way Fixed-Effect ANOVA: মডেল ও ধারণা

মডেল:
\(y_{ij}=\mu+\tau_i+\varepsilon_{ij},\quad \varepsilon_{ij}\sim N(0,\sigma^2)\)
এখানে \(\tau_i\) হলো i-তম ট্রিটমেন্টের স্থির (fixed) প্রভাব

Sum of Squares:
- \(SS_T=\sum (y-\bar y_{\cdot\cdot})^2\) — মোট পরিবর্তন
- \(SS_B=\sum n_i(\bar y_{i\cdot}-\bar y_{\cdot\cdot})^2\) — গ্রুপের গড়ের মধ্যে পার্থক্য
- \(SS_W=SS_T-SS_B\) — গ্রুপের ভিতরের এলোমেলোতা

df ও Test: \(df_B=k-1\), \(df_W=N-k\), \(F=MS_B/MS_W\) যেখানে \(MS_B=SS_B/(k-1)\), \(MS_W=SS_W/(N-k)\)

বেল-কার্ভ (Normal) — রেসিডুয়ালস normal কিনা বোঝার ধারণা

curve(dnorm(x,0,1), -4, 4, xlab="z", ylab="density", main="Normal (Bell) Curve)")
abline(v=qnorm(c(.025,.975)), lty=2)


3 3) হাতে-কলমে (ম্যানুয়াল) হিসাব — একটি বাস্তব উদাহরণ

৩টি স্প্রে (A,B,C); প্রতিটি ৪টি পর্যবেক্ষণ।

dat <- data.frame(
  spray = rep(c("A","B","C"), each=4),
  count = c(12,15,14,13,  18,19,17,18,  11,10,12,9)
)
dat$spray <- factor(dat$spray)
dat

ধাপ-ধাপে SST/SSB/SSW:

k  <- nlevels(dat$spray)
n_i <- table(dat$spray)
N  <- nrow(dat)

grand_mean <- mean(dat$count)
means <- tapply(dat$count, dat$spray, mean)

SST <- sum( (dat$count - grand_mean)^2 )
SSB <- sum( n_i * (means - grand_mean)^2 )
SSW <- SST - SSB

dfB <- k - 1
dfW <- N - k
MSB <- SSB/dfB
MSW <- SSW/dfW
Fval <- MSB/MSW
pval <- pf(Fval, dfB, dfW, lower.tail = FALSE)

list(SST=SST, SSB=SSB, SSW=SSW, dfB=dfB, dfW=dfW, MSB=MSB, MSW=MSW, F=Fval, pvalue=pval)
## $SST
## [1] 126
## 
## $SSB
## [1] 114
## 
## $SSW
## [1] 12
## 
## $dfB
## [1] 2
## 
## $dfW
## [1] 9
## 
## $MSB
## [1] 57
## 
## $MSW
## [1] 1.333333
## 
## $F
## [1] 42.75
## 
## $pvalue
## [1] 2.538915e-05

একই জিনিস aov() দিয়ে:

fit <- aov(count ~ spray, data=dat)
summary(fit)
##             Df Sum Sq Mean Sq F value   Pr(>F)    
## spray        2    114   57.00   42.75 2.54e-05 ***
## Residuals    9     12    1.33                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Assumptions চেক: QQ-plot ও Residual vs Fitted

par(mfrow=c(1,2))
qqnorm(residuals(fit)); qqline(residuals(fit))
plot(fitted(fit), residuals(fit), xlab="Fitted", ylab="Residuals"); abline(h=0,lty=2)

par(mfrow=c(1,1))

সমভ্যারিয়েন্স (Levene’s test) — ইনস্টল থাকলে রান হবে

if (requireNamespace("car", quietly = TRUE)) {
  car::leveneTest(count ~ spray, data=dat, center = median)
} else {
  cat("Note: 'car' প্যাকেজ নেই। চালাতে চাইলে আগে Console এ install.packages('car') করুন।\n")
}

Post-hoc (Tukey HSD):

TukeyHSD(fit)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = count ~ spray, data = dat)
## 
## $spray
##     diff       lwr       upr     p adj
## B-A  4.5  2.220337  6.779663 0.0009765
## C-A -3.0 -5.279663 -0.720337 0.0127984
## C-B -7.5 -9.779663 -5.220337 0.0000193


4 4) ANOVA কীভাবে “টেস্ট” হয় — সিদ্ধান্তের লজিক

  • \(H_0\) সত্যি হলে \(F\approx 1\)
  • \(F\) যদি অনেক বড় হয় → Between variance, Within-এর তুলনায় বড় → \(H_0\) রিজেক্ট।

চিত্র: Already added (F curve)।


5 5) ANOVA-এর ধরন (Types) — সংক্ষেপ + উদাহরণ

5.1 5.1 One-Way ANOVA

একটি ফ্যাক্টর, বহু লেভেল (উপরে দেখানো হয়েছে)।

5.2 5.2 Two-Way ANOVA (ইন্টার‌্যাকশনসহ/ছাড়া)

set.seed(1)
dat2 <- expand.grid(A=c("Low","High"), B=c("Old","New"), rep=1:4)
dat2$y <- with(dat2, 10 + ifelse(A=="High",3,0) + ifelse(B=="New",2,0) +
                     ifelse(A=="High" & B=="New",2,0) + rnorm(nrow(dat2),0,2))
fit2 <- aov(y ~ A*B, data=dat2)
summary(fit2)
##             Df Sum Sq Mean Sq F value   Pr(>F)    
## A            1  46.07   46.07  15.306  0.00206 ** 
## B            1 104.72  104.72  34.788 7.27e-05 ***
## A:B          1  12.98   12.98   4.311  0.06002 .  
## Residuals   12  36.12    3.01                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

5.3 5.3 Repeated-Measures ANOVA

একই সাবজেক্টে ভিন্ন সময়/শর্তে মাপ → correlation থাকে। (উদাহরণ: প্রি/পোস্ট টেস্ট)

5.4 5.4 Mixed-Effects ANOVA

কিছু ফ্যাক্টর fixed, কিছু random (যেমন ব্লক random)। lme4/lmerTest সাধারণত ব্যবহৃত।


6 6) এক্সপেরিমেন্টাল ডিজাইন: CRD & RCBD — ধারণা + সম্পর্ক

6.1 6.1 CRD (Completely Randomized Design)

  • নমুনা ইউনিটগুলো একই ধরনের (homogeneous) হলে সবচেয়ে সহজ।
  • ট্রিটমেন্ট র‌্যান্ডমলি বরাদ্দ।
set.seed(42)
trt <- factor(rep(LETTERS[1:4], each=6))
y   <- 5 + c(0,1,2,3)[as.numeric(trt)] + rnorm(length(trt),0,1.5)
summary(aov(y ~ trt))
##             Df Sum Sq Mean Sq F value Pr(>F)  
## trt          3  21.39   7.129   2.453 0.0931 .
## Residuals   20  58.13   2.907                 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

6.2 6.2 RCBD (Randomized Complete Block Design)

  • ব্লক = তুলনামূলক সমজাতীয় গ্রুপ (দিন, মেশিন, মাঠের সারি)।
  • প্রতিটি ব্লকে সব ট্রিটমেন্ট একবার করে থাকে।
  • লাভ: ব্লকিং → ত্রুটির ভ্যারিয়েন্স কমে → ট্রিটমেন্ট ডিটেক্ট করা সহজ।
set.seed(7)
trt <- factor(rep(LETTERS[1:4], times=5))   # 4 treatment, 5 blocks
blk <- factor(rep(1:5, each=4))
y <- 10 + c(0,1,2,3)[as.numeric(trt)] + c(0,-1,0.5,1,-0.5)[as.numeric(blk)] + rnorm(length(trt),0,1)
summary(aov(y ~ trt + blk))
##             Df Sum Sq Mean Sq F value  Pr(>F)   
## trt          3  31.02  10.339   7.010 0.00559 **
## blk          4  38.15   9.538   6.467 0.00516 **
## Residuals   12  17.70   1.475                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

CRD vs RCBD সম্পর্ক: RCBD-তে ব্লক যোগ করলে অপ্রয়োজনীয় variation কাটে → MS_W কমেPower বাড়ে। তবে ডিজাইনের কনস্ট্রেইন্ট বাড়ে (প্রতি ব্লকে সব ট্রিটমেন্ট থাকতে হবে)।


7 7) Contrasts ও Orthogonal Contrasts — বিস্তারিত

Contrast: গ্রুপের গড়গুলোর লিনিয়ার কম্বিনেশন \(\sum c_i \mu_i\) যেখানে \(\sum c_i=0\)
- উদাহরণ: \(\mu_1-\mu_2\), বা \((\mu_1+\mu_2)/2 - \mu_3\)
Orthogonal: দুটি কনট্রাস্ট \(\mathbf{c},\mathbf{d}\) হলে balanced ক্ষেত্রে \(\sum c_i d_i=0\) হলে ওরা অরথোগোনাল। এতে কনট্রাস্টগুলো স্বাধীনভাবে তথ্য ভাগ করে, multiple testing burden কমে।

# Balanced 4-group উদাহরণ:
C1 <- c( 1,-1, 0, 0)          # μ1 vs μ2
C2 <- c( 0, 0, 1,-1)          # μ3 vs μ4
C3 <- c( 1, 1,-1,-1)          # (μ1+μ2) vs (μ3+μ4)

sum(C1*C2); sum(C1*C3); sum(C2*C3)  # 0 => balanced case-এ orthogonal
## [1] 0
## [1] 0
## [1] 0

R-এ কাস্টম কনট্রাস্ট টেস্ট (multcomp::glht) — প্যাকেজ থাকলে রান করুন

if (requireNamespace("multcomp", quietly = TRUE)) {
  library(multcomp)
  fit <- aov(count ~ spray, data=dat)   # dat আগেই আছে
  K <- rbind("A vs B" = c(1,-1,0),
             "A vs C" = c(1, 0,-1),
             "(A+B)/2 vs C" = c(0.5,0.5,-1))
  out <- glht(fit, linfct = mcp(spray = K))
  summary(out)
} else {
  cat("Note: 'multcomp' প্যাকেজ নেই। চালাতে চাইলে আগে Console এ install.packages('multcomp') করুন।\n")
}
## 
##   Simultaneous Tests for General Linear Hypotheses
## 
## Multiple Comparisons of Means: User-defined Contrasts
## 
## 
## Fit: aov(formula = count ~ spray, data = dat)
## 
## Linear Hypotheses:
##                   Estimate Std. Error t value Pr(>|t|)    
## A vs B == 0        -4.5000     0.8165  -5.511   <0.001 ***
## A vs C == 0         3.0000     0.8165   3.674   0.0116 *  
## (A+B)/2 vs C == 0   5.2500     0.7071   7.425   <0.001 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## (Adjusted p values reported -- single-step method)


8 8) Effect Size (η², Cohen’s f) ও Power ধারণা

  • \(\eta^2 = SS_B/SS_T\) → মোট বৈচিত্র্যের কত ভাগ ট্রিটমেন্ট ব্যাখ্যা করেছে।
  • \(f = \sqrt{\eta^2/(1-\eta^2)}\) → power/sample size-এ ব্যবহার।
  • Power = 1−β; α বাড়ালে (অন্যান্য অপরিবর্তিত) সাধারণত power বাড়ে, তবে Type I errorও বাড়ে।
SST <- sum( (dat$count - mean(dat$count))^2 )
SSB <- sum( table(dat$spray) * (tapply(dat$count, dat$spray, mean) - mean(dat$count))^2 )
eta2 <- SSB/SST
f <- sqrt(eta2/(1-eta2))
c(eta2=eta2, cohen_f=f)
##      eta2   cohen_f 
## 0.9047619 3.0822070


9 9) Sample Size Determination in R (One-Way Fixed ANOVA)

নীচের কোডটি pwr ইনস্টল থাকলে চলবে।

if (requireNamespace("pwr", quietly = TRUE)) {
  library(pwr)
  # উদাহরণ: k=3, Cohen's f=0.25, α=0.05, power=0.80
  pwr.anova.test(k=3, f=0.25, sig.level=0.05, power=0.80)
} else {
  cat("Note: 'pwr' প্যাকেজ নেই। Console এ install.packages('pwr') করে নিন।\n")
}
## 
##      Balanced one-way analysis of variance power calculation 
## 
##               k = 3
##               n = 52.3966
##               f = 0.25
##       sig.level = 0.05
##           power = 0.8
## 
## NOTE: n is number in each group

প্রফেসরের স্টাইল ব্যাখ্যা (between.var / within.var থেকে f নির্ণয়):
ধরি within.var ≈ σ² (প্রতি গ্রুপে একই ভ্যারিয়েন্স), আর গ্রুপ-গড়গুলোর ভ্যারিয়েন্স between.var। Balanced কেসে \(f^2\) আনুমানিকভাবে mean-ভ্যারিয়েন্স/within-ভ্যারিয়েন্স অনুপাত থেকে আসে।

k <- 4
f_min  <- 1*sqrt(1/(2*k))
f_mid  <- .5*sqrt((k+1)/(3*(k-1)))
f_max  <- .5
c(f_min=f_min, f_mid=f_mid, f_max=f_max)
##     f_min     f_mid     f_max 
## 0.3535534 0.3726780 0.5000000


10 10) Post-hoc Tests: LSD / Tukey HSD / Bonferroni — কখন কোনটা?

  • F-test significant হলে pairwise তুলনা।
  • Tukey HSD: একসাথে সব জোড়া নিয়ন্ত্রণ (ভালো ডিফল্ট)।
  • LSD: কম কড়া (FWER বাড়তে পারে)।
  • Bonferroni/Holm: সহজ, কনজারভেটিভ।
pairwise.t.test(dat$count, dat$spray, p.adjust.method = "bonferroni")
## 
##  Pairwise comparisons using t tests with pooled SD 
## 
## data:  dat$count and dat$spray 
## 
##   A      B      
## B 0.0011 -      
## C 0.0154 2.2e-05
## 
## P value adjustment method: bonferroni
TukeyHSD(aov(count ~ spray, data=dat))
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = count ~ spray, data = dat)
## 
## $spray
##     diff       lwr       upr     p adj
## B-A  4.5  2.220337  6.779663 0.0009765
## C-A -3.0 -5.279663 -0.720337 0.0127984
## C-B -7.5 -9.779663 -5.220337 0.0000193


11 11) রিপোর্টিং টেমপ্লেট (প্র্যাকটিক্যাল চেকলিস্ট)

  • ডিজাইন: CRD/RCBD; k গ্রুপ; N; প্রতি গ্রুপে n_i
  • Assumptions: QQ-plot, Levene → সিদ্ধান্ত
  • ANOVA টেবিল: SS, df, MS, F, p-value
  • Effect size: η² (বা partial η²)
  • Post-hoc/Contrasts: কোন জোড়া বা কনট্রাস্ট significant
  • Interpretation: বাস্তব/ব্যবসায়িক অর্থ (lift, delta mean)
  • Power/Sample size: pwr.anova.test() আউটপুট
anova(fit)    # মূল ANOVA টেবিল


12 12) “কখন কোন টেস্ট?” — চিটশিট

  • ২ গ্রুপ → t-test (Levene: var equal? equal হলে pooled; না হলে Welch)
  • ৩+ গ্রুপ, এক ফ্যাক্টর → One-Way ANOVA; তারপর Tukey/Contrasts
  • হেটারোজেনিটি বেশি হলে → RCBD/ব্লকিং ভাবুন
  • ২ ফ্যাক্টর → Two-Way (interaction?)
  • Repeated measures/Mixed → উপযুক্ত RM-ANOVA/মিশ্র মডেল

শেষ কথা: উপরের .Rmd রান করলেই বেসিক→প্রো সব ধাপ আপনার সামনে টেবিল/গ্রাফসহ চলে আসবে।