Commits

Jure Žbontar  committed e68225b

Cross validation.

  • Participants
  • Parent commits 42014a2

Comments (0)

Files changed (1)

File predavanja/cv.md

 `k - 1` kosov uporabimo za učenje modela s katerim napovemo zadnji
 kos. Postopek ponovimo `k`-krat, le da vsakič napovemo drug kos podatkov.
 
-*Q: Zakaj potrebujemo prečno preverjanje? Ali ni dovolj skripta `validate.py`?*
+*Q: Zakaj potrebujemo k-kratno prečno preverjanje? Ali ni dovolj skripta
+`validate.py`?*
 
-A: bla bla
+A: k-kratno prečno preverjanje je "boljše" od skripte `validate.py`,
+ker naš model prizkusi na vseh, ne pa samo na 30%, učnih primerih,
+poleg tega nam bo prišlo prav tudi, ko bomo združevali različne
+modele. Slabost prečnega preverjanje je, da potrebuje `k`-krat več
+procesorskega časa, kar je pri velikih podatkih lahko problematično.
+K sreči algoritem kar kliče po učinkoviti paralelni implementaciji,
+ki jo boste sprogramirali v eni od vaj.
 
 *Q: Zakaj potrebujemo skripto `validate.py`? Ali k-kratno prečno prevčno
 preverjanje ni dovolj?*
 
-A: bli bli
+A: Če nismo pazljivi se lahko zgodi, da pri k-kratnem prečnem
+preverjanju nevede pogoljufamo (najbolj tipičen primer je, da pred
+prečnim preverjanjem izberemo atribute, ki dobro ločijo razred) in
+nas dobljeni rezultat lahko zavede. Nevarni so tudi algoritmi, ki 
+sprejemajo veliko parametrov, saj se lahko naučimo dobro ločevati
+le učne primere.
 
+Vaj se bomo lotili tako, da bomo najprej sprogramirali mero `logloss`,
+nato se bomo lotili k-kratnega prečnega preverjanja, zaključili pa
+bomo s paralelno implementacijo.
 
 1. Napiši funkcijo `logloss(y, P)`, ki implementira
 [Multi Class Log Loss](https://www.kaggle.com/wiki/MultiClassLogLoss) - mero,
 
             return -np.mean(np.log(p))
     </div>
+
+2. Napiši funkcijo `cv(X, y, fun, folds=4)`, ki sprejme redko matriko
+atributov `X`, seznam razredov `y`, klassifikator `fun` in `k`, ki sem
+ga v svoji kodi, iz neznanih razlogov, poimenoval `folds`.
+
+		>>> data = np.loadtxt('iris.data')
+		>>> X, y = sp.csr_matrix(data[:,:-1]), data[:,-1].astype(np.int)
+		>>> cv(X, y, majority)  # rezultat bo odvisen od nakljucne delitve podatkov
+		1.10553312572
+
+    <div class="solution">
+
+		def cv(X, y, fun, folds=4):
+			np.random.seed(42)
+			ind = np.random.randint(0, folds, y.size)
+			score = []
+			for fold in range(folds):
+				tr_ind = np.nonzero(ind != fold)[0]
+				te_ind = np.nonzero(ind == fold)[0]
+
+				P = fun(X[tr_ind], y[tr_ind], X[te_ind])
+				score.append(logloss(y[te_ind], P))
+			return np.mean(score)
+	</div>
+
+
+3. Pri k-kratnem prečnem preverjenju lahko
+vseh `k` kosov izvajamo sočasno - vsak kos na
+svojem procesorju. Poglobite se v dokumentacijo modula
+[multiprocessing](http://docs.python.org/library/multiprocessing.html).
+Posebej pozorno preberite opis metod `apply_async` razreda `Pool` in
+sprogramirajte paralelno različio k-kratnega prečnega preverjanja.
+
+	<div class="solution">
+
+		import multiprocessing
+
+		def cv(X, y, fun, folds=4):
+			np.random.seed(42)
+			ind = np.random.randint(0, folds, y.size)
+
+			res = []
+			pool = multiprocessing.Pool()
+			for fold in range(folds):
+				tr_ind = np.nonzero(ind != fold)[0]
+				te_ind = np.nonzero(ind == fold)[0]
+
+				r = pool.apply_async(fun, (X[tr_ind], y[tr_ind], X[te_ind]))
+				res.append((r, te_ind))
+
+			score = []
+			for r, te_ind in res:
+				P = r.get()
+				score.append(logloss(y[te_ind], P))
+			pool.close()
+			pool.join()
+
+			return np.mean(score)
+	</div>
+
+4. Kasneje, ko bomo združevali napovedi različnih klasifikitorjev, bomo
+za vsak učni primer potrebovali verjetnosti, ki so bile med postpokom
+k-kratnega prečnega preverjanja napovedane. Spremeni funkcijo `cv`, da
+bo vračala tudi matriko verjetnosti.
+
+		>>> P, score = cv(X, y, majority)
+		>>> P.shape
+		(150, 3)
+		>>> score
+		1.10553312572
+
+	<div class="solution">
+
+		# Spremenjene vrstice so oznacene s komentarij +++
+		def cv(X, y, fun, folds=4):
+			np.random.seed(42)
+			ind = np.random.randint(0, folds, y.size)
+
+			res = []
+			pool = multiprocessing.Pool()
+			for fold in range(folds):
+				tr_ind = np.nonzero(ind != fold)[0]
+				te_ind = np.nonzero(ind == fold)[0]
+
+				r = pool.apply_async(fun, (X[tr_ind], y[tr_ind], X[te_ind]))
+				res.append((r, te_ind))
+
+			P = np.zeros((y.size, np.max(y) + 1))           # +++
+			score = []
+			for r, te_ind in res:
+				P[te_ind] = r.get()                         # +++
+				score.append(logloss(y[te_ind], P[te_ind])) # +++
+			pool.close()
+			pool.join()
+
+			return P, np.mean(score)
+	</div>
+