Sveučilište u Zagrebu
Fakultet elektrotehnike i računarstva

Strojno učenje 2019/2020

http://www.fer.unizg.hr/predmet/su


Laboratorijska vježba 1: Regresija

Verzija: 1.2
Zadnji put ažurirano: 27. rujna 2019.

(c) 2015-2019 Jan Šnajder, Domagoj Alagić

Objavljeno: 30. rujna 2019.
Rok za predaju: 21. listopada 2019. u 07:00h


Upute

Prva laboratorijska vježba sastoji se od deset zadataka. U nastavku slijedite upute navedene u ćelijama s tekstom. Rješavanje vježbe svodi se na dopunjavanje ove bilježnice: umetanja ćelije ili više njih ispod teksta zadatka, pisanja odgovarajućeg kôda te evaluiranja ćelija.

Osigurajte da u potpunosti razumijete kôd koji ste napisali. Kod predaje vježbe, morate biti u stanju na zahtjev asistenta (ili demonstratora) preinačiti i ponovno evaluirati Vaš kôd. Nadalje, morate razumjeti teorijske osnove onoga što radite, u okvirima onoga što smo obradili na predavanju. Ispod nekih zadataka možete naći i pitanja koja služe kao smjernice za bolje razumijevanje gradiva (nemojte pisati odgovore na pitanja u bilježnicu). Stoga se nemojte ograničiti samo na to da riješite zadatak, nego slobodno eksperimentirajte. To upravo i jest svrha ovih vježbi.

Vježbe trebate raditi samostalno. Možete se konzultirati s drugima o načelnom načinu rješavanja, ali u konačnici morate sami odraditi vježbu. U protivnome vježba nema smisla.


In [1]:
# Učitaj osnovne biblioteke...
import numpy as np
import sklearn
import matplotlib.pyplot as plt
%pylab inline


Populating the interactive namespace from numpy and matplotlib

Zadatci

1. Jednostavna regresija

Zadan je skup primjera $\mathcal{D}=\{(x^{(i)},y^{(i)})\}_{i=1}^4 = \{(0,4),(1,1),(2,2),(4,5)\}$. Primjere predstavite matrixom $\mathbf{X}$ dimenzija $N\times n$ (u ovom slučaju $4\times 1$) i vektorom oznaka $\textbf{y}$, dimenzija $N\times 1$ (u ovom slučaju $4\times 1$), na sljedeći način:


In [2]:
X = np.array([[0],[1],[2],[4]])
y = np.array([4,1,2,5])

X1 = X
y1 = y

(a)

Proučite funkciju PolynomialFeatures iz biblioteke sklearn i upotrijebite je za generiranje matrice dizajna $\mathbf{\Phi}$ koja ne koristi preslikavanje u prostor više dimenzije (samo će svakom primjeru biti dodane dummy jedinice; $m=n+1$).


In [3]:
from sklearn.preprocessing import PolynomialFeatures

In [4]:
poly = PolynomialFeatures(1)
phi = poly.fit_transform(X)
print(phi)

# Vaš kôd ovdje


[[1. 0.]
 [1. 1.]
 [1. 2.]
 [1. 4.]]

In [ ]:

(b)

Upoznajte se s modulom linalg. Izračunajte težine $\mathbf{w}$ modela linearne regresije kao $\mathbf{w}=(\mathbf{\Phi}^\intercal\mathbf{\Phi})^{-1}\mathbf{\Phi}^\intercal\mathbf{y}$. Zatim se uvjerite da isti rezultat možete dobiti izračunom pseudoinverza $\mathbf{\Phi}^+$ matrice dizajna, tj. $\mathbf{w}=\mathbf{\Phi}^+\mathbf{y}$, korištenjem funkcije pinv.


In [5]:
from numpy import linalg

In [6]:
pinverse1 = pinv(phi)
pinverse2 = matmul(inv(matmul(transpose(phi), phi)), transpose(phi))

#print(pinverse1)
#print(pinverse2)

w = matmul(pinverse2, y)
print(w)
                   
# Vaš kôd ovdje


[2.2        0.45714286]

Radi jasnoće, u nastavku je vektor $\mathbf{x}$ s dodanom dummy jedinicom $x_0=1$ označen kao $\tilde{\mathbf{x}}$.

(c)

