Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
pp:2024:tema1 [2024/03/22 15:25]
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: ​10 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 31: Line 35:
   * $math[x_0] si $math[x_1] reprezinta suprafata totala, respectiv anul construcției   * $math[x_0] si $math[x_1] reprezinta suprafata totala, respectiv anul construcției
   * $math[a], $math[b] si $math[c] reprezinta parametrii modelului, pe care, folosind regresia, ii calculam astfel incat sa minimizeze suma tuturor erorilor predictiilor.   * $math[a], $math[b] si $math[c] reprezinta parametrii modelului, pe care, folosind regresia, ii calculam astfel incat sa minimizeze suma tuturor erorilor predictiilor.
-Puteti vizualiza reprezentarea grafica a acestei situatii cu aces fisier:​{{:​pp:​2024:​3d_graph.zip|}}.+Puteti vizualiza reprezentarea grafica a acestei situatii cu acest fisier:​{{:​pp:​2024:​3d_graph.zip|}}.
  
 In general, regresia poate fi implementata cu un singur atribut, cu doua sau si cu mai multe, in functie de informatiile disponibile despre procesul ce se doreste a fi prezis. Dincolo de aceste informatii, alte cunostinte despre regresie nu sunt necesare pentru implementarea acestei teme. In general, regresia poate fi implementata cu un singur atribut, cu doua sau si cu mai multe, in functie de informatiile disponibile despre procesul ce se doreste a fi prezis. Dincolo de aceste informatii, alte cunostinte despre regresie nu sunt necesare pentru implementarea acestei teme.
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 evaluareiar 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 229: Line 231:
 O valoare prea mare face regresia mai susceptiblila la a nu converge (pasii sunt prea mari, asa ca o sa se oscileze de o parte si de alta a minimului fara a se apropia de acesta.) O valoare prea mare face regresia mai susceptiblila la a nu converge (pasii sunt prea mari, asa ca o sa se oscileze de o parte si de alta a minimului fara a se apropia de acesta.)
  
-TODOAdd example graphs for alpha (5 casestoo low(gets stuck), too low(converges slow +Urmatoarele grafice ilustreaza aceste posibile situatii (cu albastru este figurat un exemplu de functie de loss pentru un singur parametru ce poate fi modificat, cu rosu aveti primele 50 de valori obtinute de gradient descent) 
-ly), just right, too high (bounces around near minimum), too high (explodes outwards)).+ 
 +{{:pp:​2024:​tema1:​0.03.jpg?​400|}} 
 +Exemplu ​alpha prea micconverge foarte incet 
 + 
 +{{:​pp:​2024:​tema1:​0.05.jpg?​400|}} 
 +Exemplu alpha prea mic: ramane blocat in minim local 
 + 
 +{{:​pp:​2024:​tema1:​0.6.jpg?​400|}} 
 +Exemplu alpha bun: converge catre minim global. 
 + 
 +{{:​pp:​2024:​tema1:​0.7.jpg?​400|}} 
 +Exemplu alpha prea mare: oscileaza in jurul minimului. 
 + 
 +{{:​pp:​2024:​tema1:​1.2.jpg?​400|}} 
 +Exemplu alpha prea mare: valorile ies din interval foarte repede ​("​explodeaza"​)
  
 </​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 261: Line 281:
   attribute_columns:​ List[String],​   attribute_columns:​ List[String],​
   value_column:​ String,   value_column:​ String,
-  ​+  ​test_percentage: Double,
-est_percentage: Double,+
   alpha: Double,   alpha: Double,
   gradient_descent_steps:​ Int   gradient_descent_steps:​ Int
Line 293: 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.
  
-Scalacheck este o biblioteca pentru Scala care permite testarea automata a codului. ​+[[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. ​
 Scalacheck genereaza o suita de date de testare random si verifica daca proprietatile specificate de utilizator sunt adevarate pentru acele date. Scalacheck genereaza o suita de date de testare random si verifica daca proprietatile specificate de utilizator sunt adevarate pentru acele date.
 Practic, aceasta este o metoda de verificare a corectitudinii codului semi-formala,​ in sensul ca incearca inputuri generice de orice fel,  Practic, aceasta este o metoda de verificare a corectitudinii codului semi-formala,​ in sensul ca incearca inputuri generice de orice fel, 
Line 309: Line 330:
 generat pentru a gasi un input mai mic care esueaza testul, acesta fiind mai usor de inteles si de debug. generat pentru a gasi un input mai mic care esueaza testul, acesta fiind mai usor de inteles si de debug.
  
-Daca aveti IntelliJ, in fisierul build.sbt se afla referinta:​ +In IntelliJ, in fisierul build.sbt se afla referinta:​ 
-    <​code>​ libraryDependencies += "​org.scalacheck"​ %% "​scalacheck"​ % "1.15.4" % "​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" ​ 
-Pentru a rula Scalacheck in terminal, trebuie sa adaugam dependinta in build.sbt si sa rulam testele folosind : +libraryDependencies += "​org.scalameta"​ %% "​munit"​ % "​0.7.29"​ % Test 
-    <​code>​ sbt test </​code>​ +</​code> ​    
-     +Aceasta este suficienta pentru a va lasa sa rulati fiserele de testare din IDE.
-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 luni25 martie 2024.</note>+Daca folosiți terminalul:​ 
 +  * PropertiesDatabase si PropertiesMatrix se rulează in mod obisnuitavâ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.
  
 <​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>​