ANOVA Test (R)

इस पोस्ट में, मैं Anova hypothesis testing पर ध्यान देना चाहता हूँ। डेटा-सेट जो मैं उपयोग करने जा रहा हूँ, वह https://smartcities.data.gov.in पर प्रकाशित है, जो कि भारत सरकार का एक प्रोजेक्ट है जो National Data Sharing and Accessibility Policy के तहत आता है।

मैं यह विश्लेषण करना चाहता हूँ कि क्या बैंगलोर में बेरोजगारी समान है या क्या कुछ क्षेत्रों में उच्च बेरोजगारी है। Unemployment_Rate_Bengaluru.csv डेटा सेट में बैंगलोर में वार्ड स्तर पर कुल रोजगार और बेरोजगार लोगों की जानकारी है। सरलता के लिए, मैं तीन क्षेत्रों पर ध्यान केंद्रित करना चाहता हूँ: बैंगलोर-पूर्व, महादेवपुरा और राजेश्वरी नगर।

चूंकि मैं यह परीक्षण करना चाहता हूँ कि बैंगलोर के विभिन्न क्षेत्रों में बेरोजगारी दर में महत्वपूर्ण अंतर है या नहीं, शून्य और वैकल्पिक परिकल्पना इस प्रकार होगी:
$$ H_0: \mu_{Bangalore-east} = \mu_{Mahadevpura} = \mu_{Rajeshwari-Nagar} $$
$$ H_1: Not\, all\, \mu\, are\, equal $$

नमूना बेरोजगारी डेटा सेट:

नमूना डेटा
cityName zoneName wardName wardNo unemployed.no employed.no total.labour rate
Bengaluru East Manorayana Palya 167 19011 13745 32756 0.5803822
Bengaluru East Ganga Nagar 154 18294 14346 32640 0.5604779
Bengaluru Mahadevapura Basavanapura 187 27146 22061 49207 0.5516695
Bengaluru Mahadevapura Ramamurthy Nagar 26 27085 20273 47358 0.5719203
Bengaluru East Radhakrishna Temple Ward 18 20081 15041 35122 0.5717499

प्रत्येक क्षेत्र में बेरोजगारी के अंतर को विज़ुअलाइज़ करना।

ggplot(unemployment, aes(x=zoneName, y= rate, group = zoneName)) + 
  geom_boxplot() +
  labs(x='Zone', y='Unemployment %') + 
  theme_minimal()

विभिन्न क्षेत्रों में बेरोजगारी के सारांश सांख्यिकी इस प्रकार हैं:

data.summary <- unemployment %>% 
  rename(group = zoneName) %>% 
  group_by(group) %>% 
  summarise(count = n(), 
            mean = mean(rate),
            sd = sd(rate),
            skewness = skewness(rate),
            kurtosis = kurtosis(rate))
data.summary
## # A tibble: 3 x 6
##   group               count  mean     sd skewness kurtosis
##   <chr>               <int> <dbl>  <dbl>    <dbl>    <dbl>
## 1 East                   81 0.574 0.0361 -0.228      0.747
## 2 Mahadevapura           24 0.567 0.0449 -0.812      1.69 
## 3 Rajarajeswari Nagar    18 0.548 0.0499  0.00421   -1.24

उपरोक्त तालिका से मैं देखता हूँ कि बेरोजगारी दर सभी तीन क्षेत्रों में 54% से 57% के बीच है।

ANOVA करने की एक शर्त यह है कि जनसंख्या प्रतिक्रिया चर प्रत्येक समूह में सामान्य वितरण का पालन करता है। विभिन्न क्षेत्रों में बेरोजगारी दर का वितरण इस प्रकार है:

ggplot() + 
  geom_density(data=unemployment, aes(x=rate, group=zoneName, color=zoneName), adjust=2) +
  labs(x = 'Unemployment Rate', y='Density',  title = 'Testing normality among response variables') +
  theme_minimal()+theme(legend.position="bottom")

