knitr::opts_chunk$set(
  echo = TRUE,
  message = FALSE,
  warning = FALSE
)
library(tidyverse)
library(car)
library(lmtest)
library(sandwich)
library(tseries)
library(ggplot2)
library(patchwork)
rm(list = ls())

🎓 Úvod do problému

Cieľom tejto analýzy je modelovať výsledné skúškové skóre študentov (exam_score) v závislosti od troch vysvetľujúcich premenných:

hours_studied – počet hodín štúdia,

sleep_hours – priemerný počet hodín spánku,

attendance_percent – percentuálna účasť na vyučovaní.

Pracovná hypotéza:

H₁: Vyšší počet hodín štúdia, viac spánku a vyššia účasť vedú k lepšiemu skúškovému skóre.

📊 Príprava dát

Načítame a vyčistíme dáta z databázy student_exam_scores.csv. Chýbajúce hodnoty nahradíme mediánom danej premennej.

df <- read_csv("student_exam_scores.csv")

# Vyber relevantné stĺpce

df <- df %>%
select(exam_score, hours_studied, sleep_hours, attendance_percent, previous_scores)

# Imputácia chýbajúcich hodnôt mediánom

column_medians <- sapply(df, median, na.rm = TRUE)
for (col in names(df)) {
df[[col]][is.na(df[[col]])] <- column_medians[col]
}

summary(df)
   exam_score    hours_studied     sleep_hours    attendance_percent previous_scores
 Min.   :17.10   Min.   : 1.000   Min.   :4.000   Min.   : 50.30     Min.   :40.0   
 1st Qu.:29.50   1st Qu.: 3.500   1st Qu.:5.300   1st Qu.: 62.20     1st Qu.:54.0   
 Median :34.05   Median : 6.150   Median :6.700   Median : 75.25     Median :67.5   
 Mean   :33.95   Mean   : 6.325   Mean   :6.622   Mean   : 74.83     Mean   :66.8   
 3rd Qu.:38.75   3rd Qu.: 9.000   3rd Qu.:8.025   3rd Qu.: 87.42     3rd Qu.:80.0   
 Max.   :51.30   Max.   :12.000   Max.   :9.000   Max.   :100.00     Max.   :95.0   

Kontrola extrémov a rozdelenia

Vizuálne skontrolujeme premenné pomocou boxplotov.

par(mfrow = c(2, 3))
for (col in names(df)) {
boxplot(df[[col]], main = col, col = "#8ecae6", border = "#023047")
}
par(mfrow = c(1, 1))

📈 Odhad lineárneho regresného modelu

model <- lm(exam_score ~ hours_studied + sleep_hours + attendance_percent, data = df)
summary(model)

Call:
lm(formula = exam_score ~ hours_studied + sleep_hours + attendance_percent, 
    data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-8.5534 -2.7064 -0.1704  3.1321  7.6393 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)        10.90021    1.95832   5.566 8.49e-08 ***
hours_studied       1.62964    0.08502  19.168  < 2e-16 ***
sleep_hours         0.57941    0.18318   3.163  0.00181 ** 
attendance_percent  0.11907    0.01920   6.202 3.24e-09 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.857 on 196 degrees of freedom
Multiple R-squared:  0.6821,    Adjusted R-squared:  0.6773 
F-statistic: 140.2 on 3 and 196 DF,  p-value: < 2.2e-16

🔍 Diagnostické grafy modelu

par(mfrow = c(2, 2))
plot(model, col = "#023047", pch = 19, cex = 0.6)
par(mfrow = c(1, 1))

Interpretácia:

  • Rezíduá sú rozložené približne symetricky okolo nuly.
  • Q–Q graf naznačuje len menšie odchýlky od normality.
  • Scale–Location graf neukazuje výraznú heteroskedasticitu.
  • Žiadne pozorovanie nemá extrémnu Cookovu vzdialenosť → žiadny študent výrazne nedeformuje výsledky.

Testovanie normality a odľahlých hodnôt

