[1] Problema orarului școlar echilibrat și limbajul R
[2] V. Bazon - Orare școlare echilibrate și limbajul R https://books.google.ro/books?id=aWrDEAAAQBAJ
Într-un târziu, ne vom baza pe funcțiile din [2] mount_days()
, mount_hours(
) și reduce_gaps()
, pentru a repartiza pe zile lecțiile prof|cls
(echilibrat, față de zile, clase și profesori), a monta pe orele zilei lecțiile dintr-o aceeași zi și respectiv, pentru a reduce (cam pe cât se poate) numărul de ferestre din orarul rezultat.
Dar mai întâi, privim iarăși la clasele cuplate – organizând mai bine față de tabelul anterior Twc
, datele asociate acestora în orarul inițial; scopul este acela de a repartiza pe zile (înaintea celorlalte) lecțiile anumitor cuplaje de profesori, la clasele cuplate existente.
Printre cele 928 de lecții din setul CDL
, avem pe anumite discipline câteva lecții ale unor cuplaje de profesori, la clase cuplate; de exemplu, un cuplaj de trei profesori are de făcut două lecții de "Germană" la clasele 11ABD
: fiecare dintre aceste două lecții angajează într-o aceeași zi și oră, trei grupe de elevi constituite din elevii amestecați ai celor trei clase.
Pentru a nu „urăți” peste măsură funcțiile de alocare (pe zile și pe orele zilei), alegem soluția cea mai simplă: convenim din start asupra unui orar de desfășurare a lecțiilor P23|C23
unde P23
este un cuplaj de doi sau de trei profesori, iar C23
este o pereche sau un triplet de clase (a revedea tabelul anterior Twc1
); numărul acestor lecții nu este prea mare, încât preferăm să elaborăm manual – sau mai degrabă, interactiv – orarul respectiv.
Lansăm o nouă sesiune de lucru cu R, pe baza următorului program:
# orr_cls_cupl.R (orar prealabil, la perechile|tripletele de clase cuplate) rm(list = ls()) # elimină obiectele din sesiunea precedentă library(tidyverse) CDL <- readRDS("CDL.rds") # 928 lecții prof|obj|cls|zi|ora (orarul original) load("Tw123.Rda") # dicționarele dependențelor Zile <- c("Lu", "Ma", "Mi", "Jo", "Vi") CDL <- CDL %>% mutate(zi = factor(zi, levels = Zile, ordered=TRUE), prof = factor(prof)) %>% select(prof, cls, ora, zi)
Avem clase cuplate, câte două sau câte trei, pe "Germană" și pe "Desen/Muzică"; determinăm cuplajele de doi sau trei profesori, care fac lecțiile respective:
P23 <- union(names(Tw2), names(Tw3)) # cuplajele de doi sau trei profesori P23 <- P23[grepl("Ds", P23) | grepl("LG", P23)] # "Desen/Muzică" sau "Germană" # "Ds1Mz1" "LG1LG4" "LG2LG1" "LG2LG3" "LG3LG4" "LG3LG1LG4"
Setul tuturor lecțiilor acestora (pe clase cuplate sau pe grupe ale unei aceleiași clase) este:
L123 <- CDL %>% filter(prof %in% P23) %>% droplevels() > print(L123 %>% arrange(prof, cls) %>% head(13)) prof cls ora zi 1 Ds1Mz1 10F 2 Vi # "pe grupe" ale clasei 2 Ds1Mz1 10B 3 Jo 3 Ds1Mz1 10C 6 Ma 4 Ds1Mz1 10D 4 Jo 5 Ds1Mz1 10E 4 Vi 6 Ds1Mz1 9A 7 Ma # cuplaj de clase "9AB" 7 Ds1Mz1 9B 7 Ma 8 Ds1Mz1 9C 5 Jo # "9CD" 9 Ds1Mz1 9D 5 Jo 10 LG1LG4 10F 4 Mi # "10EF" 11 LG1LG4 10F 5 Jo 12 LG1LG4 10E 4 Mi 13 LG1LG4 10E 5 Jo
Observăm că 10F
apare singură (nu împreună cu vreo altă clasă) în ora 2
din ziua Vi
– deci Ds1Mz1
face lecția la 10F
„pe grupe” (analog, la alte clase de-a 10-a): în săptămâna curentă Ds1
intră la grupa-1 și Mz1
intră la grupa-2 și invers, în săptămâna următoare (sau echivalent, dar mai convenabil: clasa întreagă 10F
alternează săptămânal "Desen" și "Muzică").
În schimb, clasele 9A
și 9B
apar la Ds1Mz1
într-o aceeași zi și oră – deci în ora 7
din ziua Ma
:
Ds1
intră la 9A
și Mz1
intră la 9B
în săptămâna curentă, și invers în cea următoare.
Situații asemănătoare avem pentru "Germană" (dar fără alternanță săptămânală): elevii claselor 10EF
sunt categorisiți, probabil ca „începători” sau „avansați”, rezultând două noi clase, la care intră într-o aceeași zi și oră (de două ori pe săptămână) LG1
și respectiv LG4
.
Deocamdată, ne interesează numai lecțiile pe clase cuplate – deci numai perechile sau tripletele de linii din setul L123
pe care avem aceleași valori prof|zi|ora
(diferind în perechea sau tripletul respectiv, numai câmpul cls
):
L23 <- L123 %>% count(prof, zi, ora) %>% filter(n >= 2) # Lecțiile (fără 'cls') cuplajelor la clasele cuplate L23 <- right_join(L23, L123) %>% # exclude din L123 liniile neaflate în P23 filter(!is.na(n))
Acum putem observa în treacăt, cum sunt distribuite pe zile în orarul original, lecțiile cuplajelor de profesori la clasele cuplate:
> cz <- L23 %>% select(prof,zi,ora) %>% distinct() %>% select(prof,zi) > print(table(cz$zi)) Lu Ma Mi Jo Vi 3 6 4 7 4 # cuplaje de clase (perechi sau triplete), pe zi
Noi încercăm să facem un orar echilibrat (din mai multe puncte de vedere); astfel că vrem să apară cam același număr de cuplaje de clase, în fiecare zi (nu 3 într-o zi și 7 într-o alta).
Dar chiar, vrem mai mult: rămăseseră 5 clase 10BCDEF
, la care Ds1Mz1
trebuie să intre „pe grupe” (la fiecare dintre ele); nu vedem niciun motiv, pentru care să nu putem constitui (analog cu 9AB
) de exemplu, clasele cuplate 10BD
și 10EF
(lăsând numai 10C
„pe grupe”)…
Dar oare… clasa 10A
face altfel decât celelalte clase a 10-a, "Desen" și "Muzică"?
Trebuie să verificăm:
> CDL %>% filter(cls=="10A") %>% filter(grepl("Ds1", prof) | grepl("Mz1", prof)) prof cls ora zi 1 LE3Mz1 10A 3 Mi # Muzică/Engleză (??) 2 Ds1 10A 4 Mi # Desen
Deci 10A
face "Desen" o oră pe săptămână (nu jumătate de oră, cum fac toate clasele a 9-a și a 10-a), iar drept "Muzică"… chiar ciudat: Mz1
împarte clasa cu LE3
("Engleză")!
Este clar că am greșit ceva, undeva pe parcurs. Confruntând orarul clasei 10A
din CDL
cu cel din fișierul PDF original – constatăm că Mi
ora 3 trebuia să fie LE3
(nu LE3Mz1
) și Mi
ora 4 trebuia să fie Ds1Mz1
(nu Ds1
); am greșit nu „pe parcurs”, ci din start, când am editat în Mousepad datele extrase prin Ghostscript din fișierul PDF, constituind fișierul "CDL.txt
".
Pentru orice eventualitate, în CDL.txt
am făcut imediat corecția necesară; dar (câtă vreme ne putem zice că nu s-au strecurat și alte greșeli) nu este necesar s-o luăm de la capăt. Corectăm ad-hoc în setul CDL
(și reconstituim CDL.rds
):
> CDL[which(with(CDL, prof=="LE3Mz1") == TRUE), "prof"] <- "LE3" > CDL[which(with(CDL, cls=="10A" & prof=="Ds1") == TRUE), "prof"] <- "Ds1Mz1" > saveRDS(CDL, "CDL.rds")
Mai avem de corectat în dicționarele de dependențe, eliminând "LE3Mz1
":
> Tw1$LE3 <- NULL > Tw1$Mz1 <- c("Ds1Mz1") > Tw2$Ds1Mz1 <- c("Ds1", "Mz1") > Tw2$LE3Mz1 <- NULL > save(Tw1, Tw2, Tw3, file="Tw123.Rda")
Dacă relansăm acum "orr_cls_cupl.R
", singura modificare față de datele redate mai sus constă în faptul că în L123
apare și 10A
în contul lui Ds1Mz1
; deci vom putea completa cuplajele de clase intenționate mai sus (10BD
și 10EF
) cu 10AC
(încât și la clasele a 10-a, Ds1Mz1
va putea face lecțiile pe clase cuplate, în loc de „pe grupe” ale câte uneia).
Acum împărțim liniile din L23
, încât în fiecare grup de linii să avem aceleași valori prof
, zi
și ora
(diferind doar cls
); apoi asociem acestor grupuri de linii câte un „tabel” cu același număr de linii ca grupul respectiv, conținând pe o coloană profesorul respectiv și pe o a doua coloană, vectorul claselor (repetat și acesta pe fiecare linie); reunim toate tabelele, ordonăm după prof
și cls
liniile din „tabelul” rezultat și apoi, adăugăm coloana zi
pe care înscriem repetat de sus în jos, valorile din vectorul Zile
:
L23 <- L23 %>% select(prof, zi, ora, cls) %>% split(list(.$prof, .$zi, .$ora)) %>% discard(function(K) nrow(K) == 0) %>% map_dfr(., function(K) data.frame( prof = K$prof[1], cls = paste(K$cls, collapse = " ") )) %>% arrange(prof, cls) %>% mutate(zi = factor(rep_len(Zile, nrow(.)), levels = Zile, ordered = TRUE)) print(L23) prof cls zi 1 Ds1Mz1 9A 9B Lu 2 Ds1Mz1 9C 9D Ma 3 LG1LG4 10E 10F Mi 4 LG1LG4 10E 10F Jo 5 LG2LG1 10A 10B Vi 6 LG2LG1 10A 10B Lu 7 LG2LG1 10C 10D Ma 8 LG2LG1 10C 10D Mi 9 LG2LG1 12E 12F Jo 10 LG2LG1 12E 12F Vi 11 LG2LG1 12E 12F Lu 12 LG2LG1 9A 9B Ma 13 LG2LG1 9A 9B Mi 14 LG2LG3 11E 11F Jo 15 LG2LG3 11E 11F Vi 16 LG2LG3 11E 11F Lu 17 LG2LG3 9E 9F Ma 18 LG2LG3 9E 9F Mi 19 LG2LG3 9E 9F Jo 20 LG3LG1LG4 11A 11B 11D Vi 21 LG3LG1LG4 11A 11B 11D Lu 22 LG3LG1LG4 12A 12B 12D Ma 23 LG3LG1LG4 12A 12B 12D Mi 24 LG3LG4 10E 10F Jo
Am obținut astfel o repartizare pe zile a lecțiilor cuplajelor de profesori la cele 24 de perechi sau triplete de clase cuplate – și anume, o repartizare echilibrată: fiindcă am etichetat cu Zile
de patru ori complet și încă o dată dar fără Vi
, rezultă că în primele 4 zile avem câte 5 lecții la clase cuplate, iar în a 5-a avem 4 lecții.
Dar să observăm că 10EF
apare de două ori în ziua Jo
: în linia 4 cu LG1LG4
și în linia 24 cu LG3LG4
; reetichetăm linia 24, pentru a evita situația menționată:
> L23[24, 3] <- "Vi"
Acum fiecare dintre clasele cuplate apare cel mult o singură dată pe zi:
> print(addmargins(table(L23[c('cls','zi')]))) cls Lu Ma Mi Jo Vi Sum 10A 10B 1 0 0 0 1 2 10C 10D 0 1 1 0 0 2 10E 10F 0 0 1 1 1 3 11A 11B 11D 1 0 0 0 1 2 11E 11F 1 0 0 1 1 3 12A 12B 12D 0 1 1 0 0 2 12E 12F 1 0 0 1 1 3 9A 9B 1 1 1 0 0 3 9C 9D 0 1 0 0 0 1 9E 9F 0 1 1 1 0 3 Sum 5 5 5 4 5 24
Distribuțiile zilnice individuale, pentru cuplajele de profesori care fac ore la clasele cuplate sunt deasemenea, echilibrate:
> print(addmargins(table(L23[c('prof','zi')]))) prof Lu Ma Mi Jo Vi Sum Ds1Mz1 1 1 0 0 0 2 LG1LG4 0 0 1 1 0 2 LG2LG1 2 2 2 1 2 9 LG2LG3 1 1 1 2 1 6 LG3LG1LG4 1 1 1 0 1 4 LG3LG4 0 0 0 0 1 1 Sum 5 5 5 4 5 24
În sfârșit să instituim în L23
și clasele cuplate 10AC
, 10BD
și 10EF
, în contul lui Ds1Mz1
:
> dm10 <- data.frame(prof = rep("Ds1Mz1", 3), cls = c("10A 10C", "10B 10D", "10E 10F"), zi = c("Jo", "Mi", "Vi")) > L23 <- rbind(L23, dm10) > saveRDS(L23, "cls23_days.RDS")
În "cls23_days.RDS
" avem acum ceea ce numisem cam exagerat „orar prealabil”, de fapt numai o repartizare pe zile (nu și pe orele zilei, cum se cuvenea unui „orar”), pentru lecțiile cuplajelor de doi sau trei profesori, la clasele cuplate (câte două sau câte trei). Se prea poate ca ulterior, să modificăm (dar în aceleași condiții de echilibru ca mai sus) repartizarea pe zile din L23
; așa că se cuvine să amânăm adăugarea unei coloane în care să etichetăm lecțiile respective cu orele zilei.
În fond, zi
și ora
sunt variabile independente, deci chiar se cuvine, să le tratăm separat!
Rupem de-acum legătura cu orarul original, eliminând din CDL
coloanele inițiale zi
și ora
; în plus, trebuie să eliminăm din setul CDL
lecțiile pe care deja le-am repartizat pe zile prin L23
– urmând să ne ocupăm de montarea pe zile (echilibrată) a lecțiilor rămase:
LSS <- CDL %>% select(prof, cls) qls <- sapply(L23$cls, function(Q) strsplit(Q, " ")[[1]]) %>% unlist() %>% as.vector() %>% unique() Del <- LSS %>% filter(prof %in% L23$prof & cls %in% qls) LSS <- anti_join(LSS, Del) %>% droplevels() # 870 obs. of 2 variables saveRDS(LSS, "lessons.RDS")
În lessons.RDS
avem 870 de lecții prof|cls
, unde prof
reprezintă fie un profesor „real”, fie un cuplaj (de doi profesori) diferit de cele înregistrate în L23
; urmează să repartizăm pe zile, în mod echilibrat, aceste lecții.
vezi Cărţile mele (de programare)