Ovo je nastavak 7. štiva: Testiranje hipoteza kroz primjere i odnosi se na repliciranje analize koristeći R.
Prvo ćemo učitati sve podatkovne skupove, pa pogledati kako podaci
izgledaju koristeći head(). JASP koristi GitHub repozitorij
za kod i podatke, tako da podacima možemo pristupiti i direktno putem https://github.com/jasp-stats/jasp-data-library/tree/main,
odabrati odgovarajući skup podataka i direktno učitati u R. Pritom
vodite računa da odabirete .csv format i koristite
raw prikaz (i link).
> heart.rate <- read.csv("https://raw.githubusercontent.com/jasp-stats/jasp-data-library/main/Heart%20Rate/Heart%20Rate.csv")
> head(heart.rate)
## Gender Group Heart.Rate
## 1 Female Runners 119
## 2 Female Runners 84
## 3 Female Runners 89
## 4 Female Runners 119
## 5 Female Runners 127
## 6 Female Runners 111
> weight.gain <- read.csv("https://raw.githubusercontent.com/jasp-stats/jasp-data-library/refs/heads/main/Weight%20Gain/Weight%20Gain.csv")
> head(weight.gain)
## Weight.Before Weight.After Difference
## 1 122.54 135.74 13.20
## 2 120.78 129.36 8.58
## 3 131.12 145.20 14.08
## 4 137.06 145.64 8.58
## 5 163.24 173.80 10.56
## 6 166.32 181.06 14.74
> nekretnine <- read.delim("http://sites.williams.edu/rdeveaux/files/2014/09/Saratoga.txt")
> head(nekretnine, 10)
## Price Lot.Size Waterfront Age Land.Value New.Construct Central.Air
## 1 132500 0.09 0 42 50000 0 0
## 2 181115 0.92 0 0 22300 0 0
## 3 109000 0.19 0 133 7300 0 0
## 4 155000 0.41 0 13 18700 0 0
## 5 86060 0.11 0 0 15000 1 1
## 6 120000 0.68 0 31 14000 0 0
## 7 153000 0.40 0 33 23300 0 0
## 8 170000 1.21 0 23 14600 0 0
## 9 90000 0.83 0 36 22200 0 0
## 10 122900 1.94 0 4 21200 0 0
## Fuel.Type Heat.Type Sewer.Type Living.Area Pct.College Bedrooms Fireplaces
## 1 3 4 2 906 35 2 1
## 2 2 3 2 1953 51 3 0
## 3 2 3 3 1944 51 4 1
## 4 2 2 2 1944 51 3 1
## 5 2 2 3 840 51 2 0
## 6 2 2 2 1152 22 4 1
## 7 4 3 2 2752 51 4 1
## 8 4 2 2 1662 35 4 1
## 9 3 4 2 1632 51 3 0
## 10 2 2 1 1416 44 3 0
## Bathrooms Rooms
## 1 1.0 5
## 2 2.5 6
## 3 1.0 8
## 4 1.5 5
## 5 1.0 3
## 6 1.0 8
## 7 1.5 8
## 8 1.5 9
## 9 1.5 8
## 10 1.5 6
Većina testova spomenutih u štivu dostupna je u osnovnom paketu R-a
stats, dok dodatni paketi mogu pružiti specifične funkcije
ili olakšati interpretaciju rezultata. Evo nekoliko preporučenih
paketa:
stats (ugrađeni paket):
t.test()var.test()aov(), lm()wilcox.test()kruskal.test()friedman.test()chisq.test(), fisher.test(),
mcnemar.test()BSDA (Basic Statistics and Data
Analysis):
z.test() za provođenje z-testa, što
nije izvorno uključeno u stats.rstatix:
DescTools:
> install.packages("BSDA")
> install.packages("rstatix")
> install.packages("DescTools")
Započinjemo analizom heart.rate skupa podataka. Prvo
koristimo tablicu kontingence kako bi utvrdili strukturu uzorka s
obzirom na spol i vježbanje.
> table(heart.rate$Gender, heart.rate$Group)
##
## Control Runners
## Female 200 200
## Male 200 200
Sljedeće, dobivamo uvide iz pokazatelja deskriptivne statistike.
> library(psych)
> describe(heart.rate)
## vars n mean sd median trimmed mad min max range skew
## Gender* 1 800 1.50 0.5 1.5 1.50 0.74 1 2 1 0.00
## Group* 2 800 1.50 0.5 1.5 1.50 0.74 1 2 1 0.00
## Heart.Rate 3 800 124.49 22.6 124.0 123.77 25.20 69 196 127 0.25
## kurtosis se
## Gender* -2.00 0.02
## Group* -2.00 0.02
## Heart.Rate -0.55 0.80
Sljedeće, utvrđujemo pokazatelje desriptivne statistike za varijablu
Heart.Rate za podskupine prema varijabli
Group, što će nam trebati kasnije u analizi.
> describeBy(heart.rate$Heart.Rate, heart.rate$Group)
##
## Descriptive statistics by group
## group: Control
## vars n mean sd median trimmed mad min max range skew kurtosis se
## X1 1 400 139 18.95 139 139.27 19.27 77 196 119 -0.11 -0.02 0.95
## ------------------------------------------------------------
## group: Runners
## vars n mean sd median trimmed mad min max range skew kurtosis se
## X1 1 400 109.98 15.53 109 109.39 16.31 69 164 95 0.37 -0.03 0.78
U sljedećem koraku provjeravamo ravnaju li se podaci
Heart.Rate prema normalnoj distribciji.
> shapiro.test(heart.rate$Heart.Rate)
##
## Shapiro-Wilk normality test
##
## data: heart.rate$Heart.Rate
## W = 0.98777, p-value = 3.165e-06
Ilustrativni prikaz kako bi izgledalo provođenje z-testa, prvo
koristeći paket BSDA, a potom paket
DescTools.
> library(BSDA)
## Loading required package: lattice
##
## Attaching package: 'BSDA'
## The following object is masked from 'package:datasets':
##
## Orange
> z.test(heart.rate$Heart.Rate, alternative = "two.sided", mu=120, sigma.x = 22.6)
##
## One-sample z-Test
##
## data: heart.rate$Heart.Rate
## z = 5.6193, p-value = 1.917e-08
## alternative hypothesis: true mean is not equal to 120
## 95 percent confidence interval:
## 122.9239 126.0561
## sample estimates:
## mean of x
## 124.49
> library(DescTools)
##
## Attaching package: 'DescTools'
## The following objects are masked from 'package:psych':
##
## AUC, ICC, SD
> ZTest(heart.rate$Heart.Rate, alternative = "two.sided", paired = FALSE, mu=120, sd_pop = 22.6)
##
## One Sample z-test
##
## data: heart.rate$Heart.Rate
## z = 5.6193, Std. Dev. Population = 22.6, p-value = 1.917e-08
## alternative hypothesis: true mean is not equal to 120
## 95 percent confidence interval:
## 122.9239 126.0561
## sample estimates:
## mean of x
## 124.49
Ilustrativni prikaz kako bi izgledalo provođenje klasičnog t-testa
(uz pretpostavku jednakosti varijanci,
var.equal = TRUE).
> t.test(heart.rate$Heart.Rate, alternative = "two.sided", mu=120, paired = FALSE, var.equal = TRUE)
##
## One Sample t-test
##
## data: heart.rate$Heart.Rate
## t = 5.6201, df = 799, p-value = 2.637e-08
## alternative hypothesis: true mean is not equal to 120
## 95 percent confidence interval:
## 122.9218 126.0582
## sample estimates:
## mean of x
## 124.49
Ilustrativni prikaz kako bi izgledalo provođenje Welchovog t-testa
(uz pretpostavku nejednakosti varijanci,
var.equal = FALSE).
> t.test(heart.rate$Heart.Rate, alternative = "two.sided", mu=120, paired = FALSE, var.equal = FALSE)
##
## One Sample t-test
##
## data: heart.rate$Heart.Rate
## t = 5.6201, df = 799, p-value = 2.637e-08
## alternative hypothesis: true mean is not equal to 120
## 95 percent confidence interval:
## 122.9218 126.0582
## sample estimates:
## mean of x
## 124.49
Prikaz probedbe Wilcoxonovog testa za jedan uzorak.
> wilcox.test(heart.rate$Heart.Rate, alternative = "two.sided", mu=120, paired = FALSE)
##
## Wilcoxon signed rank test with continuity correction
##
## data: heart.rate$Heart.Rate
## V = 186279, p-value = 2.801e-06
## alternative hypothesis: true location is not equal to 120
Izračun Cohenovog d, koji mjeri veličinu efekta.
> DescTools::CohenD(heart.rate$Heart.Rate, y=120, pooled = FALSE)
## [1] 0.1988191
## attr(,"magnitude")
## [1] "negligible"
Također, možemo izračunati i snagu t-testa. Ovdje pretpostavljamo da
je \(\alpha=\beta=0.05\) i to unosimo u
izračun. Dobit ćemo vrijednost delta, koja označava stvarnu
razliku u prosjecima koju ovakav test može ispravno detektirati uz
pretpostavljenu danu razinu pogrešaka tipa I i II.
> power.t.test(n=800, sd=22.6, sig.level = 0.05, power= 0.95, type = "one.sample", alternative = "two.sided")
##
## One-sample t test power calculation
##
## n = 800
## delta = 2.883841
## sd = 22.6
## sig.level = 0.05
## power = 0.95
## alternative = two.sided
Alternativno, ako bismo provodili jednosmjerna testiranja, onda bismo na taj način zadali naredbe.
> z.test(heart.rate$Heart.Rate, alternative = "greater", mu=120, sigma.x = 22.6)
##
## One-sample z-Test
##
## data: heart.rate$Heart.Rate
## z = 5.6193, p-value = 9.586e-09
## alternative hypothesis: true mean is greater than 120
## 95 percent confidence interval:
## 123.1757 NA
## sample estimates:
## mean of x
## 124.49
> ZTest(heart.rate$Heart.Rate, alternative = "greater", paired = FALSE, mu=120, sd_pop = 22.6)
##
## One Sample z-test
##
## data: heart.rate$Heart.Rate
## z = 5.6193, Std. Dev. Population = 22.6, p-value = 9.586e-09
## alternative hypothesis: true mean is greater than 120
## 95 percent confidence interval:
## 123.1757 Inf
## sample estimates:
## mean of x
## 124.49
> t.test(heart.rate$Heart.Rate, alternative = "greater", mu=120, paired = FALSE, var.equal = TRUE)
##
## One Sample t-test
##
## data: heart.rate$Heart.Rate
## t = 5.6201, df = 799, p-value = 1.319e-08
## alternative hypothesis: true mean is greater than 120
## 95 percent confidence interval:
## 123.1744 Inf
## sample estimates:
## mean of x
## 124.49
> t.test(heart.rate$Heart.Rate, alternative = "greater", mu=120, paired = FALSE, var.equal = FALSE)
##
## One Sample t-test
##
## data: heart.rate$Heart.Rate
## t = 5.6201, df = 799, p-value = 1.319e-08
## alternative hypothesis: true mean is greater than 120
## 95 percent confidence interval:
## 123.1744 Inf
## sample estimates:
## mean of x
## 124.49
> wilcox.test(heart.rate$Heart.Rate, alternative = "greater", mu=120, paired = FALSE)
##
## Wilcoxon signed rank test with continuity correction
##
## data: heart.rate$Heart.Rate
## V = 186279, p-value = 1.4e-06
## alternative hypothesis: true location is greater than 120
> z.test(heart.rate$Heart.Rate, alternative = "less", mu=120, sigma.x = 22.6)
##
## One-sample z-Test
##
## data: heart.rate$Heart.Rate
## z = 5.6193, p-value = 1
## alternative hypothesis: true mean is less than 120
## 95 percent confidence interval:
## NA 125.8043
## sample estimates:
## mean of x
## 124.49
> ZTest(heart.rate$Heart.Rate, alternative = "less", paired = FALSE, mu=120, sd_pop = 22.6)
##
## One Sample z-test
##
## data: heart.rate$Heart.Rate
## z = 5.6193, Std. Dev. Population = 22.6, p-value = 1
## alternative hypothesis: true mean is less than 120
## 95 percent confidence interval:
## -Inf 125.8043
## sample estimates:
## mean of x
## 124.49
> t.test(heart.rate$Heart.Rate, alternative = "less", mu=120, paired = FALSE, var.equal = TRUE)
##
## One Sample t-test
##
## data: heart.rate$Heart.Rate
## t = 5.6201, df = 799, p-value = 1
## alternative hypothesis: true mean is less than 120
## 95 percent confidence interval:
## -Inf 125.8056
## sample estimates:
## mean of x
## 124.49
> t.test(heart.rate$Heart.Rate, alternative = "less", mu=120, paired = FALSE, var.equal = FALSE)
##
## One Sample t-test
##
## data: heart.rate$Heart.Rate
## t = 5.6201, df = 799, p-value = 1
## alternative hypothesis: true mean is less than 120
## 95 percent confidence interval:
## -Inf 125.8056
## sample estimates:
## mean of x
## 124.49
> wilcox.test(heart.rate$Heart.Rate, alternative = "less", mu=120, paired = FALSE)
##
## Wilcoxon signed rank test with continuity correction
##
## data: heart.rate$Heart.Rate
## V = 186279, p-value = 1
## alternative hypothesis: true location is less than 120
Za dva uzorka, sad možemo i moramo provjeriti i homogenost varijanci. No, prvo moramo provjeriti jesu li varijable definirane kao odgovarajući tipovi podataka.
> str(heart.rate)
## 'data.frame': 800 obs. of 3 variables:
## $ Gender : chr "Female" "Female" "Female" "Female" ...
## $ Group : chr "Runners" "Runners" "Runners" "Runners" ...
## $ Heart.Rate: int 119 84 89 119 127 111 115 109 111 120 ...
Za potrebe daljnje analize, Gender i Group
moramo definirati kao faktore. Kad to učinimo na jednostavan način,
koristeći as.factor(), onda će modalitetima varijable biti
pripisane numeričke oznake (bit će prekodirani) po abecednom redu. To
znači da će biti Female = 1 i Male = 2,
odnosno Control = 1 i Runners = 2. Ovo je
korisno zapamtiti (ili zapisati), jer će biti važno za
interpretaciju.
> heart.rate$Group <- as.factor(heart.rate$Group)
> heart.rate$Gender <- as.factor(heart.rate$Gender)
> str(heart.rate)
## 'data.frame': 800 obs. of 3 variables:
## $ Gender : Factor w/ 2 levels "Female","Male": 1 1 1 1 1 1 1 1 1 1 ...
## $ Group : Factor w/ 2 levels "Control","Runners": 2 2 2 2 2 2 2 2 2 2 ...
## $ Heart.Rate: int 119 84 89 119 127 111 115 109 111 120 ...
Pristupamo provjeri homogenosti varijanci u dvije skupine, koristeći
Leveneov test i Brown-Forsythe test iz paketa DescTools.
Oba testa upućuju na isti zaključak.
> LeveneTest(heart.rate$Heart.Rate, group = heart.rate$Group, center = "mean")
## Levene's Test for Homogeneity of Variance (center = "mean")
## Df F value Pr(>F)
## group 1 12.807 0.0003661 ***
## 798
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
> LeveneTest(heart.rate$Heart.Rate, group = heart.rate$Group, center = "median") # Brown-Forsythe-Test
## Levene's Test for Homogeneity of Variance (center = "median")
## Df F value Pr(>F)
## group 1 13.238 0.0002919 ***
## 798
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Welchov t-test:
> t.test(heart.rate$Heart.Rate[heart.rate$Group == "Control"], heart.rate$Heart.Rate[heart.rate$Group == "Runners"], alternative = "two.sided", paired = FALSE, var.equal = FALSE)
##
## Welch Two Sample t-test
##
## data: heart.rate$Heart.Rate[heart.rate$Group == "Control"] and heart.rate$Heart.Rate[heart.rate$Group == "Runners"]
## t = 23.687, df = 768.42, p-value < 2.2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 26.61498 31.42502
## sample estimates:
## mean of x mean of y
## 139.00 109.98
Mann-Whitney U test (ekstenzija Wilcoxonovog testa za usporedbu dva nezavisna uzorka):
> wilcox.test(heart.rate$Heart.Rate[heart.rate$Group == "Control"], heart.rate$Heart.Rate[heart.rate$Group == "Runners"], alternative = "two.sided", paired = FALSE)
##
## Wilcoxon rank sum test with continuity correction
##
## data: heart.rate$Heart.Rate[heart.rate$Group == "Control"] and heart.rate$Heart.Rate[heart.rate$Group == "Runners"]
## W = 140747, p-value < 2.2e-16
## alternative hypothesis: true location shift is not equal to 0
Prelazimo na primjenu testova za dva ili više nezavisna uzorka. Ovdje će se koristiti ANOVA i Kruskal-Wallis. Na početku, ispitujemo normalnost rezuduala koristeći Q-Q plot.
> library(ggpubr)
## Loading required package: ggplot2
##
## Attaching package: 'ggplot2'
## The following objects are masked from 'package:psych':
##
## %+%, alpha
> model <- lm(Heart.Rate~Group, data = heart.rate)
> ggqqplot(residuals(model))
Osim vizualnog pristupa, možemo koristiti i Shapiro-Wilk test.
> library(rstatix)
##
## Attaching package: 'rstatix'
## The following object is masked from 'package:stats':
##
## filter
> shapiro_test(residuals(model))
## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.998 0.426
Također, provjeravamo razdiobu unutar grupa.
> heart.rate %>%
+ group_by(Group) %>%
+ shapiro_test(Heart.Rate)
## # A tibble: 2 × 4
## Group variable statistic p
## <fct> <chr> <dbl> <dbl>
## 1 Control Heart.Rate 0.997 0.772
## 2 Runners Heart.Rate 0.989 0.00409
Za velke uzorke, preferiraju se Q-Q plot prikazi naspram testa, jer pri radu s velikim uzorcima Shapiro-Wilk postaje jako osjetljiv i na mala odstupanja od normalnosti.
> ggqqplot(heart.rate, "Heart.Rate", facet.by = "Group")
Postoje tek manja odstupanja od normalnosti (izraženija za trkače), ali moramo voditi računa o tome da nas kod ANOVA-e prvenstveno zanima normalna distribucija reziduala, dok je za podatke važno da dolaze iz normalne distribucije (tolerira se odstupanje od normalnosti). Sljedeći je korak utvrđivanje homogenosti varijanci.
> heart.rate %>% levene_test(Heart.Rate~Group)
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 1 798 13.2 0.000292
Temeljem rezultata vidimo da je p-vrijednost < 0,05, što znači da
postoji značajna razlika između varijanci između skupina. Stoga ne
možemo pretpostaviti homogenost varijanci u različitim grupama. U
situaciji kada pretpostavka o homogenosti varijance nije ispunjena,
možemo izračunati Welchov jednosmjerni ANOVA test pomoću funkcije
welch_anova_test() (iz paketa rstatix). Ovaj
test ne zahtijeva pretpostavku o jednakim varijancama.
Za ilustraciju, ovdje se prikazuje kako bi se proveo ANOVA test
(koristeći anova_test() iz paketa
rstatix).
> anova_test(heart.rate, Heart.Rate~Group)
## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 Group 1 798 561.08 2.38e-94 * 0.413
Također, možemo koristiti i funkciju aov() iz paketa
stats. Za ovako dobivene rezultate možemo utvrditi i \(\eta^2\).
> rez <- aov(Heart.Rate~Group, data = heart.rate)
> summary(rez)
## Df Sum Sq Mean Sq F value Pr(>F)
## Group 1 168432 168432 561.1 <2e-16 ***
## Residuals 798 239554 300
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
> eta_squared(rez)
## Group
## 0.412838
> PostHocTest(rez)
##
## Posthoc multiple comparisons of means : Tukey HSD
## 95% family-wise confidence level
##
## $Group
## diff lwr.ci upr.ci pval
## Runners-Control -29.02 -31.42487 -26.61513 <2e-16 ***
##
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Sad prelazimo na rezultate koje možemo koristiti, a to će biti Welchova ANOVA.
> welch_anova_test(heart.rate, heart.rate$Heart.Rate~heart.rate$Group)
## # A tibble: 1 × 7
## .y. n statistic DFn DFd p method
## * <chr> <int> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 heart.rate$Heart.Rate 800 561. 1 768. 1.48e-93 Welch ANOVA
> ggboxplot(heart.rate, y = "Heart.Rate", facet.by = "Group")
Post-hoc usporedbe:
> heart.rate %>% games_howell_test(Heart.Rate~Group)
## # A tibble: 1 × 8
## .y. group1 group2 estimate conf.low conf.high p.adj p.adj.signif
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Heart.Rate Control Runners -29.0 -31.4 -26.6 0 ****
> heart.rate %>% pairwise_t_test(Heart.Rate~Group, pool.sd = FALSE, p.adjust.method = "bonferroni")
## # A tibble: 1 × 10
## .y. group1 group2 n1 n2 statistic df p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Hear… Contr… Runne… 400 400 23.7 768. 1.48e-93 1.48e-93 ****
Preostaje još prikazati Kruskall-Wallis test. Taj je test dostupan u
paketu stats i rstatix. Prikazat će se oba,
redom.
> kruskal.test(heart.rate$Heart.Rate~heart.rate$Group)
##
## Kruskal-Wallis rank sum test
##
## data: heart.rate$Heart.Rate by heart.rate$Group
## Kruskal-Wallis chi-squared = 345.59, df = 1, p-value < 2.2e-16
> kruskal_test(heart.rate, heart.rate$Heart.Rate~heart.rate$Group)
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 heart.rate$Heart.Rate 800 346. 1 3.86e-77 Kruskal-Wallis
U paketu rstatix na raspolaganju je i funkcija
kruskal_effsize() kojom se utvrđuje veličina efekta (\(\eta^2\)).
> kruskal_effsize(heart.rate, heart.rate$Heart.Rate~heart.rate$Group)
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 heart.rate$Heart.Rate 800 0.432 eta2[H] large
Na raspolaganju je i Dunnov post-hoc test (prikladan za korištenje kao post-hoc za Kruskal-Wallis test, ako podaci nisu upareni).
> DescTools::DunnTest(heart.rate$Heart.Rate, heart.rate$Group)
##
## Dunn's test of multiple comparisons using rank sums : holm
##
## mean.rank.diff pval
## Runners-Control -303.735 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
> boxplot(Heart.Rate ~ Group, data = heart.rate)
Preostaje prikazati postupak za situacije u kojima se u obzir uzimaju
dva faktora. Uz Group, ispitat će se i
Gender.
> ggboxplot(heart.rate, x = "Group", y = "Heart.Rate", color = "Gender")
> model2 <- lm(Heart.Rate ~ Group*Gender, data = heart.rate)
> ggqqplot(residuals(model2))
> shapiro_test(residuals(model2))
## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model2) 0.998 0.338
> heart.rate %>%
+ group_by(Group, Gender) %>%
+ shapiro_test(Heart.Rate)
## # A tibble: 4 × 5
## Gender Group variable statistic p
## <fct> <fct> <chr> <dbl> <dbl>
## 1 Female Control Heart.Rate 0.995 0.699
## 2 Male Control Heart.Rate 0.994 0.562
## 3 Female Runners Heart.Rate 0.995 0.755
## 4 Male Runners Heart.Rate 0.990 0.196
> ggqqplot(heart.rate, "Heart.Rate", ggtheme = theme_bw()) +
+ facet_grid(Group ~ Gender)
> heart.rate %>% levene_test(Heart.Rate ~ Group*Gender)
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 3 796 5.73 0.000697
> anova_test(heart.rate, Heart.Rate~Group*Gender)
## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 Group 1 796 695.647 1.15e-110 * 0.466
## 2 Gender 1 796 185.980 3.29e-38 * 0.189
## 3 Group:Gender 1 796 7.409 7.00e-03 * 0.009
Također, možemo koristiti i funkciju aov() iz paketa
stats. Za ovako dobivene rezultate možemo utvrditi i \(\eta^2\).
> rez2 <- aov(Heart.Rate~Group*Gender, data = heart.rate)
> summary(rez2)
## Df Sum Sq Mean Sq F value Pr(>F)
## Group 1 168432 168432 695.647 < 2e-16 ***
## Gender 1 45030 45030 185.980 < 2e-16 ***
## Group:Gender 1 1794 1794 7.409 0.00663 **
## Residuals 796 192730 242
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
> eta_squared(rez2)
## Group Gender Group:Gender
## 0.412837972 0.110371468 0.004397223
> PostHocTest(rez2)
##
## Posthoc multiple comparisons of means : Tukey HSD
## 95% family-wise confidence level
##
## $Group
## diff lwr.ci upr.ci pval
## Runners-Control -29.02 -31.17979 -26.86021 <2e-16 ***
##
## $Gender
## diff lwr.ci upr.ci pval
## Male-Female -15.005 -17.16479 -12.84521 <2e-16 ***
##
## $`Group:Gender`
## diff lwr.ci upr.ci pval
## Runners:Female-Control:Female -32.015 -36.02095 -28.009054 <2e-16 ***
## Control:Male-Control:Female -18.000 -22.00595 -13.994054 <2e-16 ***
## Runners:Male-Control:Female -44.025 -48.03095 -40.019054 <2e-16 ***
## Control:Male-Runners:Female 14.015 10.00905 18.020946 <2e-16 ***
## Runners:Male-Runners:Female -12.010 -16.01595 -8.004054 <2e-16 ***
## Runners:Male-Control:Male -26.025 -30.03095 -22.019054 <2e-16 ***
##
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Sad prelazimo na rezultate koje možemo koristiti, a to će biti Welchova ANOVA.
> heart.rate %>%
+ group_by(Gender) %>%
+ welch_anova_test(Heart.Rate~Group)
## # A tibble: 2 × 8
## Gender .y. n statistic DFn DFd p method
## * <fct> <chr> <int> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Female Heart.Rate 400 394. 1 398. 1.78e-61 Welch ANOVA
## 2 Male Heart.Rate 400 302. 1 364. 1.08e-49 Welch ANOVA
> ggboxplot(heart.rate, x= "Gender", y = "Heart.Rate", facet.by = "Group")
Post-hoc usporedbe:
> heart.rate %>%
+ group_by(Gender) %>%
+ games_howell_test(Heart.Rate~Group)
## # A tibble: 2 × 9
## Gender .y. group1 group2 estimate conf.low conf.high p.adj p.adj.signif
## * <fct> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Female Heart.Rate Contr… Runne… -32.0 -35.2 -28.8 0 ****
## 2 Male Heart.Rate Contr… Runne… -26.0 -29.0 -23.1 0 ****
> heart.rate %>%
+ group_by(Gender) %>%
+ pairwise_t_test(Heart.Rate~Group, pool.sd = FALSE, p.adjust.method = "bonferroni")
## # A tibble: 2 × 11
## Gender .y. group1 group2 n1 n2 statistic df p p.adj
## * <fct> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <dbl>
## 1 Female Heart.Rate Control Runne… 200 200 19.9 398. 1.78e-61 1.78e-61
## 2 Male Heart.Rate Control Runne… 200 200 17.4 364. 1.08e-49 1.08e-49
## # ℹ 1 more variable: p.adj.signif <chr>
Preostaje još prikazati Kruskall-Wallis test. Inačica koja se ovdje
može koristiti dostupna je u paketu rstatix.
> heart.rate %>%
+ group_by(Gender) %>%
+ kruskal_test(Heart.Rate~Group)
## # A tibble: 2 × 7
## Gender .y. n statistic df p method
## * <fct> <chr> <int> <dbl> <int> <dbl> <chr>
## 1 Female Heart.Rate 400 210. 1 1.64e-47 Kruskal-Wallis
## 2 Male Heart.Rate 400 181. 1 3.52e-41 Kruskal-Wallis
> heart.rate %>%
+ group_by(Group) %>%
+ kruskal_test(Heart.Rate~Gender)
## # A tibble: 2 × 7
## Group .y. n statistic df p method
## * <fct> <chr> <int> <dbl> <int> <dbl> <chr>
## 1 Control Heart.Rate 400 93.1 1 4.9 e-22 Kruskal-Wallis
## 2 Runners Heart.Rate 400 60.4 1 7.85e-15 Kruskal-Wallis
Da bismo dobili detaljnije uvide, možemo kreirati novu varijablu koja će podijeliti skup na četiri podskupa.
> heart.rate$Group_gender <- paste(heart.rate$Group, heart.rate$Gender, sep = "_")
> heart.rate$Group_gender <- factor(heart.rate$Group_gender, levels = c("Control_Female", "Control_Male", "Runners_Female", "Runners_Male"))
>
> str(heart.rate)
## 'data.frame': 800 obs. of 4 variables:
## $ Gender : Factor w/ 2 levels "Female","Male": 1 1 1 1 1 1 1 1 1 1 ...
## $ Group : Factor w/ 2 levels "Control","Runners": 2 2 2 2 2 2 2 2 2 2 ...
## $ Heart.Rate : int 119 84 89 119 127 111 115 109 111 120 ...
## $ Group_gender: Factor w/ 4 levels "Control_Female",..: 3 3 3 3 3 3 3 3 3 3 ...
> kruskal_test(heart.rate, Heart.Rate~Group_gender)
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 Heart.Rate 800 432. 3 2.79e-93 Kruskal-Wallis
U paketu rstatix na raspolaganju je i funkcija
kruskal_effsize() kojom se utvrđuje veličina efekta (\(\eta^2\)). Ne može se primijeniti za
interakciju, nego za svaki faktor zasebno.
> kruskal_effsize(heart.rate, Heart.Rate~Group_gender)
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 Heart.Rate 800 0.539 eta2[H] large
Na raspolaganju je i Dunnov post-hoc test (prikladan za korištenje kao post-hoc za Kruskal-Wallis test, ako podaci nisu upareni).
> DescTools::DunnTest(heart.rate$Heart.Rate, heart.rate$Group_gender)
##
## Dunn's test of multiple comparisons using rank sums : holm
##
## mean.rank.diff pval
## Control_Male-Control_Female -167.680 1.2e-12 ***
## Runners_Female-Control_Female -320.615 < 2e-16 ***
## Runners_Male-Control_Female -454.535 < 2e-16 ***
## Runners_Female-Control_Male -152.935 7.2e-11 ***
## Runners_Male-Control_Male -286.855 < 2e-16 ***
## Runners_Male-Runners_Female -133.920 6.8e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
> boxplot(Heart.Rate ~ Group_gender, data = heart.rate, boxwex = 0.5, lex.order = TRUE)
U sljedećem koraku analizira se podatkovni skup
Weight gain.
> str(weight.gain)
## 'data.frame': 16 obs. of 3 variables:
## $ Weight.Before: num 123 121 131 137 163 ...
## $ Weight.After : num 136 129 145 146 174 ...
## $ Difference : num 13.2 8.58 14.08 8.58 10.56 ...
> describe(weight.gain)
## vars n mean sd median trimmed mad min max range
## Weight.Before 1 16 144.64 22.70 138.27 142.51 24.46 117.26 201.74 84.48
## Weight.After 2 16 155.04 21.44 147.84 153.32 22.83 129.36 204.82 75.46
## Difference 3 16 10.41 3.84 11.11 10.56 4.57 3.08 15.62 12.54
## skew kurtosis se
## Weight.Before 0.80 -0.03 5.68
## Weight.After 0.64 -0.58 5.36
## Difference -0.32 -1.34 0.96
> shapiro.test(weight.gain$Difference)
##
## Shapiro-Wilk normality test
##
## data: weight.gain$Difference
## W = 0.93801, p-value = 0.3254
> var.test(weight.gain$Weight.Before, weight.gain$Weight.After, alternative = "two.sided")
##
## F test to compare two variances
##
## data: weight.gain$Weight.Before and weight.gain$Weight.After
## F = 1.1217, num df = 15, denom df = 15, p-value = 0.8269
## alternative hypothesis: true ratio of variances is not equal to 1
## 95 percent confidence interval:
## 0.3919077 3.2103408
## sample estimates:
## ratio of variances
## 1.121676
> t.test(weight.gain$Weight.Before, weight.gain$Weight.After, alternative = "two.sided", paired = TRUE, var.equal = TRUE)
##
## Paired t-test
##
## data: weight.gain$Weight.Before and weight.gain$Weight.After
## t = -10.841, df = 15, p-value = 1.71e-08
## alternative hypothesis: true mean difference is not equal to 0
## 95 percent confidence interval:
## -12.455282 -8.362218
## sample estimates:
## mean difference
## -10.40875
> library(exactRankTests)
## Package 'exactRankTests' is no longer under development.
## Please consider using package 'coin' instead.
> wilcox.exact(weight.gain$Weight.Before, weight.gain$Weight.After, alternative = "two.sided", paired = TRUE)
##
## Exact Wilcoxon signed rank test
##
## data: weight.gain$Weight.Before and weight.gain$Weight.After
## V = 0, p-value = 3.052e-05
## alternative hypothesis: true mu is not equal to 0
> data2 <- data.frame(Weight=rep(0,32), time=rep(0,32))
> data2$weight <- c(weight.gain$Weight.Before, weight.gain$Weight.After)
> data2$time <- c(rep(0, length(weight.gain$Weight.Before)), rep(1, length(weight.gain$Weight.After)))
> str(data2)
## 'data.frame': 32 obs. of 3 variables:
## $ Weight: num 0 0 0 0 0 0 0 0 0 0 ...
## $ time : num 0 0 0 0 0 0 0 0 0 0 ...
## $ weight: num 123 121 131 137 163 ...
> library(effectsize)
##
## Attaching package: 'effectsize'
## The following objects are masked from 'package:rstatix':
##
## cohens_d, eta_squared
## The following object is masked from 'package:psych':
##
## phi
> rank_biserial(weight.gain$Weight.Before, weight.gain$Weight.After, paired = TRUE)
## r (rank biserial) | 95% CI
## ----------------------------------
## -1.00 | [-1.00, -1.00]
Sljedeći po redu je slučaj Nekretnina. Postoji li statistički značajna razlika u cijeni s obzirom na to nalazi li se nekretnina uz obalu?
> library(ggpubr)
> nekretnine$Waterfront<- as.factor(nekretnine$Waterfront)
> model <- lm(nekretnine$Price~nekretnine$Waterfront, data = nekretnine)
> ggqqplot(residuals(model))
Osim vizualnog pristupa, možemo koristiti i Shapiro-Wilk test.
> library(rstatix)
> shapiro_test(residuals(model))
## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.899 2.60e-32
Također, provjeravamo razdiobu unutar grupa.
> nekretnine %>%
+ group_by(Waterfront) %>%
+ shapiro_test(Price)
## # A tibble: 2 × 4
## Waterfront variable statistic p
## <fct> <chr> <dbl> <dbl>
## 1 0 Price 0.897 2.20e-32
## 2 1 Price 0.919 1.89e- 1
Za velke uzorke, preferiraju se Q-Q plot prikazi naspram testa, jer pri radu s velikim uzorcima Shapiro-Wilk postaje jako osjetljiv i na mala odstupanja od normalnosti. No, ovdje i vizualni prikaz i test upućuju na isti zaključak.
> ggqqplot(nekretnine, "Price", facet.by = "Waterfront")
> nekretnine %>% levene_test(Price~Waterfront)
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 1 1726 4.92 0.0267
Temeljem rezultata vidimo da je p-vrijednost < 0,05, što znači da
postoji značajna razlika između varijanci između skupina. Stoga ne
možemo pretpostaviti homogenost varijanci u različitim grupama. U
situaciji kada pretpostavke nisu ispunjene, koristimo Kruskall-Wallis
test. Taj je test dostupan u paketu stats i
rstatix. Prikazat će se oba, redom.
> kruskal.test(nekretnine$Price, nekretnine$Waterfront)
##
## Kruskal-Wallis rank sum test
##
## data: nekretnine$Price and nekretnine$Waterfront
## Kruskal-Wallis chi-squared = 20.005, df = 1, p-value = 7.722e-06
> kruskal_test(nekretnine, nekretnine$Price ~ nekretnine$Waterfront)
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 nekretnine$Price 1728 20.0 1 0.00000772 Kruskal-Wallis
U paketu rstatix na raspolaganju je i funkcija
kruskal_effsize() kojom se utvrđuje veličina efekta (\(\eta^2\)).
> kruskal_effsize(nekretnine, nekretnine$Price ~ nekretnine$Waterfront)
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 nekretnine$Price 1728 0.0110 eta2[H] small
Na raspolaganju je i Dunnov post-hoc test (prikladan za korištenje kao post-hoc za Kruskal-Wallis test, ako podaci nisu upareni).
> DescTools::DunnTest(nekretnine$Price, nekretnine$Waterfront)
##
## Dunn's test of multiple comparisons using rank sums : holm
##
## mean.rank.diff pval
## 1-0 578.7573 7.7e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
> boxplot(nekretnine$Price ~ nekretnine$Waterfront, data = nekretnine)
Postoji li statistički značajna razlika u cijeni s obzirom na to koliko kamina ima nekretnina?
> nekretnine$Fireplaces <- as.factor(nekretnine$Fireplaces)
> model <- lm(nekretnine$Price~nekretnine$Fireplaces, data = nekretnine)
> ggqqplot(residuals(model))
> nekretnine %>% levene_test(Price~Fireplaces)
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 4 1723 12.1 0.00000000104
> kruskal_test(nekretnine, nekretnine$Price ~ nekretnine$Fireplaces)
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 nekretnine$Price 1728 268. 4 1.07e-56 Kruskal-Wallis
> kruskal_effsize(nekretnine, nekretnine$Price ~ nekretnine$Fireplaces)
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 nekretnine$Price 1728 0.153 eta2[H] large
> DescTools::DunnTest(nekretnine$Price, nekretnine$Fireplaces)
##
## Dunn's test of multiple comparisons using rank sums : holm
##
## mean.rank.diff pval
## 1-0 365.7473 < 2e-16 ***
## 2-0 665.3022 3.8e-16 ***
## 3-0 928.8736 0.0514 .
## 4-0 1075.6236 0.0163 *
## 2-1 299.5549 0.0011 **
## 3-1 563.1263 0.4434
## 4-1 709.8763 0.2222
## 3-2 263.5714 0.9310
## 4-2 410.3214 0.7676
## 4-3 146.7500 0.9310
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Postoji li statistički značajna razlika u veličini zemljišta s obzirom na to nalazi li se nekretnina uz obalu?
> model <- lm(nekretnine$Lot.Size~nekretnine$Waterfront, data = nekretnine)
> ggqqplot(residuals(model))
> nekretnine %>% levene_test(Lot.Size~Waterfront)
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 1 1726 0.0296 0.863
Iako pretpostavka o homogenosti varijanci nije narušena, pretpostavka o normalnosti reziduala jest, pa ćemo koristiti neparametrijske alternative.
> kruskal_test(nekretnine, nekretnine$Lot.Size ~ nekretnine$Waterfront)
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 nekretnine$Lot.Size 1728 0.00645 1 0.936 Kruskal-Wallis
> kruskal_effsize(nekretnine, nekretnine$Lot.Size ~ nekretnine$Waterfront)
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 nekretnine$Lot.Size 1728 -0.000576 eta2[H] small
> DescTools::DunnTest(nekretnine$Lot.Size, nekretnine$Waterfront)
##
## Dunn's test of multiple comparisons using rank sums : holm
##
## mean.rank.diff pval
## 1-0 10.39019 0.9360
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Postoji li statistički značajna razlika u veličini zemljišta s obzirom na to koliko kamina ima nekretnina?
> model <- lm(nekretnine$Lot.Size~nekretnine$Fireplaces, data = nekretnine)
> ggqqplot(residuals(model))
> nekretnine %>% levene_test(Lot.Size~Fireplaces)
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 4 1723 3.33 0.00998
Obje pretpostavke su narušene, pa ćemo koristiti neparametrijske alternative.
> kruskal_test(nekretnine, nekretnine$Lot.Size ~ nekretnine$Fireplaces)
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 nekretnine$Lot.Size 1728 73.1 4 4.95e-15 Kruskal-Wallis
> kruskal_effsize(nekretnine, nekretnine$Lot.Size ~ nekretnine$Fireplaces)
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 nekretnine$Lot.Size 1728 0.0401 eta2[H] small
> DescTools::DunnTest(nekretnine$Lot.Size, nekretnine$Fireplaces)
##
## Dunn's test of multiple comparisons using rank sums : holm
##
## mean.rank.diff pval
## 1-0 164.8289 1.7e-10 ***
## 2-0 474.9310 1.8e-08 ***
## 3-0 750.1453 0.23586
## 4-0 327.3953 1.00000
## 2-1 310.1021 0.00065 ***
## 3-1 585.3163 0.58445
## 4-1 162.5663 1.00000
## 3-2 275.2143 1.00000
## 4-2 -147.5357 1.00000
## 4-3 -422.7500 1.00000
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Je li barem 5% promatranih nekretnina novogradnja?
> table(nekretnine$New.Construct)
##
## 0 1
## 1647 81
> binom_test(x=81, n = 1728, p=0.05, alternative = "less")
## # A tibble: 1 × 6
## n estimate conf.low conf.high p p.signif
## * <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 1728 0.0469 0 0.0561 0.298 ns
Je li distribucija tipa goriva (fuel.type) je ista među nekretninama koje imaju i onima koje nemaju središnji sustav za klimatizaciju (central.air)?
> table(nekretnine$Central.Air, nekretnine$Fuel.Type)
##
## 2 3 4
## 0 666 248 179
## 1 531 67 37
> chisq.test(nekretnine$Central.Air, nekretnine$Fuel.Type)
##
## Pearson's Chi-squared test
##
## data: nekretnine$Central.Air and nekretnine$Fuel.Type
## X-squared = 98.079, df = 2, p-value < 2.2e-16
Jesu li varijable Fuel.type i Heat.type međusobno neovisne?
> table(nekretnine$Heat.Type, nekretnine$Fuel.Type)
##
## 2 3 4
## 2 961 16 144
## 3 230 1 71
## 4 6 298 1
> chisq.test(nekretnine$Heat.Type, nekretnine$Fuel.Type)
##
## Pearson's Chi-squared test
##
## data: nekretnine$Heat.Type and nekretnine$Fuel.Type
## X-squared = 1594.4, df = 4, p-value < 2.2e-16
> CramerV(nekretnine$Heat.Type, nekretnine$Fuel.Type)
## [1] 0.6792176
> Lambda(nekretnine$Heat.Type, nekretnine$Fuel.Type, direction = "symmetric")
## [1] 0.5043937
> Lambda(nekretnine$Heat.Type, nekretnine$Fuel.Type, direction = "row")
## [1] 0.4645799
> Lambda(nekretnine$Heat.Type, nekretnine$Fuel.Type, direction = "column")
## [1] 0.5499058
Dodatni dobar izvor za učenje inferencijalne statistike uz podršku R-a je udžbenik Summary and Analysis of Extension Program Evaluation in R (Mangiafico, S.S. 2016.).
Arnholt, A. T., & Evans, B. (2017). Package ‘BSDA’. https://cran.r-project.org/web/packages/BSDA/index.html
Ben-Shachar, M. S., Lüdecke, D., & Makowski, D. (2020). effectsize: Estimation of effect size indices and standardized parameters. Journal of open source software, 5(56), 2815. https://dominiquemakowski.github.io/publication/benshachar2020effectsize/benshachar2020effectsize.pdf, https://CRAN.R-project.org/package=effectsize
Conover, W. J. (1999). Practical nonparametric statistics (Vol. 350). John Wiley & sons.
De Veaux, D. (2015). How much is a Fireplace Worth? Stats 101 Public Library.https://community.amstat.org/stats101/resources/viewdocument?DocumentKey=e4f8d3f1-41a3-4f01-9f8b-f8fbe1562c15&tab=librarydocuments&CommunityKey=5ad27b39-58d0-49e9-9f6f-0c39c82a0401
Excel, M. S. (2007). Microsoft Excel. Denver Co., USA.
Hohenwarter, M., & Hohenwarter, M. (2002). GeoGebra. Available on-line at http://www.geogebra.org/cms/en.
Hollander, M., Wolfe, D. A. & Chicken, E. (2013). Nonparametric statistical methods. John Wiley & Sons Inc.
Holmes, A., Illowsky, B., & Dean, S. (2017). Introductory Business Statistics 2e. OpenStax. https://openstax.org/books/introductory-business-statistics/pages/preface
Hornik, K. (2012). The comprehensive R archive network. Wiley interdisciplinary reviews: Computational statistics, 4(4), 394-398.
Horton, N. J., Baumer, B. S., & Wickham, H. (2015). Setting the stage for data science: integration of data management skills in introductory and second courses in statistics (nycflights13). https://nhorton.people.amherst.edu/precursors/nycflights13.pdf
Hothorn, T., Hornik, K., & Hothorn, M. T. (2022). Package ‘exactRankTests’. https://CRAN.R-project.org/package=exactRankTests
Horvat, J., & Mijoč, J. (2018). Osnove statistike, treće dopunjeno izdanje. Zagreb: Ljevak.
Illowsky, B., & Dean, S. (2018). Introductory statistics. https://openstax.org/books/introductory-statistics-2e/pages/preface
JASP Team (2024). JASP (Version 0.19.3)[Computer software].
Kassambara, A. (2019). rstatix: Pipe-friendly framework for basic statistical tests. CRAN: Contributed Packages. https://CRAN.R-project.org/package=rstatix
Kassambara, A. (2023) ggpubr: ‘ggplot2’ Based Publication Ready Plots. CRAN https://CRAN.R-project.org/package=ggpubr
Kostelić, K. & Etinger, D. (2024). Uvod u R i RStudio. Sveučilište Jurja Dobrile u Puli. https://bookdown.org/kakoste/Uvod_u_R_i_RStudio/
Moore, D. S., McCabe, G. P., and Craig, B. A. (2012). Introduction to the Practice of Statistics (7th ed.). New York: Freeman
Okoye, K., & Hosseini, S. (2024). Analysis of variance (ANOVA) in R: one-way and two-way ANOVA. In R Programming: Statistical Data Analysis in Research (pp. 187-209). Singapore: Springer Nature Singapore. https://link.springer.com/chapter/10.1007/978-981-97-3385-9_9
Revelle, W., & Revelle, M. W. (2015). Package ‘psych’. The comprehensive R archive network, 337(338), 161-165. https://cran.rstudio.org/web/packages/psych/psych.pdf
Signorell, A. (2025) DescTools: Tools for Descriptive Statistics. CRAN. https://CRAN.R-project.org/package=DescTools
Šošic, I. (2004). Primijenjena statistika. Skolska knjiga, Zagreb.
Wickham, H., Francois, R., Henry, L., & Müller, K. (2014). dplyr. A Grammar of Data Manipulation 2020 [Last accessed on 2020 Aug 12] Available from, Rproject.
Yarberry, W., & Yarberry, W. (2021). Dplyr. CRAN recipes: DPLYR, stringr, lubridate, and regex in R, 1-58.