Prikažite primjere iz $\mathcal{D}$ i funkciju $h(\tilde{\mathbf{x}})=\mathbf{w}^\intercal\tilde{\mathbf{x}}$. Izračunajte pogrešku učenja prema izrazu $E(h|\mathcal{D})=\frac{1}{2}\sum_{i=1}^N(\tilde{\mathbf{y}}^{(i)} - h(\tilde{\mathbf{x}}))^2$. Možete koristiti funkciju srednje kvadratne pogreške mean_squared_error iz modula sklearn.metrics.

Q: Gore definirana funkcija pogreške $E(h|\mathcal{D})$ i funkcija srednje kvadratne pogreške nisu posve identične. U čemu je razlika? Koja je "realnija"?


In [7]:
import sklearn.metrics as mt

wt = w #(np.array([w]))

print(wt)
print(phi)

hx = np.dot(phi, w)

E = mt.mean_squared_error(hx, y)
print(E)

# Vaš kôd ovdje


[2.2        0.45714286]
[[1. 0.]
 [1. 1.]
 [1. 2.]
 [1. 4.]]
2.042857142857143

(d)

Uvjerite se da za primjere iz $\mathcal{D}$ težine $\mathbf{w}$ ne možemo naći rješavanjem sustava $\mathbf{w}=\mathbf{\Phi}^{-1}\mathbf{y}$, već da nam doista treba pseudoinverz.

Q: Zašto je to slučaj? Bi li se problem mogao riješiti preslikavanjem primjera u višu dimenziju? Ako da, bi li to uvijek funkcioniralo, neovisno o skupu primjera $\mathcal{D}$? Pokažite na primjeru.


In [8]:
# Vaš kôd ovdje

w = matmul(inv(phi), y)
print(w)


---------------------------------------------------------------------------
LinAlgError                               Traceback (most recent call last)
<ipython-input-8-23444b0bcc75> in <module>
      1 # Vaš kôd ovdje
      2 
----> 3 w = matmul(inv(phi), y)
      4 print(w)

<__array_function__ internals> in inv(*args, **kwargs)

c:\users\domin\appdata\local\programs\python\python36\lib\site-packages\numpy\linalg\linalg.py in inv(a)
    544     a, wrap = _makearray(a)
    545     _assertRankAtLeast2(a)
--> 546     _assertNdSquareness(a)
    547     t, result_t = _commonType(a)
    548 

c:\users\domin\appdata\local\programs\python\python36\lib\site-packages\numpy\linalg\linalg.py in _assertNdSquareness(*arrays)
    211         m, n = a.shape[-2:]
    212         if m != n:
--> 213             raise LinAlgError('Last 2 dimensions of the array must be square')
    214 
    215 def _assertFinite(*arrays):

LinAlgError: Last 2 dimensions of the array must be square

(e)

Proučite klasu LinearRegression iz modula sklearn.linear_model. Uvjerite se da su težine koje izračunava ta funkcija (dostupne pomoću atributa coef_ i intercept_) jednake onima koje ste izračunali gore. Izračunajte predikcije modela (metoda predict) i uvjerite se da je pogreška učenja identična onoj koju ste ranije izračunali.


In [9]:
from sklearn.linear_model import LinearRegression

In [10]:
# Vaš kôd ovdje
lr = LinearRegression().fit(X, y)
#print(lr.score(X, y))
#print(lr.coef_)
#print(lr.intercept_)
print([lr.intercept_, lr.coef_[0]])

print(wt)

pr = lr.predict(X)
E = mt.mean_squared_error(pr, y)
print(E)


[2.2, 0.45714285714285713]
[2.2        0.45714286]
2.042857142857143

2. Polinomijalna regresija i utjecaj šuma

(a)

Razmotrimo sada regresiju na većem broju primjera. Definirajte funkciju make_labels(X, f, noise=0) koja uzima matricu neoznačenih primjera $\mathbf{X}_{N\times n}$ te generira vektor njihovih oznaka $\mathbf{y}_{N\times 1}$. Oznake se generiraju kao $y^{(i)} = f(x^{(i)})+\mathcal{N}(0,\sigma^2)$, gdje je $f:\mathbb{R}^n\to\mathbb{R}$ stvarna funkcija koja je generirala podatke (koja nam je u stvarnosti nepoznata), a $\sigma$ je standardna devijacija Gaussovog šuma, definirana parametrom noise. Za generiranje šuma možete koristiti funkciju numpy.random.normal.

