Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
pp:2024:tema1 [2024/03/23 10:11] alexandra.udrescu01 |
pp:2024:tema1 [2024/04/01 14:22] (current) alexandra.udrescu01 |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Tema 1: Regresie Liniara ====== | ====== Tema 1: Regresie Liniara ====== | ||
- | Deadline: 12 aprilie 2024 | + | Deadline: ''12 aprilie 2024'' |
- | Schelet de cod: {{:pp:2024:tema1:t1-skel.zip|}} | + | Schelet de cod: {{:pp:2024:tema1:t1_v2.zip|}} |
+ | /* {{:pp:2024:tema1:t1.zip|}} */ | ||
+ | |||
+ | <note warning>Schelet actualizat 24 martie - adaugat teste pentru Regresie.</note> | ||
+ | <note warning>Cerinta actualizata 26 martie - update cerinta ''split'' & schelet actualizat pentru testarea lui ''split''.</note> | ||
<note warning> | <note warning> | ||
Folosiți un stil de programare funcțional. | Folosiți un stil de programare funcțional. | ||
Line 112: | Line 116: | ||
def split(percentage: Double): (Dataset, Dataset) = ??? | def split(percentage: Double): (Dataset, Dataset) = ??? | ||
</code> | </code> | ||
- | care imparte setul de date in doua seturi. Valoarea ''percentage'' este intre ''0'' si ''0.5'' si reprezinta procentul din dataset ce va fi pastrat pentru evaluare, din totalul de intrari ale dataset-ului. Metoda va intoarce o pereche de dataset-uri: unul mai mare (numit "de antrenare") si unul mai mic ("de testare/validare"). Pentru aceasta impartire, urmatii pasii urmatori: | + | care imparte setul de date in doua seturi. Valoarea ''percentage'' este intre ''0'' si ''0.5'' si reprezinta procentul din dataset ce va fi pastrat pentru evaluare, din totalul de intrari ale dataset-ului. Metoda va intoarce o pereche de dataset-uri: unul mai mare (numit "de antrenare") si unul mai mic ("de testare/validare"). Pentru aceasta impartire, urmati pasii urmatori: |
- Sortati setul de date crescator dupa prima coloana | - Sortati setul de date crescator dupa prima coloana | ||
- | - Parcurgeti lista de intrari (de la sus in jos) | + | - Pentru fiecare $math[ 1 / percentage - 1] intrari consecutive din dataset-ul sortat, adaugati o intrare in dataset-ul de evaluare, iar restul - in cel de training. |
- | - La fiecare pas, verificati cate din elementele procesate au fost adaugate in setul de date de evaluare | + | |
- | - Daca procentul e mai mic decat cel tinta, adaugati elementul in setul de date de test, altfel, in cel de antrenare | + | |
<note warning>Aveti grija la randul de cap de tabel. Aceasta nu este considerat o intrare si trebuie sa apara in ambele dataseturi construite. </note> | <note warning>Aveti grija la randul de cap de tabel. Aceasta nu este considerat o intrare si trebuie sa apara in ambele dataseturi construite. </note> | ||
Line 211: | Line 213: | ||
- **Gradient Descent:** Pentru un numar predefinit de pasi (''gradient_descent_steps''), se executa urmatorii sub-pasi: | - **Gradient Descent:** Pentru un numar predefinit de pasi (''gradient_descent_steps''), se executa urmatorii sub-pasi: | ||
- **Calculul estimarilor:** Folosind atributele fiecarei locuinte si ipoteza de la pasul curent (coeficientii asociati fiecarui atribut), vom inmulti matricea ''X'' de dimensiune $math[m * (n + 1)] cu vectorul de coeficienti ''W'' de dimensiune $math[(n + 1) * 1], rezultand un **vector de estimari** de dimensiune $math[m * 1]. Acest vector de estimari reprezinta practic pretul prezis de regresia noastra pentru fiecare din cele m locuinte din setul de date. Cu alte cuvinte, daca ''W'' are coeficientii $math[W_0, W_1, ..., W_n] iar o locuinta are atributele $math[1, X_1, X_2, ..., X_n], noi vom calcula pretul prezis ca fiind $math[W_0 + W_1 * X_1 + W_2 * X_2 + ... + W_n * X_n]. | - **Calculul estimarilor:** Folosind atributele fiecarei locuinte si ipoteza de la pasul curent (coeficientii asociati fiecarui atribut), vom inmulti matricea ''X'' de dimensiune $math[m * (n + 1)] cu vectorul de coeficienti ''W'' de dimensiune $math[(n + 1) * 1], rezultand un **vector de estimari** de dimensiune $math[m * 1]. Acest vector de estimari reprezinta practic pretul prezis de regresia noastra pentru fiecare din cele m locuinte din setul de date. Cu alte cuvinte, daca ''W'' are coeficientii $math[W_0, W_1, ..., W_n] iar o locuinta are atributele $math[1, X_1, X_2, ..., X_n], noi vom calcula pretul prezis ca fiind $math[W_0 + W_1 * X_1 + W_2 * X_2 + ... + W_n * X_n]. | ||
- | - **Calculul erorii:** In continuare, vrem sa facem astfel incat pretul prezis sa se apropie cat mai mult cu pretul real al locuintelor, definind astfel o functie de eroare egala cu diferenta dintre pretul real si cel prezis (preturile prezise sunt valorile din vectorul de estimari), in modul. Pretul real pentru toate locuintele se va retine ca un vector ''Y'' cu dimensiunea $math[m * 1]. Astfel eroarea va avea, de asemenea, dimensiunea $math[m * 1]. | + | - **Calculul erorii:** In continuare, vrem sa facem astfel incat pretul prezis sa se apropie cat mai mult cu pretul real al locuintelor, definind astfel o functie de eroare egala cu diferenta dintre pretul prezis si cel real (preturile prezise sunt valorile din vectorul de estimari). Pretul real pentru toate locuintele se va retine ca un vector ''Y'' cu dimensiunea $math[m * 1]. Astfel eroarea va avea, de asemenea, dimensiunea $math[m * 1]. |
- **Calculul gradientului:** Gradientul reprezinta directia (crestem sau scadem) si marimea ajustarii necesare pentru coeficientii ''W'', pentru a reduce eroarea. Se calculeaza inmultind transpusa matricei ''X'' (de dimensiune $math[(n+1) * m]) cu vectorul de eroare (de dimensiune $math[m * 1]), si apoi se imparte fiecare element la m pentru a obtine media aritmetica. Rezultatul este un vector de dimensiune $math[(n+1) * 1]. | - **Calculul gradientului:** Gradientul reprezinta directia (crestem sau scadem) si marimea ajustarii necesare pentru coeficientii ''W'', pentru a reduce eroarea. Se calculeaza inmultind transpusa matricei ''X'' (de dimensiune $math[(n+1) * m]) cu vectorul de eroare (de dimensiune $math[m * 1]), si apoi se imparte fiecare element la m pentru a obtine media aritmetica. Rezultatul este un vector de dimensiune $math[(n+1) * 1]. | ||
- **Actualizarea ipotezei (W):** Se actualizeaza ''W'' scazand produsul dintre gradient si un pas de invatare (alpha, un scalar), din valorile curente ale lui ''W''. Acest pas determina cat de repede invatam sau ajustam parametrii - influentand viteza de convergere la valorile optime. Noua valoare a lui ''W'' va fi folosita in urmatoarea iteratie a algoritmului. | - **Actualizarea ipotezei (W):** Se actualizeaza ''W'' scazand produsul dintre gradient si un pas de invatare (alpha, un scalar), din valorile curente ale lui ''W''. Acest pas determina cat de repede invatam sau ajustam parametrii - influentand viteza de convergere la valorile optime. Noua valoare a lui ''W'' va fi folosita in urmatoarea iteratie a algoritmului. | ||
- | - Acum ca avem coeficientii regresiei, pentru ca am calculat matricea ''W'' dupa ''gradient_descent_steps'' pasi, vrem sa vedem cat de buna este estimarea noastra. Acum vom lua setul de date de validare si vom calcula predictiile regresiei noastre pentru fiecare locuinta. In continuare, vom calcula eroarea ca media aritmetica intre modulul diferentei dintre pretul prezis si cel real pentru fiecare locuinta din acest set de date de validare. | + | - Acum ca avem coeficientii regresiei, pentru ca am calculat matricea ''W'' dupa ''gradient_descent_steps'' pasi, vrem sa vedem cat de buna este estimarea noastra. Acum vom lua setul de date de validare si vom calcula predictiile regresiei noastre pentru fiecare locuinta. In continuare, vom calcula eroarea ca media aritmetica intre diferentei dintre pretul prezis si cel real pentru fiecare locuinta din acest set de date de validare. |
- Vom intoarce ipoteza finala ''W'' si eroarea pe setul de validare. | - Vom intoarce ipoteza finala ''W'' si eroarea pe setul de validare. | ||
Line 248: | Line 250: | ||
</hidden> | </hidden> | ||
==== 3.1. Regresia pentru o lista de atribute - 30p ==== | ==== 3.1. Regresia pentru o lista de atribute - 30p ==== | ||
+ | |||
+ | <note important> | ||
+ | In fisierul TestRegression exista 10 teste unitare. Fiecare valorează 3p din punctul aferent temi. Cu alte cuvinte cele 10 teste se scaleaza la 30p. | ||
+ | </note> | ||
Implementati functionalitatea metodei ''regression'' in interiorul clasei ''Regression''. Aceasta metoda trebuie sa execute urmatorii pasi, presupunand ca lucram cu ''n'' atribute selectate pentru a realiza regresia liniara. Matricea de intrare ''X'' va contine ''n + 1'' coloane: ''n'' coloane pentru atributele selectate si o coloana suplimentara care contine constanta ''1'' pentru a gestiona termenul liber al regresiei. | Implementati functionalitatea metodei ''regression'' in interiorul clasei ''Regression''. Aceasta metoda trebuie sa execute urmatorii pasi, presupunand ca lucram cu ''n'' atribute selectate pentru a realiza regresia liniara. Matricea de intrare ''X'' va contine ''n + 1'' coloane: ''n'' coloane pentru atributele selectate si o coloana suplimentara care contine constanta ''1'' pentru a gestiona termenul liber al regresiei. | ||
Line 306: | Line 312: | ||
===== Testare ====== | ===== Testare ====== | ||
- | In cadrul acestei teme, testarea se va face folosind ''Scalacheck'', o biblioteca de property-based testing. | + | In cadrul acestei teme, testarea se va face folosind ''Scalacheck'', o biblioteca de property-based testing si ''munit'', o biblioteca de teste unitare. Vom verifica implementarile de Dataset si Matrix folosind Scalacheck, iar Regression va fi testat cu munit. |
+ | |||
+ | [[https://github.com/scalameta/munit | Munit]] este o biblioteca de testare unitara pentru Scala.Testele unitare sunt o metoda de testare a unitatilor individuale de cod, cum ar fi functii, metode sau clase, in izolare de alte parti ale aplicatiei. Scopul principal al testelor unitare este de a verifica daca unitatile individuale de cod functioneaza conform asteptarilor specificate. Aceste teste sunt scrise de catre dezvoltatori pentru a valida comportamentul corect al codului lor si pentru a identifica eventualele erori sau bug-uri in mod eficient. Testele unitare preiau un input predefinit si verifica daca rezultatul functiilor implementate este acelasi cu cel asteptat. | ||
[[https://scalacheck.org. | Scalacheck]] este o biblioteca pentru Scala care permite testarea automata a codului. | [[https://scalacheck.org. | Scalacheck]] este o biblioteca pentru Scala care permite testarea automata a codului. | ||
Line 323: | Line 331: | ||
In IntelliJ, in fisierul build.sbt se afla referinta: | In IntelliJ, in fisierul build.sbt se afla referinta: | ||
- | <code> libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.14.1" % "test" </code> | + | <code> |
- | Aceasta este suficienta pentru a va lasa sa rulati fiserele de testare din IDE. | + | libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.14.1" % "test" |
+ | libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test | ||
+ | </code> | ||
+ | Aceasta este suficienta pentru a va lasa sa rulati fiserele de testare din IDE. | ||
+ | Daca folosiți terminalul: | ||
+ | * PropertiesDatabase si PropertiesMatrix se rulează in mod obisnuit, având o metoda main. | ||
+ | * Pentru a rula TestRegression, folositi comanda următoare in radacina scheletului: | ||
+ | <code>sbt test</code> | ||
Sunteti liberi (si incurajati) sa adaugati si alte teste daca vi se par utile. | Sunteti liberi (si incurajati) sa adaugati si alte teste daca vi se par utile. | ||
- | |||
- | <note important>Testele pentru regresie (secțiunea 3) vor fi postate pana luni, 25 martie 2024.</note> | ||
<note> Checkerul nu acorda punctajul pentru task-ul 3.2. Acesta va fi acordat manual pe baza corectitudinii scriptului de plot. </note> | <note> Checkerul nu acorda punctajul pentru task-ul 3.2. Acesta va fi acordat manual pe baza corectitudinii scriptului de plot. </note> |