residuals <- residuals(model)
jarque.bera.test(residuals)

    Jarque Bera Test

data:  residuals
X-squared = 5.1125, df = 2, p-value = 0.0776
outlierTest(model)
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:

Interpretácia:

Ak p-hodnota testu Jarque–Bera > 0.05, rezíduá sú približne normálne rozložené. Žiadne významné odľahlé pozorovania sa nevyskytli.

🔁 Alternatívny model – log transformácia

Premennú hours_studied zlogaritmizujeme, aby sme zachytili možný nelineárny vzťah.

model2 <- lm(exam_score ~ I(log(hours_studied + 1)) + sleep_hours + attendance_percent, data = df)
summary(model2)

Call:
lm(formula = exam_score ~ I(log(hours_studied + 1)) + sleep_hours + 
    attendance_percent, data = df)

Residuals:
   Min     1Q Median     3Q    Max 
-9.605 -2.687  0.091  3.340  9.939 

Coefficients:
                          Estimate Std. Error t value Pr(>|t|)    
(Intercept)                2.11559    2.27489   0.930  0.35353    
I(log(hours_studied + 1)) 10.04270    0.57918  17.339  < 2e-16 ***
sleep_hours                0.60652    0.19503   3.110  0.00215 ** 
attendance_percent         0.11990    0.02045   5.863  1.9e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.108 on 196 degrees of freedom
Multiple R-squared:  0.6394,    Adjusted R-squared:  0.6339 
F-statistic: 115.9 on 3 and 196 DF,  p-value: < 2.2e-16

Diagnostika nového modelu:

par(mfrow = c(2, 2))
plot(model2, col = "#219ebc", pch = 19, cex = 0.6)
par(mfrow = c(1, 1))

Ak nový model má vyššie R² a lepšie diagnostické vlastnosti, je vhodnejší pre interpretáciu.

Test heteroskedasticity

Vizualizácia rezíduí voči vybraným premenným:

p1 <- ggplot(df, aes(x = hours_studied, y = resid(model)^2)) +
geom_point(color = "#8ecae6", alpha = 0.7) +
geom_smooth(method = "loess", color = "#ffb703") +
labs(x = "Hours studied", y = "Squared residuals", title = "Residuals vs Hours studied") +
theme_minimal()

p2 <- ggplot(df, aes(x = attendance_percent, y = resid(model)^2)) +
geom_point(color = "#8ecae6", alpha = 0.7) +
geom_smooth(method = "loess", color = "#ffb703") +
labs(x = "Attendance (%)", y = "Squared residuals", title = "Residuals vs Attendance") +
theme_minimal()

p1 + p2

Formálny test heteroskedasticity (Breusch–Pagan):

bptest(model)

    studentized Breusch-Pagan test

data:  model
BP = 2.1436, df = 3, p-value = 0.5431
bptest(model2)

    studentized Breusch-Pagan test

data:  model2
BP = 1.7747, df = 3, p-value = 0.6205

Ak p-hodnota > 0.05 → predpoklad homoskedasticity nie je porušený.

🧩 Zhrnutie

✅ Výsledky:

Záver:

Model je vhodný na interpretáciu vzťahu medzi študijnými návykmi a úspešnosťou študentov. Študenti, ktorí sa viac učia a častejšie navštevujú hodiny, dosahujú lepšie výsledky skúšok.

LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIgLSBjdmnEjWVuaWUgNSIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogRGlhbmEgSHJ1xaFvdnNrw6EKLS0tCgpgYGB7cn0KCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwKICBtZXNzYWdlID0gRkFMU0UsCiAgd2FybmluZyA9IEZBTFNFCikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KGxtdGVzdCkKbGlicmFyeShzYW5kd2ljaCkKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGF0Y2h3b3JrKQpybShsaXN0ID0gbHMoKSkKCmBgYAoKIyDwn46TIMOadm9kIGRvIHByb2Jsw6ltdQoKQ2llxL5vbSB0ZWp0byBhbmFsw716eSBqZSBtb2RlbG92YcWlIHbDvXNsZWRuw6kgc2vDusWha292w6kgc2vDs3JlIMWhdHVkZW50b3YgKGV4YW1fc2NvcmUpIHYgesOhdmlzbG9zdGkgb2QgdHJvY2ggdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaDoKCmhvdXJzX3N0dWRpZWQg4oCTIHBvxI1ldCBob2TDrW4gxaF0w7pkaWEsCgpzbGVlcF9ob3VycyDigJMgcHJpZW1lcm7DvSBwb8SNZXQgaG9kw61uIHNww6Fua3UsCgphdHRlbmRhbmNlX3BlcmNlbnQg4oCTIHBlcmNlbnR1w6FsbmEgw7rEjWFzxaUgbmEgdnl1xI1vdmFuw60uCgojIyMgUHJhY292bsOhIGh5cG90w6l6YToKCkjigoE6IFZ5xaHFocOtIHBvxI1ldCBob2TDrW4gxaF0w7pkaWEsIHZpYWMgc3DDoW5rdSBhIHZ5xaHFoWlhIMO6xI1hc8WlIHZlZMO6IGsgbGVwxaFpZW11IHNrw7rFoWtvdsOpbXUgc2vDs3JlLgoKIyDwn5OKIFByw61wcmF2YSBkw6F0CgpOYcSNw610YW1lIGEgdnnEjWlzdMOtbWUgZMOhdGEgeiBkYXRhYsOhenkgc3R1ZGVudF9leGFtX3Njb3Jlcy5jc3YuIENow71iYWrDumNlIGhvZG5vdHkgbmFocmFkw61tZSBtZWRpw6Fub20gZGFuZWogcHJlbWVubmVqLgoKYGBge3J9CmRmIDwtIHJlYWRfY3N2KCJzdHVkZW50X2V4YW1fc2NvcmVzLmNzdiIpCgojIFZ5YmVyIHJlbGV2YW50bsOpIHN0xLpwY2UKCmRmIDwtIGRmICU+JQpzZWxlY3QoZXhhbV9zY29yZSwgaG91cnNfc3R1ZGllZCwgc2xlZXBfaG91cnMsIGF0dGVuZGFuY2VfcGVyY2VudCwgcHJldmlvdXNfc2NvcmVzKQoKIyBJbXB1dMOhY2lhIGNow71iYWrDumNpY2ggaG9kbsO0dCBtZWRpw6Fub20KCmNvbHVtbl9tZWRpYW5zIDwtIHNhcHBseShkZiwgbWVkaWFuLCBuYS5ybSA9IFRSVUUpCmZvciAoY29sIGluIG5hbWVzKGRmKSkgewpkZltbY29sXV1baXMubmEoZGZbW2NvbF1dKV0gPC0gY29sdW1uX21lZGlhbnNbY29sXQp9CgpzdW1tYXJ5KGRmKQoKYGBgCgojIEtvbnRyb2xhIGV4dHLDqW1vdiBhIHJvemRlbGVuaWEKClZpenXDoWxuZSBza29udHJvbHVqZW1lIHByZW1lbm7DqSBwb21vY291IGJveHBsb3Rvdi4KCmBgYHtyfQpwYXIobWZyb3cgPSBjKDIsIDMpKQpmb3IgKGNvbCBpbiBuYW1lcyhkZikpIHsKYm94cGxvdChkZltbY29sXV0sIG1haW4gPSBjb2wsIGNvbCA9ICIjOGVjYWU2IiwgYm9yZGVyID0gIiMwMjMwNDciKQp9CnBhcihtZnJvdyA9IGMoMSwgMSkpCgpgYGAKCiMg8J+TiCBPZGhhZCBsaW5lw6FybmVobyByZWdyZXNuw6lobyBtb2RlbHUKCmBgYHtyfQptb2RlbCA8LSBsbShleGFtX3Njb3JlIH4gaG91cnNfc3R1ZGllZCArIHNsZWVwX2hvdXJzICsgYXR0ZW5kYW5jZV9wZXJjZW50LCBkYXRhID0gZGYpCnN1bW1hcnkobW9kZWwpCgpgYGAKCiMg8J+UjSBEaWFnbm9zdGlja8OpIGdyYWZ5IG1vZGVsdQoKYGBge3J9CnBhcihtZnJvdyA9IGMoMiwgMikpCnBsb3QobW9kZWwsIGNvbCA9ICIjMDIzMDQ3IiwgcGNoID0gMTksIGNleCA9IDAuNikKcGFyKG1mcm93ID0gYygxLCAxKSkKCmBgYAoKIyMjIEludGVycHJldMOhY2lhOgoKLSAgIFJlesOtZHXDoSBzw7ogcm96bG/FvmVuw6kgcHJpYmxpxb5uZSBzeW1ldHJpY2t5IG9rb2xvIG51bHkuCi0gICBR4oCTUSBncmFmIG5hem5hxI11amUgbGVuIG1lbsWhaWUgb2RjaMO9bGt5IG9kIG5vcm1hbGl0eS4KLSAgIFNjYWxl4oCTTG9jYXRpb24gZ3JhZiBuZXVrYXp1amUgdsO9cmF6bsO6IGhldGVyb3NrZWRhc3RpY2l0dS4KLSAgIMW9aWFkbmUgcG96b3JvdmFuaWUgbmVtw6EgZXh0csOpbW51IENvb2tvdnUgdnpkaWFsZW5vc8WlIOKGkiDFvmlhZG55IMWhdHVkZW50IHbDvXJhem5lIG5lZGVmb3JtdWplIHbDvXNsZWRreS4KCiMgVGVzdG92YW5pZSBub3JtYWxpdHkgYSBvZMS+YWhsw71jaCBob2Ruw7R0CgpgYGB7cn0KcmVzaWR1YWxzIDwtIHJlc2lkdWFscyhtb2RlbCkKamFycXVlLmJlcmEudGVzdChyZXNpZHVhbHMpCgpvdXRsaWVyVGVzdChtb2RlbCkKCmBgYAoKIyMjIEludGVycHJldMOhY2lhOgoKQWsgcC1ob2Rub3RhIHRlc3R1IEphcnF1ZeKAk0JlcmEgXD4gMC4wNSwgcmV6w61kdcOhIHPDuiBwcmlibGnFvm5lIG5vcm3DoWxuZSByb3psb8W+ZW7DqS4gxb1pYWRuZSB2w716bmFtbsOpIG9kxL5haGzDqSBwb3pvcm92YW5pYSBzYSBuZXZ5c2t5dGxpLgoKIyDwn5SBIEFsdGVybmF0w612bnkgbW9kZWwg4oCTIGxvZyB0cmFuc2Zvcm3DoWNpYQoKUHJlbWVubsO6IGhvdXJzX3N0dWRpZWQgemxvZ2FyaXRtaXp1amVtZSwgYWJ5IHNtZSB6YWNoeXRpbGkgbW/Fvm7DvSBuZWxpbmXDoXJueSB2esWlYWguCgpgYGB7cn0KbW9kZWwyIDwtIGxtKGV4YW1fc2NvcmUgfiBJKGxvZyhob3Vyc19zdHVkaWVkICsgMSkpICsgc2xlZXBfaG91cnMgKyBhdHRlbmRhbmNlX3BlcmNlbnQsIGRhdGEgPSBkZikKc3VtbWFyeShtb2RlbDIpCgpgYGAKCkRpYWdub3N0aWthIG5vdsOpaG8gbW9kZWx1OgoKYGBge3J9CnBhcihtZnJvdyA9IGMoMiwgMikpCnBsb3QobW9kZWwyLCBjb2wgPSAiIzIxOWViYyIsIHBjaCA9IDE5LCBjZXggPSAwLjYpCnBhcihtZnJvdyA9IGMoMSwgMSkpCgpgYGAKCkFrIG5vdsO9IG1vZGVsIG3DoSB2ecWhxaFpZSBSwrIgYSBsZXDFoWllIGRpYWdub3N0aWNrw6kgdmxhc3Rub3N0aSwgamUgdmhvZG5lasWhw60gcHJlIGludGVycHJldMOhY2l1LgoKIyBUZXN0IGhldGVyb3NrZWRhc3RpY2l0eQoKVml6dWFsaXrDoWNpYSByZXrDrWR1w60gdm/EjWkgdnlicmFuw71tIHByZW1lbm7DvW06CgpgYGB7cn0KcDEgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IGhvdXJzX3N0dWRpZWQsIHkgPSByZXNpZChtb2RlbCleMikpICsKZ2VvbV9wb2ludChjb2xvciA9ICIjOGVjYWU2IiwgYWxwaGEgPSAwLjcpICsKZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgY29sb3IgPSAiI2ZmYjcwMyIpICsKbGFicyh4ID0gIkhvdXJzIHN0dWRpZWQiLCB5ID0gIlNxdWFyZWQgcmVzaWR1YWxzIiwgdGl0bGUgPSAiUmVzaWR1YWxzIHZzIEhvdXJzIHN0dWRpZWQiKSArCnRoZW1lX21pbmltYWwoKQoKcDIgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IGF0dGVuZGFuY2VfcGVyY2VudCwgeSA9IHJlc2lkKG1vZGVsKV4yKSkgKwpnZW9tX3BvaW50KGNvbG9yID0gIiM4ZWNhZTYiLCBhbHBoYSA9IDAuNykgKwpnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBjb2xvciA9ICIjZmZiNzAzIikgKwpsYWJzKHggPSAiQXR0ZW5kYW5jZSAoJSkiLCB5ID0gIlNxdWFyZWQgcmVzaWR1YWxzIiwgdGl0bGUgPSAiUmVzaWR1YWxzIHZzIEF0dGVuZGFuY2UiKSArCnRoZW1lX21pbmltYWwoKQoKcDEgKyBwMgoKYGBgCgpGb3Jtw6FsbnkgdGVzdCBoZXRlcm9za2VkYXN0aWNpdHkgKEJyZXVzY2jigJNQYWdhbik6CgpgYGB7cn0KYnB0ZXN0KG1vZGVsKQpicHRlc3QobW9kZWwyKQoKYGBgCgpBayBwLWhvZG5vdGEgXD4gMC4wNSDihpIgcHJlZHBva2xhZCBob21vc2tlZGFzdGljaXR5IG5pZSBqZSBwb3J1xaFlbsO9LgoKIyDwn6epIFpocm51dGllCgrinIUgVsO9c2xlZGt5OgoKLSAgIGhvdXJzX3N0dWRpZWQgYSBhdHRlbmRhbmNlX3BlcmNlbnQgc8O6IMWhdGF0aXN0aWNreSB2w716bmFtbsOpIGEgbWFqw7ogcG96aXTDrXZueSB2cGx5di4KLSAgIHNsZWVwX2hvdXJzIG3DoSBtZW7FocOtIGFsZWJvIG5ldsO9em5hbW7DvSBlZmVrdC4KLSAgIFJlesOtZHXDoSBzw7ogcHJpYmxpxb5uZSBub3Jtw6FsbmUgYSBoZXRlcm9za2VkYXN0aWNpdGEgc2EgbmVwb3R2cmRpbGEuCgojIyBaw6F2ZXI6CgpNb2RlbCBqZSB2aG9kbsO9IG5hIGludGVycHJldMOhY2l1IHZ6xaVhaHUgbWVkemkgxaF0dWRpam7DvW1pIG7DoXZ5a21pIGEgw7pzcGXFoW5vc8Wlb3UgxaF0dWRlbnRvdi4gxaB0dWRlbnRpLCBrdG9yw60gc2EgdmlhYyB1xI1pYSBhIMSNYXN0ZWrFoWllIG5hdsWhdGV2dWrDuiBob2RpbnksIGRvc2FodWrDuiBsZXDFoWllIHbDvXNsZWRreSBza8O6xaFvay4K