Generirajte skup za učenje od $N=50$ primjera uniformno distribuiranih u intervalu $[-5,5]$ pomoću funkcije $f(x) = 5 + x -2 x^2 -5 x^3$ uz šum $\sigma=200$:


In [11]:
from numpy.random import normal

def make_labels(X, f, noise=0) :
    # Vaš kôd ovdje
    N = numpy.random.normal
    fx = f(X)
    #nois = [N(0, noise) for _ in range(X.shape[0])]
    #print(nois)
    #y = f(X) + nois
    y = [ f(x) + N(0, noise) for x in X ]
    
    return y

In [12]:
def make_instances(x1, x2, N) :
    return np.array([np.array([x]) for x in np.linspace(x1,x2,N)])

Prikažite taj skup funkcijom scatter.


In [13]:
# Vaš kôd ovdje
N = 50
def f(x):
    return 5 + x - 2*x*x - 5*x*x*x
noise = 200

X2 = make_instances(-5, 5, N)
y2 = make_labels(X2, f, noise)

#print(X)
#print(y)

s = scatter(X2, y2)


(b)

Trenirajte model polinomijalne regresije stupnja $d=3$. Na istom grafikonu prikažite naučeni model $h(\mathbf{x})=\mathbf{w}^\intercal\tilde{\mathbf{x}}$ i primjere za učenje. Izračunajte pogrešku učenja modela.


In [14]:
# Vaš kôd ovdje
import sklearn.linear_model as lm

def polyX(d):

    p3 = PolynomialFeatures(d).fit_transform(X2)
    l2 = LinearRegression().fit(p3, y2)
    h2 = l2.predict(p3)

    E = mt.mean_squared_error(h2, y2)
    print('d: ' + str(d) + ' E: ' + str(E))
    #print(p3)
    plot(X2, h2, label = str(d))

scatter(X2, y2)
polyX(3)


d: 3 E: 45372.70706576215

3. Odabir modela

(a)

Na skupu podataka iz zadatka 2 trenirajte pet modela linearne regresije $\mathcal{H}_d$ različite složenosti, gdje je $d$ stupanj polinoma, $d\in\{1,3,5,10,20\}$. Prikažite na istome grafikonu skup za učenje i funkcije $h_d(\mathbf{x})$ za svih pet modela (preporučujemo koristiti plot unutar for petlje). Izračunajte pogrešku učenja svakog od modela.

Q: Koji model ima najmanju pogrešku učenja i zašto?


In [15]:
# Vaš kôd ovdje
figure(figsize=(15,10))
scatter(X2, y2)
polyX(1)
polyX(3)
polyX(5)
polyX(10)
polyX(20)

s = plt.legend(loc="center right")


d: 1 E: 65238.640429367864
d: 3 E: 45372.70706576215
d: 5 E: 42339.04347591081
d: 10 E: 39171.298402557346
d: 20 E: 35988.446443693305

(b)

Razdvojite skup primjera iz zadatka 2 pomoću funkcije model_selection.train_test_split na skup za učenja i skup za ispitivanje u omjeru 1:1. Prikažite na jednom grafikonu pogrešku učenja i ispitnu pogrešku za modele polinomijalne regresije $\mathcal{H}_d$, sa stupnjem polinoma $d$ u rasponu $d\in [1,2,\ldots,20]$. Budući da kvadratna pogreška brzo raste za veće stupnjeve polinoma, umjesto da iscrtate izravno iznose pogrešaka, iscrtajte njihove logaritme.

NB: Podjela na skupa za učenje i skup za ispitivanje mora za svih pet modela biti identična.

Q: Je li rezultat u skladu s očekivanjima? Koji biste model odabrali i zašto?

Q: Pokrenite iscrtavanje više puta. U čemu je problem? Bi li problem bio jednako izražen kad bismo imali više primjera? Zašto?


In [16]:
from sklearn.model_selection import train_test_split

In [17]:
# Vaš kôd ovdje

xTr, xTest, yTr, yTest = train_test_split(X2, y2, test_size=0.5)

testError = []

for d in range(1,33):

    polyXTrain = PolynomialFeatures(d).fit_transform(xTr)    
    polyXTest = PolynomialFeatures(d).fit_transform(xTest)

    l2 = LinearRegression().fit(polyXTrain, yTr)
    h2 = l2.predict(polyXTest)

    E = mt.mean_squared_error(h2, yTest)
    print('d: ' + str(d) + ' E: ' + str(E))
    testError.append(E)
    #print(p3)
    #plot(polyXTest, h2, label = str(d))