उपरोक्त ग्राफ से, ऐसा लगता है कि तीन समूह सामान्य रूप से वितरित हैं। सामान्यता के लिए परीक्षण करने के लिए, हम Shapiro-Wilk परीक्षण का उपयोग कर सकते हैं।
प्रत्येक समूह के लिए परीक्षण की परिकल्पना इस प्रकार होगी:
\(H_0\): समूह में बेरोजगारी दर सामान्य रूप से वितरित है
\(H_1\): समूह में बेरोजगारी दर सामान्य रूप से वितरित नहीं है

for(i in 1:nrow(data.summary)){
  test.dist <- (unemployment %>% dplyr::filter(zoneName == data.summary$group[i]))$rate
  cat('Testing for group ', data.summary$group[i], '\n')
  print(shapiro.test(test.dist))
  norm.plot <- ggplot() + 
    geom_qq(aes(sample = test.dist)) +
    stat_qq_line(aes(sample = test.dist)) +
    ggtitle(paste0("Normal distribution Q-Q plot for group ",data.summary$group[i])) +
    theme_minimal()
  plot(norm.plot)
}
## Testing for group  East 
## 
##  Shapiro-Wilk normality test
## 
## data:  test.dist
## W = 0.97147, p-value = 0.06734

## Testing for group  Mahadevapura 
## 
##  Shapiro-Wilk normality test
## 
## data:  test.dist
## W = 0.90815, p-value = 0.03216

## Testing for group  Rajarajeswari Nagar 
## 
##  Shapiro-Wilk normality test
## 
## data:  test.dist
## W = 0.95852, p-value = 0.5734

चूंकि \(p > \alpha\), जहाँ \(\alpha = 0.01\), सभी तीन समूहों में शून्य परिकल्पना को बनाए रखा जा रहा है। इसलिए, हम मान सकते हैं कि सभी समूहों में बेरोजगारी दर सामान्य रूप से वितरित है।

ANOVA के लिए एक और शर्त यह है कि जनसंख्या के विविधताओं को समान माना जाता है। यह एक अनुमान है जिसे मैं इस समय लेना चाहता हूँ।

इन अनुमानों को लेते हुए, नमूने के आदर्श वितरण इस प्रकार हैं। इन वितरणों की तुलना एक simulation से की जा सकती है जिसे मैंने बनाया है, जहाँ F मान (और ANOVA की महत्वता) को समूह के औसत के बीच की दूरी बढ़ाकर देखा जा सकता है।

plot.normal.groups <- function(data.summary, mean, sd, label, title){
  common.group.sd <- mean(data.summary$sd)
  range <- seq(mean-3*sd, mean+3*sd, by = sd*0.001)
  norm.dist <- data.frame(range = range, dist = dnorm(x = range, mean = mean, sd = sd))
  # Plotting sampling distribution and x_bar value with cutoff
  norm.aov.plot <- ggplot(data = norm.dist, aes(x = range,y = dist))
  for (i in 1:nrow(data.summary)) {
    norm.aov.plot <- norm.aov.plot + 
      stat_function(fun = dnorm, color=colors()[sample(50:100, 1)],  size = 1, 
                    args = list(mean = data.summary$mean[i], sd = common.group.sd))
  }
  norm.aov.plot + labs(x = label, y='Density',  title = title) +
      theme_minimal()+theme(legend.position="bottom")
}
set.seed(9)
mean <- mean(unemployment$rate)
sd <- sd(unemployment$rate)
plot.normal.groups(data.summary, mean, sd, 'Travel time (sec)', 'Assuming normality among response variables')

ANOVA करने के लिए
$$ H_0: \mu_{Bangalore-east} = \mu_{Mahadevpura} = \mu_{Rajeshwari-Nagar} $$
$$ H_1: Not\, all\, \mu\, are\, equal $$

# Functions used in anova-test

