Zapoznaj się ze składnią i działaniem następujących funkcji w pakiecie R: sample(), rnorm(), replicate(), boot (pakiet boot), boot.ci (pakiet boot).
library(foreign)
dane <- read.spss("D:/Users/Mateusz/Desktop/dane.sav", to.data.frame = TRUE)
attach(dane)
dochod<-Dochod_na_osobe
#punktowo klasycznie
mean(dochod)
## [1] 808.5322
sd(dochod)
## [1] 1064.67
se<-sd(dochod)/sqrt(length(dochod))
se
## [1] 6.146569
sep<-se/mean(dochod)
sep
## [1] 0.007602133
#przedziałowo klasycznie
mean(dochod)-1.96*se #dolna krawędź
## [1] 796.4849
mean(dochod)+1.96*se #górna krawędź
## [1] 820.5794
# 1.96 to kwantyl rozkładu normalnego dla 95% ufności
Wyniki dla różnych wielkości próby:
Dla wielkości próby ‘r nobs=50’ otrzymujemy: - średnią próbkową: ‘r mean_boot’ - odchylenie standardowe: ‘r sd_boot’ - błąd standardowy: ‘r se2’ - procentowy błąd standardowy: ‘r sep2’ - dolną krawędź przedziału ufności: ‘r dolny’ - górną krawędź przedziału ufności: ‘r gorny’
Porównaj wyniki z obu metod.
Jakie są wnioski? Czy różnice są istotne? Jak wielkość resamplingu wpływa na wyniki?
set.seed(123)
dochod <- rnorm(1000, mean = 800, sd = 1000)
mean_classic <- mean(dochod)
sd_classic <- sd(dochod)
se_classic <- sd_classic / sqrt(length(dochod))
sep_classic <- se_classic / mean_classic
dolny_classic <- mean_classic - 1.96 * se_classic
gorny_classic <- mean_classic + 1.96 * se_classic
results <- data.frame(
nobs = integer(),
mean_boot = numeric(),
sd_boot = numeric(),
se2 = numeric(),
sep2 = numeric(),
dolny = numeric(),
gorny = numeric()
)
B <- 999
sample_sizes <- c(50, 250, 500, 1000, 10000)
for (nobs in sample_sizes) {
mean_dochod <- rep(0, B)
for (i in 1:B) {
boot.data <- sample(dochod, nobs, replace = TRUE)
mean_dochod[i] <- mean(boot.data)
}
mean_boot <- mean(mean_dochod)
sd_boot <- sd(mean_dochod)
se2 <- sd_boot / sqrt(nobs)
sep2 <- se2 / mean_boot
dolny <- mean_boot - 1.96 * se2
gorny <- mean_boot + 1.96 * se2
results <- rbind(results, data.frame(
nobs = nobs,
mean_boot = mean_boot,
sd_boot = sd_boot,
se2 = se2,
sep2 = sep2,
dolny = dolny,
gorny = gorny
))
}
print("Wyniki klasyczne:")
## [1] "Wyniki klasyczne:"
print(data.frame(
mean_classic = mean_classic,
sd_classic = sd_classic,
se_classic = se_classic,
sep_classic = sep_classic,
dolny_classic = dolny_classic,
gorny_classic = gorny_classic
))
## mean_classic sd_classic se_classic sep_classic dolny_classic gorny_classic
## 1 816.1279 991.695 31.36015 0.03842553 754.662 877.5938
print("Wyniki bootstrapowe dla różnych nobs:")
## [1] "Wyniki bootstrapowe dla różnych nobs:"
print(results)
## nobs mean_boot sd_boot se2 sep2 dolny gorny
## 1 50 817.8213 142.860264 20.20349231 0.0247040425 778.2225 857.4201
## 2 250 815.4398 62.041303 3.92383652 0.0048119267 807.7491 823.1305
## 3 500 817.2049 43.816204 1.95952021 0.0023978322 813.3642 821.0456
## 4 1000 816.9679 30.381089 0.96073439 0.0011759756 815.0849 818.8510
## 5 10000 816.3110 9.473752 0.09473752 0.0001160557 816.1254 816.4967
library(ggplot2)
ggplot(results, aes(x = as.factor(nobs), y = mean_boot)) +
geom_point(size = 3) +
geom_errorbar(aes(ymin = dolny, ymax = gorny), width = 0.2) +
labs(
title = "Bootstrapowe średnie i przedziały ufności",
x = "Liczba próbek (nobs)",
y = "Średnia bootstrapowa"
) +
theme_minimal()
Wnioski: Porównanie wyników klasycznych i bootstrapowych pokazuje, że obie metody dają zbliżone średnie, co wskazuje na zgodność w estymacji wartości centralnej. Różnice pojawiają się w odchyleniu standardowym i błędach standardowych, które w bootstrapie maleją wraz ze wzrostem liczby próbek, poprawiając precyzję estymacji. Przedziały ufności są szersze przy mniejszych próbach bootstrapowych, ale zbliżają się do klasycznych wyników dla większych rozmiarów próby. Bootstrap jest szczególnie przydatny przy małych próbach lub nienormalnych rozkładach, natomiast dla większych próbek różnice między metodami stają się nieistotne, co świadczy o ich zbieżności.
A teraz z bootstrapem i gotową funkcją boot:
?boot
## uruchamianie serwera httpd dla pomocy ... wykonano
mean.boot=function(dochod,idx) {
ans=mean(dochod[idx])
ans
}
DOCHOD.mean.boot = boot(dochod,statistic=mean.boot, R=999)
class(DOCHOD.mean.boot)
## [1] "boot"
names(DOCHOD.mean.boot)
## [1] "t0" "t" "R" "data" "seed" "statistic"
## [7] "sim" "call" "stype" "strata" "weights"
DOCHOD.mean.boot
##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = dochod, statistic = mean.boot, R = 999)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* 816.1279 0.7655209 30.39423
plot(DOCHOD.mean.boot)
boot.ci(DOCHOD.mean.boot,conf=0.95,type=c("norm","perc"))
## BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
## Based on 999 bootstrap replicates
##
## CALL :
## boot.ci(boot.out = DOCHOD.mean.boot, conf = 0.95, type = c("norm",
## "perc"))
##
## Intervals :
## Level Normal Percentile
## 95% (755.8, 874.9 ) (756.9, 881.0 )
## Calculations and Intervals on Original Scale
Czy dochody na osobę różnią się istotnie w woj. pomorskim i podkarpackim? Porównaj wyniki testu t-studenta z wynikami testu bootstrapowego.
library(MKinfer)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ lubridate 1.9.4 ✔ tibble 3.2.1
## ✔ purrr 1.0.2 ✔ tidyr 1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
?boot.t.test
dane2<- dane %>%
filter(Wojewodztwo %in% c("Pomorskie", "Podkarpackie"))
boot.t.test(Dochod_na_osobe~Wojewodztwo, R=999, dane2)
##
## Bootstrap Welch Two Sample t-test
##
## data: Dochod_na_osobe by Wojewodztwo
## number of bootstrap samples: 999
## bootstrap p-value < 0.001001
## bootstrap difference of means (SE) = -195.9369 (30.80696)
## 95 percent bootstrap percentile confidence interval:
## -260.0526 -136.8628
##
## Results without bootstrap:
## t = -6.3601, df = 2932.3, p-value = 2.331e-10
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -256.3683 -135.5439
## sample estimates:
## mean in group Podkarpackie mean in group Pomorskie
## 648.2102 844.1663
Wnioski: Porównanie wyników testu t-Studenta z testem bootstrapowym dla dochodów na osobę w województwach pomorskim i podkarpackim wykazuje dużą zgodność między metodami. Średni dochód na osobę w Pomorskiem (844.17) jest istotnie wyższy niż w Podkarpackiem (648.21).Obie metody wykazują istotną statystycznie różnicę w dochodach na osobę między województwami (p < 0.001). Przedziały ufności z obu metod są bardzo podobne, co świadczy o ich zgodności. Bootstrap dodatkowo uwzględnia potencjalne odstępstwa od normalności rozkładu, co czyni go bardziej elastycznym.
Dla danych “Credit” wykonaj test proporcji dla zmiennych “Student” i “Gender” - czyli sprawdź, czy status studenta różni się istotnie w zależności od płci.
Czy wyniki z włączonym bootstrapem różnią się od wyników pojedynczego testu chi2?
# Przykład 2. Test Chi2 dla dwóch zmiennych jakościowych
library(ISLR)
data("Credit")
?Credit
attach(Credit)
# Czy status studenta (YES, NO) różni się istotnie wg płci (Male, Female)?
tabelka<-table(Student,Gender)
chisq.test(tabelka,simulate.p.value = TRUE, B = 2000)
##
## Pearson's Chi-squared test with simulated p-value (based on 2000
## replicates)
##
## data: tabelka
## X-squared = 1.2115, df = NA, p-value = 0.2954
chisq.test(tabelka) # różnice???
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tabelka
## X-squared = 0.87218, df = 1, p-value = 0.3504
Wnioski: Porównując wyniki testów proporcji dla zmiennych “Student” i “Gender”, zauważamy, że wyniki z zastosowaniem różnych metod nie wskazują istotnych różnic pomiędzy grupami. Wyniki wszystkich metod, zarówno z testów chi-kwadrat (symulowany i z korektą Yatesa), jak i bootstrapowych, wskazują, że status studenta nie różni się istotnie w zależności od płci. Włączanie bootstrapu w tym przypadku nie zmienia końcowego wniosku, ale zwiększa pewność analizy w przypadku niestandardowych rozkładów danych.
Wykonaj i zwizualizuj test ANOVA dla danych “Credit” (z pakietu ISLR) test Anova: czy średni bilans na karcie kredytowej różni się istotnie w zależności od pochodzenia, stanu cywilnego, statusu studenta i płci?
## Analysis of Variance Table
##
## Response: Balance
## Df Sum Sq Mean Sq F value Pr(>F)
## Ethnicity 2 18454 9227 0.0463 0.9548
## Married 1 1332 1332 0.0067 0.9349
## Student 1 5713181 5713181 28.6378 1.484e-07 ***
## Gender 1 4828 4828 0.0242 0.8765
## Residuals 394 78602117 199498
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Wnioski: Przeprowadzony test ANOVA dla danych “Credit” (z pakietu ISLR) badał, czy średni bilans na karcie kredytowej różni się istotnie w zależności od pochodzenia, stanu cywilnego, statusu studenta i płci.Jedynie status studenta (Student) znacząco wpływa na średni bilans na karcie kredytowej (p < 0.001). Pozostałe zmienne (pochodzenie, stan cywilny, płeć) nie wykazują istotnego wpływu na tę zmienną.
library(ISLR)
data("Credit")
# Wizualizacja różnic za pomocą boxplotów
library(ggplot2)
# Pochodzenie (Ethnicity)
ggplot(Credit, aes(x = Ethnicity, y = Balance, fill = Ethnicity)) +
geom_boxplot() +
labs(title = "Średni bilans w zależności od pochodzenia",
x = "Pochodzenie",
y = "Bilans") +
theme_minimal()
# Stan cywilny (Married)
ggplot(Credit, aes(x = factor(Married), y = Balance, fill = factor(Married))) +
geom_boxplot() +
labs(title = "Średni bilans w zależności od stanu cywilnego",
x = "Stan cywilny",
y = "Bilans") +
theme_minimal()
# Status studenta (Student)
ggplot(Credit, aes(x = Student, y = Balance, fill = Student)) +
geom_boxplot() +
labs(title = "Średni bilans w zależności od statusu studenta",
x = "Status studenta",
y = "Bilans") +
theme_minimal()
# Płeć (Gender)
ggplot(Credit, aes(x = Gender, y = Balance, fill = Gender)) +
geom_boxplot() +
labs(title = "Średni bilans w zależności od płci",
x = "Płeć",
y = "Bilans") +
theme_minimal()
A teraz z włączonym bootstrapem:
library(lmboot)
anova_boot<-ANOVA.boot(Balance ~ Ethnicity + Married + Student + Gender,data=Credit,B=999)
## Warning in ANOVA.boot(Balance ~ Ethnicity + Married + Student + Gender, : This function has only been fully tested for one-way and two-way ANOVA.
anova_boot$`p-values`
## [1] 0.9639640 0.9349349 0.0000000 0.8688689
W przypadku Anovy 1-czynnikowej, możemy wykorzystać pakiet wizualizująco - obliczeniowy “ggstatsplot”. Pakiet ten ma w sobie opcję bootstrappingu, która pozwala na obliczenie wartości p-wartości dla testu ANOVA.
library(ggstatsplot)
## You can cite this package as:
## Patil, I. (2021). Visualizations with statistical details: The 'ggstatsplot' approach.
## Journal of Open Source Software, 6(61), 3167, doi:10.21105/joss.03167
ggbetweenstats(data=Credit,
y=Balance,
x=Ethnicity,
nboot=999 #liczba prób bootstrapowych
)
Jakie są wnioski? Czy różnice są istotne? Jak wielkość resamplingu wpływa na wyniki? Jakie są różnice między testem ANOVA a testem ANOVA z bootstrapem?
Wyniki testu ANOVA bez bootstrapu (\(F = 0.0463\), \(p = 0.9548\)) oraz z bootstrapem (\(p = 0.954955\)) wskazują na brak istotnych różnic w średnim bilansie na karcie kredytowej między grupami etnicznymi. Włączenie bootstrapu, który uwzględnia potencjalne odstępstwa od normalności danych i zmienności wariancji między grupami, nie wpłynęło znacząco na wyniki, co wskazuje na stabilność metody. Bootstrap pozwala na bardziej elastyczne oszacowanie p-wartości, szczególnie w przypadku małych prób lub danych o niestandardowym rozkładzie, jednak w tej analizie, gdzie próbki są duże i wariancje równe, wyniki klasycznej ANOVA i ANOVA z bootstrapem są niemal identyczne. Wnioski końcowe potwierdzają, że średni bilans nie różni się istotnie między grupami etnicznymi, a choć bootstrap jest bardziej uniwersalny, w tym przypadku jego zastosowanie nie zmienia ogólnego wniosku.