plot(numpy.log(numpy.array(testError)))


d: 1 E: 67419.3351219913
d: 2 E: 80500.71984758964
d: 3 E: 65443.17220069123
d: 4 E: 62548.71558712938
d: 5 E: 64439.31928603909
d: 6 E: 64430.15726494553
d: 7 E: 62480.661259611436
d: 8 E: 63828.63503962773
d: 9 E: 67409.342885196
d: 10 E: 80336.64543081427
d: 11 E: 75534.85892796707
d: 12 E: 86610.73764141298
d: 13 E: 93437.45880779717
d: 14 E: 101418.6812579038
d: 15 E: 101826.78901991164
d: 16 E: 94997.98899230913
d: 17 E: 98078.16510154339
d: 18 E: 115699.4679543442
d: 19 E: 111070.62315845155
d: 20 E: 2498634.41149886
d: 21 E: 164456.59200109806
d: 22 E: 1692999.743605582
d: 23 E: 346851.2546505648
d: 24 E: 88675726.18492387
d: 25 E: 549323.2722732476
d: 26 E: 26115274.090464216
d: 27 E: 129895916.00585802
d: 28 E: 14872281.047185427
d: 29 E: 3827893.378930051
d: 30 E: 84013425.71068993
d: 31 E: 25745228.949655004
d: 32 E: 452975428.36179245
Out[17]:
[<matplotlib.lines.Line2D at 0x17f8a1b9898>]

(c)

Točnost modela ovisi o (1) njegovoj složenosti (stupanj $d$ polinoma), (2) broju primjera $N$, i (3) količini šuma. Kako biste to analizirali, nacrtajte grafikone pogrešaka kao u 3b, ali za sve kombinacija broja primjera $N\in\{100,200,1000\}$ i količine šuma $\sigma\in\{100,200,500\}$ (ukupno 9 grafikona). Upotrijebite funkciju subplots kako biste pregledno posložili grafikone u tablicu $3\times 3$. Podatci se generiraju na isti način kao u zadatku 2.

NB: Pobrinite se da svi grafikoni budu generirani nad usporedivim skupovima podataka, na sljedeći način. Generirajte najprije svih 1000 primjera, podijelite ih na skupove za učenje i skupove za ispitivanje (dva skupa od po 500 primjera). Zatim i od skupa za učenje i od skupa za ispitivanje načinite tri različite verzije, svaka s drugačijom količinom šuma (ukupno 2x3=6 verzija podataka). Kako bi simulirali veličinu skupa podataka, od tih dobivenih 6 skupova podataka uzorkujte trećinu, dvije trećine i sve podatke. Time ste dobili 18 skupova podataka -- skup za učenje i za testiranje za svaki od devet grafova.


In [18]:
# Vaš kôd ovdje

# Vaš kôd ovdje
figure(figsize=(15,15))

N = 1000
def f(x):
    return 5 + x - 2*x*x - 5*x*x*x

X3 = make_instances(-5, 5, N)

xAllTrain, xAllTest = train_test_split(X3, test_size=0.5)
i = 0
j = 0

for N in [100, 200, 1000]:
    for noise in [100, 200, 500]:
        j += 1
        
        xTrain = xAllTrain[:N]
        xTest = xAllTest[:N]
        yTrain = make_labels(xTrain, f, noise)
        yTest = make_labels(xTest, f, noise)

        trainError = []
        testError = []

        for d in range(1,21):

            polyXTrain = PolynomialFeatures(d).fit_transform(xTrain)    
            polyXTest = PolynomialFeatures(d).fit_transform(xTest)

            l2 = LinearRegression().fit(polyXTrain, yTrain)
            h2 = l2.predict(polyXTest)

            testE = mt.mean_squared_error(h2, yTest)
            testError.append(testE)
            
            h2 = l2.predict(polyXTrain)
            trainE = mt.mean_squared_error(h2, yTrain)
            trainError.append(trainE)
            #print('d: ' + str(d) + ' E: ' + str(E))
            #print(p3)
            #plot(polyXTest, h2, label = str(d))

        subplot(3,3,j, title = "N: " + str(N) + " noise: " + str(noise))
        plot(numpy.log(numpy.array(trainError)), label = 'train')        
        plot(numpy.log(numpy.array(testError)), label = 'test')
        plt.legend(loc="center right")
        




