I. La metrica della distanza
Innanzitutto, il numero di funzioni (colonne) in un set di dati non è un fattore nella selezione di una metrica della distanza da utilizzare in kNN. Ci sono alcuni studi pubblicati diretti proprio a questa domanda, e le solite basi per il confronto sono:
la distribuzione statistica sottostante dei tuoi dati;
la relazione tra le caratteristiche che compongono i tuoi dati (sono indipendenti - ovvero, che aspetto ha la matrice di covarianza); e
lo spazio delle coordinate da cui sono stati ottenuti i dati.
Se si dispone di alcuna conoscenza preliminare della distribuzione (s) da cui i dati è stato campionato, almeno uno (ben documentate e approfondite) lo studio conclude che la distanza euclidea è la scelta migliore.
YMetrica euclidea utilizzata nei motori di raccomandazione Web su larga scala e nella ricerca accademica attuale. Le distanze calcolate da Euclide hanno un significato intuitivo e le scale di calcolo - cioè, la distanza euclidea viene calcolata allo stesso modo, indipendentemente dal fatto che i due punti siano in due dimensioni o in uno spazio di ventidue dimensioni.
Ha fallito solo per me alcune volte, ognuno di quei casi la distanza euclidea è fallita perché il sistema di coordinate (cartesiano) sottostante era una scelta sbagliata. E di solito lo riconoscerai perché, ad esempio, le lunghezze del percorso (distanze) non sono più additive - ad esempio, quando lo spazio metrico è una scacchiera, la distanza di Manhattan è migliore di Euclide, allo stesso modo quando lo spazio metrico è Terra e le tue distanze sono trans -continentali, una metrica di distanza adatta per un sistema di coordinate polari è una buona idea (ad esempio, Londra a Vienna è di 2,5 ore, Vienna a San Pietroburgo è di altre 3 ore, più o meno nella stessa direzione, eppure da Londra a St Pietroburgo non è di 5,5 ore, invece è poco più di 3 ore.)
Ma a parte quei casi in cui i tuoi dati appartengono a un sistema di coordinate non cartesiane, la scelta della metrica della distanza non è di solito materiale. (Vedi questo post sul blog di uno studente CS, confrontando diverse metriche di distanza esaminando il loro effetto sul classificatore kNN - chi square dà i migliori risultati, ma le differenze non sono grandi; Uno studio più completo è nel documento accademico, Studio comparativo di Funzioni a distanza per i vicini più vicini - Mahalanobis (essenzialmente euclideo normalizzato per tenere conto della covarianza dimensionale) è stato il migliore in questo studio.
Una condizione importante: affinché i calcoli della metrica della distanza siano significativi, è necessario ridimensionarei tuoi dati - raramente è possibile creare un modello kNN per generare previsioni accurate senza farlo. Ad esempio, se stai costruendo un modello kNN per prevedere le prestazioni atletiche e le tue variabili di aspettativa sono altezza (cm), peso (kg), grasso corporeo (%) e polso a riposo (battiti al minuto), un punto dati tipico potrebbe assomigliare a questo: [180.4, 66.1, 11.3, 71]. Chiaramente il calcolo della distanza sarà dominato dall'altezza, mentre il contributo di% di grasso corporeo sarà quasi trascurabile. In altre parole, se invece i dati fossero riportati in modo diverso, in modo che il peso corporeo fosse in grammi anziché in chilogrammi, il valore originale di 86.1 sarebbe 86.100, il che avrebbe un grande effetto sui risultati, che è esattamente ciò che si indossa voglio.
X_new = (X_old - mu) / sigma
II. La struttura dei dati
Se sei preoccupato per le prestazioni della struttura kd-tree, A Voronoi Tessellation è un contenitore concettualmente semplice ma che migliorerà drasticamente le prestazioni e ridimensionerà meglio di kd-Trees.
Questo non è il modo più comune di conservare i dati di addestramento di kNN, sebbene l'applicazione di VT a questo scopo, così come i conseguenti vantaggi in termini di prestazioni, siano ben documentati (vedi ad esempio questo rapporto di Microsoft Research ). Il significato pratico di questo è che, a condizione che tu stia utilizzando un linguaggio 'mainstream' (ad esempio, nell'indice TIOBE ), dovresti trovare una libreria per eseguire VT. So che in Python e R, ci sono più opzioni per ogni lingua (ad esempio, il pacchetto voronoi per R disponibile su CRAN )
L'uso di un VT per kNN funziona in questo modo ::
Dai tuoi dati, seleziona casualmente i punti w: questi sono i tuoi centri Voronoi. Una cella Voronoi incapsula tutti i punti vicini che sono più vicini a ciascun centro. Immagina se assegni un colore diverso a ciascuno dei centri Voronoi, in modo che ogni punto assegnato a un dato centro sia dipinto quel colore. Finché hai una densità sufficiente, farlo mostrerà bene i confini di ciascun centro Voronoi (come il confine che separa due colori.
Come selezionare i centri Voronoi? Uso due linee guida ortogonali. Dopo aver selezionato casualmente i punti w, calcolare il VT per i dati di allenamento. Quindi controlla il numero di punti dati assegnati a ciascun centro Voronoi: questi valori dovrebbero essere più o meno gli stessi (data la densità dei punti uniforme nello spazio dati). In due dimensioni, ciò causerebbe un VT con tessere della stessa dimensione. Questa è la prima regola, ecco la seconda. Seleziona w per iterazione: esegui l'algoritmo kNN con w come parametro variabile e misura le prestazioni (tempo necessario per restituire una previsione eseguendo una query sul VT).
Quindi immagina di avere un milione di punti dati ..... Se i punti persistessero in una normale struttura di dati 2D o in un albero kd, eseguiresti in media un paio di milioni di calcoli di distanza per ciascunonuovi punti dati di cui si desidera prevedere la variabile di risposta. Naturalmente, questi calcoli vengono eseguiti su un singolo set di dati. Con una V / T, la ricerca del vicino più vicino viene eseguita in due passaggi uno dopo l'altro, rispetto a due diverse popolazioni di dati: prima contro i centri Voronoi, quindi una volta trovato il centro più vicino, i punti all'interno della cella corrispondenti a quel centro viene cercato per trovare l'attuale vicino più vicino (mediante calcoli di distanza successivi) Combinati, questi due look-up sono molto più veloci di un singolo look-forza bruta. È facile da vedere: per i punti dati 1M, supponi di selezionare 250 centri Voronoi per tassellare il tuo spazio dati. In media, ogni cella Voronoi avrà 4.000 punti dati. Quindi, invece di eseguire in media 500.000 calcoli di distanza (forza bruta), esegui molto meno, in media solo 125 + 2.000.
III. Calcolo del risultato (la variabile di risposta prevista)
Esistono due passaggi per calcolare il valore previsto da una serie di dati di allenamento kNN. Il primo è identificare n, o il numero di vicini più vicini da usare per questo calcolo. Il secondo è come ponderare il loro contributo al valore previsto.
Con il primo componente, puoi determinare il valore migliore di n risolvendo un problema di ottimizzazione (molto simile all'ottimizzazione dei minimi quadrati). Questa è la teoria; in pratica, la maggior parte delle persone usa solo n = 3. In ogni caso, è semplice eseguire l'algoritmo kNN su una serie di istanze di test (per calcolare i valori previsti) per n = 1, n = 2, n = 3, ecc. E tracciare l'errore in funzione di n. Se vuoi solo un valore plausibile per n per iniziare, usa nuovamente n = 3.
Il secondo componente è come ponderare il contributo di ciascuno dei vicini (assumendo n> 1).
La tecnica di ponderazione più semplice è semplicemente moltiplicare ciascun vicino per un coefficiente di ponderazione, che è solo 1 / (dist * K), o l'inverso della distanza da quel vicino all'istanza del test spesso moltiplicata per una costante derivata empiricamente, K. I non sono un fan di questa tecnica perché spesso sovrappesa i vicini più vicini (e contemporaneamente sottopeso i pesi a quelli più distanti); il significato di ciò è che una determinata previsione può dipendere quasi interamente da un singolo vicino, il che a sua volta aumenta la sensibilità dell'algoritmo al rumore.
Una funzione di ponderazione migliore, che evita sostanzialmente questa limitazione, è la funzione gaussiana , che in pitone assomiglia a questa:
def weight_gauss(dist, sig=2.0) :
return math.e**(-dist**2/(2*sig**2))
Per calcolare un valore previsto usando il tuo codice kNN, dovresti identificare gli n vicini più vicini al punto dati di cui desideri prevedere la variabile di risposta ("istanza di prova"), quindi chiamare la funzione weight_gauss, una volta per ciascuno dei n vicini, passando nella distanza tra ciascun vicino il punto di prova. Questa funzione restituirà il peso per ciascun vicino, che viene quindi utilizzato come coefficiente di quel vicino nel calcolo della media ponderata.