-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
164 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# k-NN | ||
|
||
L'algoritmo di **$k$-nearest neighbors** prevede la classe di appartenenza semplicemente scegliendo quella **più frequente** tra i $k$ _feature vector_ (i.e. input) più vicini, secondo la loro [distanza euclidea](https://en.wikipedia.org/wiki/Euclidean_distance). | ||
|
||
Si vuole quindi **bilanciare** $k$: **non troppo piccolo** per evitare sensibilità al rumore, e **non troppo grande** per evitare costi computazionali elevati. | ||
È anche possibile dare un **peso alla distanza** con $w = \frac{1}{d^2}$. | ||
|
||
Uno **svantaggio** della _distanza euclidea_ è che assume che ogni _feature_ (i.e. elemento del vettore) abbia lo stesso peso. | ||
Questo si può aggirare **scalando** ogni colonna $j$ in modo che il suo intervallo | ||
$$ | ||
\left[\min_i A_{ij}, \max_i A_{ij}\right] \to [0, 1] | ||
$$ | ||
con `StandardScaler` o `MinMaxScaling`, che sono però entrambi sensibili agli _outliers_. | ||
|
||
Per esempio, usando dati casuali | ||
```python | ||
from sklearn.datasets import make_blobs | ||
from sklearn.model_selection import train_test_split | ||
from sklearn.preprocessing import MinMaxScaler | ||
from sklearn.neighbors import KNeighborsClassifier | ||
|
||
X, X_labels = make_blobs( | ||
n_samples=1000, centers=4, | ||
random_state=12345 | ||
) | ||
X_train, X_test, y_train, y_test = train_test_split( | ||
X, X_labels, | ||
test_size=0.33, | ||
random_state=42 | ||
) | ||
|
||
scaler = MinMaxScaler() | ||
scaler.fit(X_train) | ||
|
||
kNN = KNeighborsClassifier(n_neighbors=10) | ||
kNN.fit(scaler.transform(X_train), y_train) | ||
y_pred = kNN.predict(scaler.transform(X_test)) | ||
``` | ||
si ottiene la seguente classificazione, con le `X` normalizzate in $[0, 1]$: | ||
|
||
![Scatter plot dei confini dei data point normalizzati](assets/01.png) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# Decision tree | ||
|
||
|
||
Attraverso gli _alberi decisionali_ è possibile **partizionare** il dominio dei _feature vector_ in base ai valori delle singole _feature_ (i.e. componenti), e a dei **threshold** che rappresentano il confine di suddivisione. | ||
|
||
Per esempio, dallo spazio con _feature vector_ $(x, y)$ | ||
|
||
![Dati in cluster opposti](assets/01.png) | ||
|
||
si può ricavare un albero simile a: | ||
|
||
```dot process | ||
digraph { | ||
node [shape=box] | ||
edge [arrowsize=0.8] | ||
0 [label="x ≤ 1.4" style=rounded] | ||
1 [label="y ≤ 1.5" style=rounded] | ||
2 [label="y ≤ 1.45" style=rounded] | ||
3 [label="Purple"] | ||
4 [label="Yellow"] | ||
5 [label="Yellow"] | ||
6 [label="Purple"] | ||
{ | ||
rank=same | ||
_0 [shape=point width=0 height=inf style=invis] | ||
1 -> _0 -> 2 [style=invis] | ||
} | ||
{ | ||
rank=same | ||
_1, _2 [shape=point width=0 height=inf style=invis] | ||
3 -> _1 -> 4 [style=invis] | ||
5 -> _2 -> 6 [style=invis] | ||
} | ||
0 -> _0 [style=invis weight=100] | ||
1 -> _1 [style=invis weight=100] | ||
2 -> _2 [style=invis weight=100] | ||
0 -> 1 [label="True"] | ||
0 -> 2 [label="False"] | ||
1 -> 3 [label="True"] | ||
1 -> 4 [label="False"] | ||
2 -> 5 [label="True"] | ||
2 -> 6 [label="False"] | ||
} | ||
``` | ||
|
||
## Classificazione | ||
|
||
Un algoritmo per la costruzione dell'albero è l'**algoritmo di Hunt** ricorsivo, che prende un _dataset_ $\mathcal{D}$: | ||
```c | ||
build_tree(D) | ||
best_split, best_gain = null | ||
for each feature f | ||
for each threshold t | ||
gain = split_goodness(f, t) // Riduzione dell'errore partizionando per (f <= t) | ||
if gain >= best_gain | ||
best_gain = gain | ||
best_split = (f, t) | ||
|
||
if best_gain = 0 or other_stopping_criterion | ||
μ = best_prediction(D) // Media/moda delle y di D per regressione/classificazione | ||
return Leaf(μ) | ||
|
||
f, t = best_split | ||
L = build_tree(filter(D, x : x[f] <= t)) | ||
R = build_tree(filter(D, x : x[f] > t)) | ||
return Node(L, R) | ||
``` | ||
### Foglie | ||
La `best_prediction(D)` è definita come la moda delle $y$ di $(x, y) \in \mathcal{D}$, ovvero il **label più frequente**: | ||
$$ | ||
\argmin_\mu \mathrm{Error}(\mathcal{D}, \mu) = | ||
\argmin_\mu \frac{1}{|\mathcal{D}|} \sum_{(x, y) \in \mathcal{D}} | ||
\begin{cases} | ||
0 & \text{se } \mu = y \\ | ||
1 & \text{altrimenti} | ||
\end{cases} | ||
$$ | ||
Per semplicità, d'ora in poi si definisce $\mathrm{Error}(\mathcal{D})$ come l'errore della miglior previsione $\mu$ di $\mathcal{D}$. | ||
### Nodi interni | ||
La qualità del taglio $(f, t)$ è dato dal **guadagno** dell'errore che si ha tagliando $\mathcal{D}$ rispetto a non tagliare: | ||
$$ | ||
\mathrm{Gain}((f, t), \mathcal{D}) = \mathrm{Error}(\mathcal{D}) - | ||
\left( | ||
\frac{|\mathcal{D}_L|}{|\mathcal{D}|} \mathrm{Error}(\mathcal{D}_L) + | ||
\frac{|\mathcal{D}_R|}{|\mathcal{D}|} \mathrm{Error}(\mathcal{D}_R) | ||
\right) | ||
$$ |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Supervised learning | ||
|
||
L'_apprendimento supervisionato_ avviene istruendo un modello **conoscendo gli output** voluti a priori. | ||
|
||
Tra le due principali forme di apprendimento, ci sono: | ||
- **Classificazione**: per predire l'appartenenza a delle categorie | ||
- **Analisi di regressione**: per stimare una funzione numerica sui dati | ||
|
||
Il **dataset** viene suddiviso in **training** e **test** per poter **valutare** successivamente il modello, per esempio: | ||
```python | ||
from sklearn.model_selection import train_test_split | ||
from sklearn.metrics import accuracy_score | ||
|
||
X_train, X_test, y_train, y_test = train_test_split( | ||
X, y, test_size=0.25, random_state=42 | ||
) | ||
model.fit(X_train, y_train) | ||
y_pred = model.predict(X_test) | ||
accuracy = accuracy_score(y_true=y_test, y_pred=y_pred) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Data e web mining |