#print(X)
#print(y)

#s = scatter(X2, y2)


Q: Jesu li rezultati očekivani? Obrazložite.

4. Regularizirana regresija

(a)

U gornjim eksperimentima nismo koristili regularizaciju. Vratimo se najprije na primjer iz zadatka 1. Na primjerima iz tog zadatka izračunajte težine $\mathbf{w}$ za polinomijalni regresijski model stupnja $d=3$ uz L2-regularizaciju (tzv. ridge regression), prema izrazu $\mathbf{w}=(\mathbf{\Phi}^\intercal\mathbf{\Phi}+\lambda\mathbf{I})^{-1}\mathbf{\Phi}^\intercal\mathbf{y}$. Napravite izračun težina za regularizacijske faktore $\lambda=0$, $\lambda=1$ i $\lambda=10$ te usporedite dobivene težine.

Q: Kojih je dimenzija matrica koju treba invertirati?

Q: Po čemu se razlikuju dobivene težine i je li ta razlika očekivana? Obrazložite.


In [19]:
# Vaš kôd ovdje

def reg2(lambd):
    phi4 = PolynomialFeatures(3).fit_transform(X1)
    w = matmul( matmul(inv( matmul(transpose(phi4), phi4) + lambd * identity(len(phi4))), transpose(phi4)), y1)
    print(w)
    
reg2(0)
reg2(1)
reg2(10)


[ 4.         -5.91666667  3.375      -0.45833333]
[ 1.79567372 -0.24729075 -0.0175289   0.07014758]
[0.43312265 0.11060671 0.13827839 0.03093411]

(b)

Proučite klasu Ridge iz modula sklearn.linear_model, koja implementira L2-regularizirani regresijski model. Parametar $\alpha$ odgovara parametru $\lambda$. Primijenite model na istim primjerima kao u prethodnom zadatku i ispišite težine $\mathbf{w}$ (atributi coef_ i intercept_).

Q: Jesu li težine identične onima iz zadatka 4a? Ako nisu, objasnite zašto je to tako i kako biste to popravili.


In [20]:
from sklearn.linear_model import Ridge

In [32]:
phi4 = PolynomialFeatures(3).fit_transform(X1)
r = Ridge(0).fit(phi4, y1)
print(r.coef_)
print(r.intercept_)

# Vaš kôd ovdje


[ 0.         -5.91666667  3.375      -0.45833333]
4.000000000000021

5. Regularizirana polinomijalna regresija

(a)

Vratimo se na slučaj $N=50$ slučajno generiranih primjera iz zadatka 2. Trenirajte modele polinomijalne regresije $\mathcal{H}_{\lambda,d}$ za $\lambda\in\{0,100\}$ i $d\in\{2,10\}$ (ukupno četiri modela). Skicirajte pripadne funkcije $h(\mathbf{x})$ i primjere (na jednom grafikonu; preporučujemo koristiti plot unutar for petlje).

Q: Jesu li rezultati očekivani? Obrazložite.


In [46]:
# Vaš kôd ovdje

N = 50

figure(figsize = (15, 15))
x123 = scatter(X2, y2)

for lambd in [0, 100]:
    for d in [2, 10]:
        phi2 = PolynomialFeatures(d).fit_transform(X2)
        r = Ridge(lambd).fit(phi2, y2)
        h2 = r.predict(phi2)
        #print(d)
        plot(X2, h2, label="lambda " + str(lambd) + " d " + str(d))
        
x321 = plt.legend(loc="center right")


(b)

Kao u zadataku 3b, razdvojite primjere na skup za učenje i skup za ispitivanje u omjeru 1:1. Prikažite krivulje logaritama pogreške učenja i ispitne pogreške u ovisnosti za model $\mathcal{H}_{d=10,\lambda}$, podešavajući faktor regularizacije $\lambda$ u rasponu $\lambda\in\{0,1,\dots,50\}$.

Q: Kojoj strani na grafikonu odgovara područje prenaučenosti, a kojoj podnaučenosti? Zašto?

Q: Koju biste vrijednosti za $\lambda$ izabrali na temelju ovih grafikona i zašto?


In [64]:
# Vaš kôd ovdje


xTr, xTest, yTr, yTest = train_test_split(X2, y2, test_size=0.5)
figure(figsize=(10,10))
trainError = []
testError = []

