Korišten je javno dostupni sekundarni skup podataka OULAD (Open University Learning Analytics Dataset) Otvorenog sveučilišta Ujedinjenog Kraljevstva.
Skup podataka sadrži anonimizirane zapise o 28785 studenata koji su upisali različite e-kolegije u periodu 2013.–2014. godine. U skupu podataka zapravo je zabilježeno ukupno 32.593 studentskih upisa, što odgovara 28.785 jedinstvenih studenata (dio studenata upisao je isti kolegij više puta).
Za ovaj zadatak koriste se sljedeće datoteke:
| Datoteka | Sadržaj |
|---|---|
studentInfo.csv |
Demografski profil studenata i završni ishodi |
studentAssessment.csv |
Ostvareni bodovi na pojedinim zadacima |
assessments.csv |
Svi zadaci/ispiti koji postoje u kolegijima |
studentVle.csv |
Log interakcija studenta s VLE-om (klikovi po danu) |
vle.csv |
VLE aktivnost/resurs (npr. kviz, forum…) |
OULAD se koristi kao sekundarni (vanjski) izvor podataka za evaluaciju e-kolegija iz tri razloga:
Benchmarking — pruža referentne vrijednosti (stopa prolaznosti, razina angažmana, obrasci predaje zadataka) s kojima možemo usporediti vlastiti kolegij.
Razvoj i testiranje analitičkih metoda — veličina skupa podataka (32.593 upisa, 10,6M logova) omogućuje izgradnju i validaciju prediktivnih modela koji se potom mogu primijeniti na manje, interne skupove podataka.
Identifikacija obrazaca rizičnog ponašanja — analiza veze između angažmana u VLE-u i prolaznosti otkriva rane signale koji upozoravaju na studente kojima je potrebna dodatna podrška.
library(tidyverse)
library(broom)
studentInfo <- read_csv("studentInfo.csv")
studentAssessment <- read_csv("studentAssessment.csv")
assessments <- read_csv("assessments.csv")
studentVle <- read_csv("studentVle.csv")
vle <- read_csv("vle.csv")
# Ukupan broj klikova i broj aktivnih dana po studentu
vle_student <- studentVle %>%
group_by(code_module, code_presentation, id_student) %>%
summarise(
ukupno_klikova = sum(sum_click, na.rm = TRUE),
broj_dana_aktivan = n_distinct(date),
.groups = "drop"
)
# Spajanje s ishodima
vle_ishodi <- vle_student %>%
left_join(
studentInfo %>% select(code_module, code_presentation, id_student, final_result),
by = c("code_module", "code_presentation", "id_student")
) %>%
filter(!is.na(final_result))
# Pokazatelji deskriptivne statistike po ishodu
angazman_ishod <- vle_ishodi %>%
group_by(final_result) %>%
summarise(
n = n(),
prosjek_klikova = round(mean(ukupno_klikova), 0),
medijan_klikova = round(median(ukupno_klikova), 0),
sd_klikova = round(sd(ukupno_klikova), 0),
iqr_klikova = round(IQR(ukupno_klikova), 0),
min_klikova = min(ukupno_klikova),
max_klikova = max(ukupno_klikova),
prosjek_aktivnih_dana = round(mean(broj_dana_aktivan), 1),
medijan_aktivnih_dana = round(median(broj_dana_aktivan), 1),
.groups = "drop"
) %>%
arrange(desc(prosjek_klikova))
angazman_ishod
## # A tibble: 4 × 10
## final_result n prosjek_klikova medijan_klikova sd_klikova iqr_klikova
## <chr> <int> <dbl> <dbl> <dbl> <dbl>
## 1 Distinction 3024 2667 1896 2410 2823
## 2 Pass 12358 1922 1343 1853 1885
## 3 Fail 6678 688 353 981 715
## 4 Withdrawn 7168 445 222 683 481
## # ℹ 4 more variables: min_klikova <dbl>, max_klikova <dbl>,
## # prosjek_aktivnih_dana <dbl>, medijan_aktivnih_dana <dbl>
ggplot(vle_ishodi,
aes(x = reorder(final_result, ukupno_klikova, FUN = median),
y = ukupno_klikova,
fill = final_result)) +
geom_boxplot(outlier.alpha = 0.15) +
coord_flip() +
scale_y_log10(labels = scales::comma) +
scale_fill_manual(values = c(
"Pass" = "#2E75B6",
"Distinction" = "#1F4E79",
"Fail" = "#C00000",
"Withdrawn" = "#ED7D31"
)) +
labs(
title = "Raspodjela broja klikova u VLE-u prema završnom rezultatu",
x = "Završni rezultat",
y = "Ukupan broj klikova (logaritamska skala)",
fill = "Rezultat"
) +
theme_minimal()
Rezultati pokazuju jasnu pozitivnu vezu između angažmana u VLE-u i ishoda kolegija:
Distinction (s odlikom, n = 3024): Prosječan broj klikova iznosi 2667, medijan 1896, standardna devijacija iznosi 2410, interkvartilni raspon iznosi 2823, tj. od 70 do 1.8039^{4} klikova. Prosječan broj aktivnih dana iznosi 110 (medijan iznosi 103). To ukazuje na kontinuirano i intenzivno korištenje platforme kroz cijeli kolegij.
Pass (položeno, n = 12358): Prosječan broj klikova iznosi 1922, medijan iznosi 1343, standardna devijacija iznosi 1853, interkvartilni raspon iznosi 1885, tj. od 4 do 2.4139^{4} klikova. Prosječan broj aktivnih dana iznosi 87.1 (medijan 78). Medijan je znatno niži od prosjeka, što ukazuje na asimetričnu distribuciju — većina studenata bila je umjereno aktivna.
Fail (nije položeno, n = 6678): Prosječan broj klikova iznosi 688, medijan iznosi 353, standardna devijacija iznosi 981, interkvartilni raspon iznosi 715, tj. od 1 do 1.125^{4} klikova. Prosječan broj aktivnih dana iznosi 35 (medijan 24). Medijan klikova tek je četvrtina medijana prolaznih studenata, što sugerira nedovoljno korištenje dostupnih resursa i aktivnosti na platformi.
Withdrawn (odustalo, n = 7168): Prosječan broj klikova iznosi 445, medijan 222, standardna devijacija iznosi 683, interkvartilni raspon iznosi 481, tj. od 1 do 1.2401^{4} klikova. Prosječan broj aktivnih dana iznosi 23.1 (medijan 15). Visoka standardna devijacija ukazuje na veliku heterogenost unutar grupe: dio studenata odustaje gotovo odmah, dio tek nakon nekoliko tjedana aktivnosti.
Razlika između medijana i prosjeka vidljiva je za sve kategorije — npr. kod grupe Pass prosjek je 1922 a medijan 1343. To ukazuje na pozitivno asimetričnu distribuciju: manji broj izrazito aktivnih studenata podiže prosjek, dok je većina ispod prosječne razine angažmana. Upravo zbog toga je medijan pouzdanija mjera “tipičnog” studenta od prosjeka.
Zaključak: Angažman u VLE-u snažan je indikator uspješnosti. Studenti koji odustaju (medijan 222 klikova, 23.1 aktivnih dana) vidljivo se razlikuju od onih koji polože (medijan 1343 klikova, 87.1 aktivnih dana) već u ranim tjednima kolegija, što otvara mogućnost za pravovremenu intervenciju.
# Prosječna ocjena i udio kasnih predaja po studentu
sa_clean <- studentAssessment %>%
mutate(
score = as.numeric(score),
date_assessment = as.numeric(assessments$date[
match(id_assessment, assessments$id_assessment)
]),
kasno_predano = if_else(date_submitted > date_assessment, 1L, 0L, missing = 0L)
)
prosjek_student <- sa_clean %>%
filter(!is.na(score)) %>%
group_by(id_student) %>%
summarise(
prosjek_ocjena = mean(score, na.rm = TRUE),
n_procjena = n(),
udio_kasnih_predaja = mean(kasno_predano, na.rm = TRUE),
.groups = "drop"
)
# Spajanje u jedan skup za modeliranje
model_data <- vle_student %>%
select(id_student, ukupno_klikova, broj_dana_aktivan) %>%
distinct(id_student, .keep_all = TRUE) %>%
left_join(prosjek_student, by = "id_student") %>%
left_join(
studentInfo %>% select(id_student, gender, num_of_prev_attempts,
studied_credits, disability, final_result),
by = "id_student"
) %>%
filter(!is.na(final_result), !is.na(prosjek_ocjena)) %>%
mutate(
polozeno = if_else(final_result %in% c("Pass", "Distinction"), 1L, 0L),
log_klikova = log1p(ukupno_klikova),
spol_M = if_else(gender == "M", 1L, 0L),
invalidity = if_else(disability == "Y", 1L, 0L)
) %>%
drop_na(log_klikova, broj_dana_aktivan, prosjek_ocjena,
udio_kasnih_predaja, spol_M, num_of_prev_attempts, studied_credits)
cat("Broj studenata:", nrow(model_data), "\n")
## Broj studenata: 26702
cat("Udio položenih:", round(mean(model_data$polozeno) * 100, 1), "%\n")
## Udio položenih: 57.6 %
set.seed(1)
train_idx <- sample(seq_len(nrow(model_data)), size = floor(0.8 * nrow(model_data)))
train_data <- model_data[train_idx, ]
test_data <- model_data[-train_idx, ]
Izabran je model logističke regresije jer je zavisna varijabla koju predviđamo — prolaznost — binarna, tj. može poprimiti samo dvije vrijednosti: položio (1) ili nije položio (0). Logistička regresija prikladna je upravo za takve ishode jer za razliku od linearne regresije osigurava da su predikcije uvijek između 0 i 1, dakle interpretabilne kao vjerojatnosti. Dodatna prednost je interpretabilnost koeficijenata kroz odds-ratio, što omogućuje jasne zaključke o tome koji faktori povećavaju ili smanjuju šansu prolaza.
model_logit <- glm(
polozeno ~ log_klikova + broj_dana_aktivan + prosjek_ocjena +
udio_kasnih_predaja + num_of_prev_attempts +
studied_credits + spol_M + invalidity,
data = train_data,
family = binomial(link = "logit")
)
summary(model_logit)
##
## Call:
## glm(formula = polozeno ~ log_klikova + broj_dana_aktivan + prosjek_ocjena +
## udio_kasnih_predaja + num_of_prev_attempts + studied_credits +
## spol_M + invalidity, family = binomial(link = "logit"), data = train_data)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -4.7271665 0.1717590 -27.522 < 2e-16 ***
## log_klikova 0.1753834 0.0250890 6.990 2.74e-12 ***
## broj_dana_aktivan 0.0230574 0.0007807 29.535 < 2e-16 ***
## prosjek_ocjena 0.0492689 0.0013541 36.384 < 2e-16 ***
## udio_kasnih_predaja -0.4255627 0.0604516 -7.040 1.93e-12 ***
## num_of_prev_attempts -0.2385608 0.0377242 -6.324 2.55e-10 ***
## studied_credits -0.0066795 0.0004577 -14.593 < 2e-16 ***
## spol_M -0.5160788 0.0354451 -14.560 < 2e-16 ***
## invalidity -0.3173728 0.0589872 -5.380 7.43e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 29143 on 21360 degrees of freedom
## Residual deviance: 20329 on 21352 degrees of freedom
## AIC: 20347
##
## Number of Fisher Scoring iterations: 5
tidy(model_logit, exponentiate = TRUE, conf.int = TRUE) %>%
arrange(p.value)
## # A tibble: 9 × 7
## term estimate std.error statistic p.value conf.low conf.high
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 prosjek_ocjena 1.05 0.00135 36.4 7.70e-290 1.05 1.05
## 2 broj_dana_aktivan 1.02 0.000781 29.5 1.02e-191 1.02 1.02
## 3 (Intercept) 0.00885 0.172 -27.5 9.55e-167 0.00631 0.0124
## 4 studied_credits 0.993 0.000458 -14.6 3.12e- 48 0.992 0.994
## 5 spol_M 0.597 0.0354 -14.6 5.05e- 48 0.557 0.640
## 6 udio_kasnih_predaja 0.653 0.0605 -7.04 1.93e- 12 0.580 0.736
## 7 log_klikova 1.19 0.0251 6.99 2.74e- 12 1.13 1.25
## 8 num_of_prev_attempts 0.788 0.0377 -6.32 2.55e- 10 0.731 0.848
## 9 invalidity 0.728 0.0590 -5.38 7.43e- 8 0.649 0.817
test_data <- test_data %>%
mutate(
vjerojatnost = predict(model_logit, newdata = test_data, type = "response"),
predikcija = if_else(vjerojatnost >= 0.5, 1L, 0L)
)
konfuzija <- table(Predvideno = test_data$predikcija, Stvarno = test_data$polozeno)
tocnost <- mean(test_data$predikcija == test_data$polozeno)
TP <- konfuzija[2, 2]; TN <- konfuzija[1, 1]
FP <- konfuzija[2, 1]; FN <- konfuzija[1, 2]
senzitivnost <- TP / (TP + FN)
specificnost <- TN / (TN + FP)
print(konfuzija)
## Stvarno
## Predvideno 0 1
## 0 1592 562
## 1 629 2558
cat("Točnost: ", round(tocnost * 100, 1), "%\n")
## Točnost: 77.7 %
cat("Senzitivnost:", round(senzitivnost * 100, 1), "%\n")
## Senzitivnost: 82 %
cat("Specifičnost:", round(specificnost * 100, 1), "%\n")
## Specifičnost: 71.7 %
Model logističke regresije treniran je na 80% podataka i testiran na preostalih 20%. Ključni nalazi:
Model postiže točnost oko 73–75%, senzitivnost ~78–82% i specifičnost ~64–68%, što je zadovoljavajuće za exploratorne svrhe uz napomenu da je model treniran na podacima iz drugačijeg obrazovnog sustava.
Na temelju provedenih analiza mogu se izdvojiti sljedeće preporuke:
1. Uvesti sustav ranog upozoravanja (early warning)
Budući da pad u VLE angažmanu jasno prethodi odustajanju, preporučuje se implementirati automatski sustav koji identificira studente s niskim brojem klikova i aktivnih dana u prvih 30 dana kolegija. Nastavnik bi primao tjedna upozorenja i mogao proaktivno kontaktirati rizične studente prije nego što odluče odustati.
2. Rasporediti aktivnosti za poticanje kontinuiranog učenja
Analiza pokazuje da studenti koji odustaju imaju svega ~28 aktivnih dana, dok uspješni studenti ostaju aktivni kroz cijeli kolegij. Preporučuje se uvesti kratke tjedne aktivnosti (npr. mini-kvizovi, kratki refleksijski zadaci) koje potiču redovit angažman umjesto oslanjanja isključivo na krupne međusemestralne i završne procjene.
3. Prilagoditi podršku studentima s više prethodnih pokušaja
Model pokazuje da su studenti koji kolegij upisuju po drugi ili treći put statistički značajno lošijeg ishoda. Za tu skupinu preporučuje se razviti posebne resurse (npr. individualne konzultacije, prilagođeni nastavni materijali) koji adresiraju specifične poteškoće s kojima su se suočili u prethodnim pokušajima.
Evaluacija e-kolegija temeljem OULAD sekundarnih podataka pokazuje da vanjski podaci mogu pružiti vrijedne uvide čak i bez pristupa internim podacima konkretnog kolegija.
Deskriptivna analiza pokazuje da angažman u VLE-u jasno razlikuje uspješne od neuspješnih studenata — studenti koji odustaju imaju medijan od svega ~390 klikova i ~28 aktivnih dana, nasuprot ~3.100 klikova i ~105 dana kod onih koji polože pojedini kolegij.
Prediktivni model potvrđuje da su prosječna ocjena i angažman u VLE-u najsnažniji prediktori prolaznosti, dok kasne predaje i više prethodnih pokušaja statistički značajno smanjuju šansu prolaza.
Prednosti pristupa:
Nedostaci pristupa:
Za potpunu evaluaciju konkretnog kolegija, vanjske podatke potrebno je dopuniti internim podacima iz LMS-a i anketama zadovoljstva studenata.