f.plot <- function(pop.mean=0, alpha = 0.05, f, df1, df2,
                              label = 'F distribution',title = 'Anova test'){
  # Creating a sample F distribution
  range <- seq(qf(0.0001, df1, df2), qf(0.9999, df1, df2), by = (qf(0.9999, df1, df2)-qf(0.0001, df1, df2))*0.001)
  f.dist <- data.frame(range = range, dist = df(x = range, ncp = pop.mean, df1 = df1, df2 = df2)) %>% 
    dplyr::mutate(H0 = if_else(range <= qf(p = 1-alpha, ncp = pop.mean, df1 = df1,df2 = df2),'Retain', 'Reject'))
  # Plotting sampling distribution and F value with cutoff
  plot.test <- ggplot(data = f.dist, aes(x = range,y = dist)) +
    geom_area(aes(fill = H0)) +
    scale_color_manual(drop = TRUE, values = c('Retain' = "#00BFC4", 'Reject' = "#F8766D"), aesthetics = 'fill') +
    geom_vline(xintercept = f, size = 2) +
    geom_text(aes(x = f, label = paste0('F = ', round(f,3)), y = mean(dist)), colour="blue", vjust = 1.2) +
    labs(x = label, y='Density',  title = title) +
    theme_minimal()+theme(legend.position="bottom")
  plot(plot.test)
}
anva <- aov(rate ~ zoneName, unemployment)
anova.summary <- summary(anva)
print(anova.summary)
##              Df  Sum Sq  Mean Sq F value Pr(>F)  
## zoneName      2 0.01065 0.005323   3.315 0.0397 *
## Residuals   120 0.19269 0.001606                 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
f.plot(f = anova.summary[[1]]$F[1], df1 = anova.summary[[1]]$Df[1], df2 = anova.summary[[1]]$Df[2])

यहाँ \(p < \alpha\), जहाँ \(\alpha = 0.05\) इसलिए शून्य परिकल्पना को अस्वीकार किया जा रहा है। इस परीक्षण से हम देख सकते हैं कि सभी समूहों का औसत समान नहीं है। लेकिन यह जानने के लिए कि कौन से समूह समान हैं और कौन से भिन्न हैं, मैं TukeyHSD परीक्षण कर रहा हूँ।

tukey.test <- TukeyHSD(anva)
print(tukey.test)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = rate ~ zoneName, data = unemployment)
## 
## $zoneName
##                                          diff         lwr          upr
## Mahadevapura-East                -0.007071899 -0.02917267  0.015028872
## Rajarajeswari Nagar-East         -0.026768634 -0.05154855 -0.001988723
## Rajarajeswari Nagar-Mahadevapura -0.019696735 -0.04934803  0.009954561
##                                      p adj
## Mahadevapura-East                0.7285538
## Rajarajeswari Nagar-East         0.0309193
## Rajarajeswari Nagar-Mahadevapura 0.2597730
# Plot pairwise TukeyHSD comparisons and color by significance level
tukey.df <- as.data.frame(tukey.test$zoneName)
tukey.df$pair = rownames(tukey.df)
ggplot(tukey.df, aes(colour=cut(`p adj`, c(0, 0.01, 0.05, 1), 
                           label=c("p<0.01","p<0.05","Non-Sig")))) +
  geom_hline(yintercept=0, lty="11", colour="grey30") +
  geom_errorbar(aes(pair, ymin=lwr, ymax=upr), width=0.2) +
  geom_point(aes(pair, diff)) +
  labs(x = 'Groups', y='Density',  colour="", title = 'Tukey HSD Test') +
    theme_minimal()+theme(legend.position="bottom")

इस परीक्षण से हम देख सकते हैं कि राजेश्वरी नगर और बैंगलोर पूर्व के बीच महत्वपूर्ण अंतर है (जिसका \(\alpha = 0.05\) विश्वास स्तर है)।

Back to top