for lambd in range(0,51):

    polyXTrain = PolynomialFeatures(10).fit_transform(xTr)    
    polyXTest = PolynomialFeatures(10).fit_transform(xTest)

    l2 = Ridge(lambd).fit(polyXTrain, yTr)
    h2 = l2.predict(polyXTest)

    E = mt.mean_squared_error(h2, yTest)
    #print('d: ' + str(d) + ' E: ' + str(E))
    testError.append(log( E))
    
    h2 = l2.predict(polyXTrain)
    E = mt.mean_squared_error(h2, yTr)
    trainError.append(log(E))
    #print(p3)
    #plot(polyXTest, h2, label = str(d))

plot(numpy.log(numpy.array(testError)), label="test")
plot(numpy.log(numpy.array(trainError)), label="train")
legend()


Out[64]:
<matplotlib.legend.Legend at 0x17f8d93f240>

6. L1-regularizacija i L2-regularizacija

Svrha regularizacije jest potiskivanje težina modela $\mathbf{w}$ prema nuli, kako bi model bio što jednostavniji. Složenost modela može se okarakterizirati normom pripadnog vektora težina $\mathbf{w}$, i to tipično L2-normom ili L1-normom. Za jednom trenirani model možemo izračunati i broj ne-nul značajki, ili L0-normu, pomoću sljedeće funkcije koja prima vektor težina $\mathbf{w}$:


In [73]:
def nonzeroes(coef, tol=1e-6): 
    return len(coef) - len(coef[np.isclose(0, coef, atol=tol)])

(a)

Za ovaj zadatak upotrijebite skup za učenje i skup za testiranje iz zadatka 3b. Trenirajte modele L2-regularizirane polinomijalne regresije stupnja $d=10$, mijenjajući hiperparametar $\lambda$ u rasponu $\{1,2,\dots,100\}$. Za svaki od treniranih modela izračunajte L{0,1,2}-norme vektora težina $\mathbf{w}$ te ih prikažite kao funkciju od $\lambda$. Pripazite što točno šaljete u funkciju za izračun normi.

Q: Objasnite oblik obiju krivulja. Hoće li krivulja za $\|\mathbf{w}\|_2$ doseći nulu? Zašto? Je li to problem? Zašto?

Q: Za $\lambda=100$, koliki je postotak težina modela jednak nuli, odnosno koliko je model rijedak?


In [76]:
# Vaš kôd ovdje
d = 10

l0 = []
l1 = []
l2 = []


xTr, xTest, yTr, yTest = train_test_split(X2, y2, test_size=0.5)

for lambd in range(0,101):

    polyXTrain = PolynomialFeatures(10).fit_transform(xTr)    
    polyXTest = PolynomialFeatures(10).fit_transform(xTest)

    r = Ridge(lambd).fit(polyXTrain, yTr)
    
    r.coef_[0] = r.intercept_
    
    l0.append(nonzeroes(r.coef_))
    #print(r.coef_)
    l1.append(numpy.linalg.norm(r.coef_, ord=1))
    l2.append(numpy.linalg.norm(r.coef_, ord=2))
    

figure(figsize=(10,10))
plot(l0, label="l0")
legend()

figure(figsize=(10,10))
plot(l1, label="l1")
legend()

figure(figsize=(10,10))
plot(l2, label="l2")
legend()


Out[76]:
<matplotlib.legend.Legend at 0x17f8ee97630>

(b)

Glavna prednost L1-regularizirane regresije (ili LASSO regression) nad L2-regulariziranom regresijom jest u tome što L1-regularizirana regresija rezultira rijetkim modelima (engl. sparse models), odnosno modelima kod kojih su mnoge težine pritegnute na nulu. Pokažite da je to doista tako, ponovivši gornji eksperiment s L1-regulariziranom regresijom, implementiranom u klasi Lasso u modulu sklearn.linear_model. Zanemarite upozorenja.


In [26]:
# Vaš kôd ovdje

7. Značajke različitih skala

Često se u praksi možemo susreti sa podatcima u kojima sve značajke nisu jednakih magnituda. Primjer jednog takvog skupa je regresijski skup podataka grades u kojem se predviđa prosjek ocjena studenta na studiju (1--5) na temelju dvije značajke: bodova na prijamnom ispitu (1--3000) i prosjeka ocjena u srednjoj školi. Prosjek ocjena na studiju izračunat je kao težinska suma ove dvije značajke uz dodani šum.

