#!/usr/bin/env python # coding: utf-8 # Sveučilište u Zagrebu
# Fakultet elektrotehnike i računarstva # # ## Strojno učenje 2016./2017. # # http://www.fer.unizg.hr/predmet/su # ### Laboratorijska vježba 0: Uvod u Python # # (c) 2015-2016 Domagoj Alagić # # Verzija: 0.1
# Zadnji put ažurirano: 7. listopada 2016. # In[3]: import numpy as np import scipy as sp from scipy import stats import matplotlib.pyplot as plt from sklearn import datasets get_ipython().run_line_magic('pylab', 'inline') # ## 1. # __(a)__ Kreirajte dvije liste: $a = [2, 4, 5, 6, 8, 13]$ i $b = [1, 3, 10, 13, 15]$. # In[418]: a = [2, 4, 5, 6, 8, 13] b = [1, 3, 10, 13, 15] print a, b # __(b)__ Napišite kôd koji konkatenira liste $a$ i $b$ u listu $c$: # In[419]: c = a + b print c # __(c)__ Sortirajte listu $c$: # In[420]: c = sorted(c) print c # __(d)__ Izbacite duplikate iz liste c: # In[421]: c = list(set(c)) print c # __(e)__ Dohvatite i ispišite (pazite na indeksiranje od 0): # * treći element, # * zadnja dva elementa, # * sve elemente između trećeg i šestog (uključujući treći element, isključujući šesti). # In[455]: print c[2] print c[-2:] print c[2:5] # __(f)__ Generirajte interval brojeva `ran` s elementima iz $[2, 20]$. # In[423]: ran = range(2, 21) print ran # __(g)__ Ispišite sve generirane brojeve iz intervala skupa s njihovim indeksima u listi: # In[424]: for ind, val in enumerate(ran): print ind, val # __(h)__ Korištenjem sažetog zapisa liste (engl. _list comprehension_) transformirajte listu `ran` tako da sve elemente zamijenite njihovim prirodnim logaritmom. # In[425]: ran_ln = [np.log(elem) for elem in ran] print ran_ln # ## 2. # __(a)__ Napišite funkciju `make_3sg_form(word)` koja vraća glagol u trećem licu jednine za dani glagol u infinitivu, npr. _try_ -> _tries_. Slijedite sljedeća pravila: # * Ako glagol završava na _y_, odbaci _y_ i dodaj _ies_. # * Ako glagol završava na _o_, _ch_, _s_, _sh_, _x_ ili _z_, dodaj _es_. # * Inače samo dodaj _s_. # # NB: Znakovni niz je zapravo polje znakova tako da vrijede "trikovi" za indeksiranje polja. # # __(b)__ Isprobajte implementiranu funkciju za _fix_, _brush_, _cry_, _play_ i _echo_. Primjetite da je ovo složen problem i da tri jednostavna pravila neće uspjeti pokriti sve slučajeve. # In[426]: def make_3sg_form(word): ret_word = word if ret_word.endswith("y"): ret_word = ret_word[0:-1] + "ies" elif ret_word.endswith("o") or ret_word.endswith("x") or ret_word.endswith("s") or \ ret_word.endswith("ch") or ret_word.endswith("sh"): ret_word += "es" else: ret_word += "s" return ret_word print "fix", "->", make_3sg_form("fix") print "brush", "->", make_3sg_form("brush") print "jump", "->", make_3sg_form("jump") print "cry", "->", make_3sg_form("cry") print "echo", "->", make_3sg_form("echo") # ## 3. # Napišite funkciju `filterShortWords (word_list, min_length)` koja prima listu riječi i minimalnu dopuštenu duljinu riječi te vraća __novu__ listu riječi koja sadrži samo one riječi čija je duljina veća od minimalne dopuštene. Obavezno provjerite da je dana duljina riječi pozitivan broj veći od 1. Ako nije, bacite iznimku. U slučaju da korisnik nije zadao duljinu, funkcija radi jednako kao da je korisnik zadao duljinu od dva znaka (koristite podrazumijevane argumente, engl. _default arguments_). # # Zadatak riješite na dva načina: # # * __(a)__ korištenjem `for` petlji, # * __(b)__ korištenjem sažetog zapisa liste, # * __(c)__ korištenjem metode `filter` u kombinaciji s lambda-izrazom. # # __(d)__ Pokažite na primjeru da su izlazi implementiranih funkcija jednaki. # # NB: Podrazumijevani elementi (ili grupa istih) uvijek dolaze na kraju liste argumenata u definiciji funkcije. # In[427]: def filterShortWordsLoop(word_list, min_length=2): if min_length < 1: raise ValueError("Length must be >= 1.") filtered_list = [] for word in word_list: if len(word) >= min_length: filtered_list.append(word) return filtered_list # In[428]: def filterShortWordsLambda(word_list, min_length=2): if min_length < 1: raise ValueError("Length must be >= 1.") return filter(lambda elem: len(elem) >= min_length, word_list) # In[429]: def filterShortWordsCompr(word_list, min_length=2): if min_length < 1: raise ValueError("Length must be >= 1.") return [elem for elem in word_list if len(elem) >= min_length] # In[430]: word_list = ["Ja", "sam", "mali", "Mate", "od", "mame", "i", "tate"] print filterShortWordsLoop(word_list, min_length=3) print filterShortWordsLambda(word_list, min_length=3) print filterShortWordsCompr(word_list, min_length=3) # ## 4. # Dana vam je mapa koja za ključeve sadrži nazive programskih jezika, a za vrijednosti liste programskih paradigmi koje određeni jezik pokriva. # In[431]: langs_paradigms = { "Java" : ["object-oriented", "imperative"], "Haskell" : ["functional"], "Lisp" : ["functional", "procedural"] } # Napišite razred `ProgLanguageRepository` uzimajući u obzir sljedeće stvari: # * Konstruktor ovog razreda prima početnu mapu koja sadrži programske jezike i njihove paradigme. # * Dana mapa sprema se kao član klase imena `data`. # * Razred sadrži metodu `count` koja vraća broj programskih jezika dostupnih u repozitoriju. # * Razred sadrži metodu `get_langs_paradigms (lang)` koja za dano ime programskog jezika vraća listu njegovih paradigmi ili vraća `None` ako taj jezik ne postoji u repozitoriju. # * Razred sadrži metodu `add_lang_paradigm (lang, paradigm)` koja danom programskom jeziku dodaje paradigmu (ako je već nema). # * Razred sadrži metodu `remove_lang_paradigm (lang, paradigm)` koja danom programskom jeziku miče danu paradigmu (ako je ima). # * Razred ima nadjačanu metodu za znakovnu reprezentaciju koja samo ispisuje znakovnu reprezentaciju člana `data`. # # Pokažite na par primjera da vaša implementacija radi. # In[432]: class ProgLanguageRepository: # Konstruktor def __init__(self, data): self.data = data def count(self): return len(self.data.keys()) # len(self.data) def get_langs_paradigms(self, lang): if lang in self.data: return self.data[lang] else: return None def add_lang_paradigm(self, lang, paradigm): if paradigm not in self.data[lang]: self.data[lang].append(paradigm) def remove_lang_paradigm(self, lang, paradigm): if paradigm in self.data[lang]: self.data[lang].remove(paradigm) def __str__(self): return self.data.__str__() # In[433]: prog_repo = ProgLanguageRepository(langs_paradigms) print prog_repo # In[434]: print prog_repo.get_langs_paradigms("Lisp") print prog_repo.get_langs_paradigms("d") # In[435]: prog_repo.add_lang_paradigm("Haskell", "object-oriented") prog_repo.add_lang_paradigm("Haskell", "object-oriented") print prog_repo # In[436]: prog_repo.remove_lang_paradigm("Haskell", "object-oriented") prog_repo.remove_lang_paradigm("Haskell", "object-oriented") print prog_repo # ## 5. # __(a)__ Napišite kôd koji stvara sljedeća tri vektor-stupca, jedan vektor-redak i kvadratnu matricu ranga 2 (koristite `numpy` za cijeli zadatak): # # $ x_{1} = \begin{pmatrix} # 1\\ # 2\\ # \end{pmatrix}$, # $ x_{2} = \begin{pmatrix} # 3\\ # 5\\ # \end{pmatrix}$, # $ x_{3} = \begin{pmatrix} # -3\\ # 4\\ # \end{pmatrix}$, # $ x_{4} = \begin{pmatrix} # 4\\ # 0\\ # \end{pmatrix}^T$, # $ A = \begin{pmatrix} # 5 & 3 \\ # 10 & 6 \\ # \end{pmatrix} # $ # # __(b)__ Zatim napišite naredbe koje stvaraju dvije nove matrice: matricu $C$ dimenzija $2\times3$ koja se dobije tako da se vektor-stupci poredaju horizontalno jedan kraj drugog te matricu $D$ dimenzija $3\times2$ koja se dobije tako da se matrica $A$ postavi ispod danog vektor-retka. # In[437]: # stvaranje svih danih vektora i matrica x_1 = np.array([[1], [2]]) x_2 = np.array([[3], [5]]) x_3 = np.array([[-3], [4]]) x_4 = np.array([4, 0]) A = np.array([[5, 3], [10, 6]]) print x_1 print x_2 print x_3 print x_4 print A # In[438]: # stvaranje matrice C C = np.hstack([x_1, x_2, x_3]) print C # In[439]: # stvaranje matrice D D = np.vstack([x_4, A]) print D # __(c)__ Izračunajte umnožak matrica $C$ i $D$ te ga pohranite u matricu $U$. # In[440]: U = C.dot(D) print U # __(d)__ Nadalje, napišite kôd koji izračunava inverz matrice $U$ (spremiti u matricu $I$) kojeg zatim transponira (i sprema u matricu $R$). # In[441]: I = np.linalg.inv(U) print I R = np.transpose(I) print R # __(e)__ Izračunajte sumu svih elemenata u matrici $D$ (spremite u varijablu `D_total`), ali i sume po zasebnim dimenzijama (`D_x`, `D_y`). # In[442]: D_total = np.sum(D[:]) print D_total D_x = np.sum(D, axis=0) # po x osi print D_x D_y = np.sum(D, axis=1) # po y osi print D_y # __(f)__ Ispišite determinantu matrice $R$. # In[443]: print np.linalg.det(R) # __(g)__ Isprobajte vrijedi li $R\cdot R^{-1} = I$. # In[444]: RI = np.dot(R, np.linalg.inv(R)) print RI # __(h)__ Stvorite vektor-stupac $n$ dimenzija $4\times 1$ čiji su svi elementi 0 (bez ručnog pisanja svih elemenata). # In[445]: n = np.zeros([4, 1]) print n # ## 6. # __(a)__ Napišite kôd koji iscrtava sljedeće funkcije: # # $f_{1}(x) = \sqrt{(1-(|x|-1)^2)}$ i $f_{2}(x) = -3 \cdot \sqrt{(1-\sqrt{\frac{|x|}{2}})}$ # # pritom definirajući domenu funkcija kao $x \in [-2, 2]$ (u 1000 točaka). Graf funkcije $f_{1}(x)$ prikažite plavom bojom, a graf funkcije $f_{2}(x)$ crvenom. Iscrtajte oba grafa na istoj slici tako da su vidljive točke iz intervala $x \in [-3, 3]$ i $y \in [-3, 1.5]$. # # __(b)__ Ostavite oznake osi jednostavno kao $x$ i $y$. Iscrtajte legendu u donjem desnom kutu tako da je naziv funkcije $f_{1}(x)$ _bolja polovica_, a naziv funkcije $f_{2}(x)$ _dobra polovica_. # In[446]: # funkcije def f_1(x): return np.sqrt((1 - (np.abs(x) - 1)**2)) def f_2(x): return -3 * np.sqrt(1 - np.sqrt((np.abs(x)/2))) # domena u 1000 točaka x = np.linspace(-2, 2, 1000) # iscrtavanje prvog grafa plavom linijom plt.plot(x, f_1(x), 'b-', label="bolja polovica") # iscrtavanje drugog grafa crvenom linijom plt.plot(x, f_2(x), 'r-', label="dobra polovica") # postavljanje ograničenja prikaza plt.xlim([-3, 3]) plt.ylim([-3, 1.5]) # postavljanje oznaka osi plt.xlabel("x") plt.ylabel("y") # iscrtavanje legende plt.legend(loc="lower right") plt.show() # ## 7. # __(a)__ Učitajte skup podataka _Iris_. Ovaj skup podataka sadrži 150 instanci, 50 za svaku od tri klase (_Iris setosa_, _Iris virginica_ i _Iris versicolor_). Svaka instanca, to jest vektor, sadrži četiri značajke: širinu i dužinu latice te širinu i dužinu čašićnog listića. U polju _iris.data_ nalaze se instance, dok se u _iris.target_ nalaze oznake instanci (njihove stvarne klase). Ispišite dimenzije polja instanci te polja njihovih stvarnih oznaka. # In[447]: # učitavanje dataseta iris = datasets.load_iris() print iris.data.shape print iris.target.shape # __(b)__ Budući da ne možemo vizualizirati 4-dimenzijske podatke, iz svake instance izdvojite samo prve dvije značajke. Koristite indeksiranje poljem brojeva. Ispišite dimenzije dobivenog polja instanci. # In[448]: data_2dim = iris.data[:, 0:2] print data_2dim.shape # __(c)__ Logičkim indeksiranjem razdvojite primjere za svaku od tri klase. Ispišite dimenzije dobivenih polja. # In[449]: class_1_samples = iris.data[iris.target == 0] class_2_samples = iris.data[iris.target == 1] class_3_samples = iris.data[iris.target == 2] print class_1_samples.shape print class_2_samples.shape print class_3_samples.shape # __(d)__ Napišite kôd koji iscrtava četiri zasebna grafa (četiri podgrafa u 2x2 mreži), pri čemu tri grafa prikazuju instance određene klase (točke u 2-dimenzijskom prostoru), a četvrti ih prikazuje sve (u različitim bojama). Osigurajte da svi grafovi prikazuju isto područje grafa (npr. $x \in [4,9]$ i $y \in [1.5, 5]$). # # Proučite kako se postavlja veličina glavnog okvira (u koji se smještaju podgrafovi) te ju postavite na 10x8. # In[450]: plt.figure(figsize=(10,8)) # class 1 plt.subplot(221) plt.scatter(class_1_samples[:,0], class_1_samples[:,1], c='r') plt.xlim([4, 9]) plt.ylim([1.5, 5]) # class 2 plt.subplot(222) plt.scatter(class_2_samples[:,0], class_2_samples[:,1], c='g') plt.xlim([4, 9]) plt.ylim([1.5, 5]) # class 3 plt.subplot(223) plt.scatter(class_3_samples[:,0], class_3_samples[:,1], c='b') plt.xlim([4, 9]) plt.ylim([1.5, 5]) # all three classes plt.subplot(224) plt.scatter(data_2dim[:,0], data_2dim[:,1], c=iris.target, cmap=plt.cm.Set1) plt.xlim([4, 9]) plt.ylim([1.5, 5]) plt.show() # ## 8. # __(a)__ Napišite kôd koji u petlji iscrtava grafove normalnih distribucija definiranih s parametarima $\mu$ i $\sigma$: # # * $\mu = 3$ # * $\sigma \in [1, 5]$ (korak 1) # # Dakle, generirat ćete pet grafova normalnih distribucija: $\mathcal{N}_{1}(\mu = 3, \sigma = 1)$, $\mathcal{N}_{2}(\mu = 3, \sigma = 2)$, ... , $\mathcal{N}_{1}(\mu = 3, \sigma = 5)$. # # Grafove iscrtajte na istoj slici tako da su vidljive točke iz intervala $x \in [-15, 15]$ i $y \in [0, 0.5]$. Za svaki graf upotrijebite drugu boju. Za domenu koristite $[-50, 50]$ (uzorkujte 1000 točaka). Također napravite legendu u gornjem lijevom kutu koji će sve grafove nazvati onako kako su i u zadatku # definirani ($\LaTeX$ kôd radi unutar znakovnih nizova koji definiraju oznaku unutar legende), npr. $\mathcal{N}_{1}(\mu = 3, \sigma = 5)$. # # In[451]: xs = np.linspace(-50, 50, 1000) sigmas = range(1, 6) for sigma, color in zip(sigmas, "rgbmy"): n_dist = stats.norm.pdf(xs, loc=3, scale=sigma) label = "$\mathcal{N}_{1}(\mu = 3, \sigma = " + str(sigma) + ")$" plt.plot(xs, n_dist, color, label=label) plt.xlim([-15, 15]) plt.ylim([0, 0.5]) plt.legend(loc="upper left") plt.show() # Sada pretpostavite da imate zadanu distribuciju ocjena na nekom kolegiju koja se pokorava normalnoj distribuciji $\mathcal{N}_{G}(\mu = 62, \sigma = 13)$. Najprije je iscrtajte (nebitno kako), ali osigurajte da je domena $[0, 100]$ (raspon mogućih bodova na kolegiju) također uzorkovana u 1000 točaka. # In[452]: xsg = np.linspace(0, 100, 1000) n_g = stats.norm.pdf(xsg, loc=62, scale=13) plt.plot(xsg, n_g, 'b-') plt.show() # Međutim, vi polažete kolegij naknadno na roku, a profesoru se zaista ne da ispravljati vaš ispit. Kako bi tome doskočio, profesor često koristi tradicionalnu metodu stubišta (https://www.linkedin.com/pulse/20140414044726-2259773-a-guide-to-grading-exams) koju možemo aproksimirati nasumičnim odabirom broja iz distribucije bodova na ispitu. Napišite kôd koji iz distribucije bodova $\mathcal{N}_{G}$ dohvaća slučajnu vrijednost koja predstavlja vaš broj bodova (zaokružite bodove na cijeli broj). # In[453]: points = int(stats.norm.rvs(loc=62, scale=13)) print "Na ispitu sam osvojio", points, "bodova." # ## 10. # Iscrtajte konture 2-dimenzijske Gausove distribucije $\mathcal{N} (\vec{\mu}, \Sigma)$ sa sljedećim parametrima: # # * $\vec{\mu} = [1, 1]$ # * $\Sigma = \begin{pmatrix} # 1 & 1 \\ # 0.5 & 3 \\ # \end{pmatrix}$ # # Za domenu uzmite $x_{1} \in [-1, 2]$ i $y_{2} \in [-2, 2]$. # In[474]: mnormal = stats.multivariate_normal([1, 1], [[1, 1], [0.5, 3]]) x_1 = np.linspace(-1, 2) x_2 = np.linspace(-2, 2) X1, X2 = np.meshgrid(x_1, x_2) X1X2 = np.dstack((X1, X2)) plt.contourf(X1, X2, mnormal.pdf(X1X2)) plt.show()