Koristite sljedeći kôd kako biste generirali ovaj skup podataka.


In [27]:
n_data_points = 500
np.random.seed(69)

# Generiraj podatke o bodovima na prijamnom ispitu koristeći normalnu razdiobu i ograniči ih na interval [1, 3000].
exam_score = np.random.normal(loc=1500.0, scale = 500.0, size = n_data_points) 
exam_score = np.round(exam_score)
exam_score[exam_score > 3000] = 3000
exam_score[exam_score < 0] = 0

# Generiraj podatke o ocjenama iz srednje škole koristeći normalnu razdiobu i ograniči ih na interval [1, 5].
grade_in_highschool = np.random.normal(loc=3, scale = 2.0, size = n_data_points)
grade_in_highschool[grade_in_highschool > 5] = 5
grade_in_highschool[grade_in_highschool < 1] = 1

# Matrica dizajna.
grades_X = np.array([exam_score,grade_in_highschool]).T

# Završno, generiraj izlazne vrijednosti.
rand_noise = np.random.normal(loc=0.0, scale = 0.5, size = n_data_points)
exam_influence = 0.9
grades_y = ((exam_score / 3000.0) * (exam_influence) + (grade_in_highschool / 5.0) \
            * (1.0 - exam_influence)) * 5.0 + rand_noise
grades_y[grades_y < 1] = 1
grades_y[grades_y > 5] = 5

a) Iscrtajte ovisnost ciljne vrijednosti (y-os) o prvoj i o drugoj značajki (x-os). Iscrtajte dva odvojena grafa.


In [28]:
# Vaš kôd ovdje

b) Naučite model L2-regularizirane regresije ($\lambda = 0.01$), na podacima grades_X i grades_y:


In [29]:
# Vaš kôd ovdje

Sada ponovite gornji eksperiment, ali prvo skalirajte podatke grades_X i grades_y i spremite ih u varijable grades_X_fixed i grades_y_fixed. Za tu svrhu, koristite StandardScaler.


In [30]:
from sklearn.preprocessing import StandardScaler

In [31]:
# Vaš kôd ovdje

Q: Gledajući grafikone iz podzadatka (a), koja značajka bi trebala imati veću magnitudu, odnosno važnost pri predikciji prosjeka na studiju? Odgovaraju li težine Vašoj intuiciji? Objasnite.

8. Multikolinearnost i kondicija matrice

a) Izradite skup podataka grades_X_fixed_colinear tako što ćete u skupu grades_X_fixed iz zadatka 7b duplicirati zadnji stupac (ocjenu iz srednje škole). Time smo efektivno uveli savršenu multikolinearnost.


In [ ]:
# Vaš kôd ovdje

Ponovno, naučite na ovom skupu L2-regularizirani model regresije ($\lambda = 0.01$).


In [ ]:
# Vaš kôd ovdje

Q: Usporedite iznose težina s onima koje ste dobili u zadatku 7b. Što se dogodilo?

b) Slučajno uzorkujte 50% elemenata iz skupa grades_X_fixed_colinear i naučite dva modela L2-regularizirane regresije, jedan s $\lambda=0.01$ i jedan s $\lambda=1000$). Ponovite ovaj pokus 10 puta (svaki put s drugim podskupom od 50% elemenata). Za svaki model, ispišite dobiveni vektor težina u svih 10 ponavljanja te ispišite standardnu devijaciju vrijednosti svake od težina (ukupno šest standardnih devijacija, svaka dobivena nad 10 vrijednosti).


In [ ]:
# Vaš kôd ovdje

Q: Kako regularizacija utječe na stabilnost težina?
Q: Jesu li koeficijenti jednakih magnituda kao u prethodnom pokusu? Objasnite zašto.

c) Koristeći numpy.linalg.cond izračunajte kondicijski broj matrice $\mathbf{\Phi}^\intercal\mathbf{\Phi}+\lambda\mathbf{I}$, gdje je $\mathbf{\Phi}$ matrica dizajna (grades_X_fixed_colinear). Ponovite i za $\lambda=0.01$ i za $\lambda=10$.


In [ ]:
# Vaš kôd ovdje

Q: Kako regularizacija utječe na kondicijski broj matrice $\mathbf{\Phi}^\intercal\mathbf{\Phi}+\lambda\mathbf{I}$?