Zum Hauptinhalt springen




Abkürzungen kNN es bedeutet k-Nächste-Nachbarn, que es un Algorithmus de aprendizaje supervisado. Se puede utilizar para la clasificación, así como para problemas de regresión.

Wie funktioniert der kNN-Algorithmus?

kNN entscheidet die Klasse des neuen Datenpunkts basierend auf der maximalen Anzahl von Nachbarn, die der Datenpunkt hat und die zur selben Klasse gehören.

Wenn die Nachbarn eines neuen Datenpunkts wie folgt sind: NY: 7, NJ: 0, IN: 4, dann ist die Klasse des neuen Datenpunktes NY.

Angenommen, Sie arbeiten in einem Postamt und haben die Aufgabe, Briefe unter den Postboten zu organisieren und zu verteilen, um die Anzahl der Fahrten in die verschiedenen Stadtteile zu minimieren. Und da wir uns nur Dinge vorstellen, können wir davon ausgehen, dass es nur sieben verschiedene Stadtteile gibt. Dies ist eine Art Klassifizierungsproblem. Sie müssen die Buchstaben in Klassen unterteilen, wobei sich die Klassen hier auf die beziehen Upper East Side, Innenstadt von Manhattan, und so weiter.

Wenn Sie Zeit und Ressourcen verschwenden möchten, können Sie jedem Postboten einen Brief aus jeder Nachbarschaft geben und hoffen, dass er sich in derselben Nachbarschaft trifft und Ihren korrupten Plan entdeckt. Das ist die schlechteste Art der Verteilung, die erreicht werden kann.

Auf der anderen Seite können Sie die Buchstaben danach organisieren, welche Adressen einander am nächsten liegen.

Sie könnten mit beginnen "Wenn es innerhalb von drei Blöcken ist, geben Sie es dem gleichen Postboten". Diese Anzahl von nächsten Blöcken ist, woher es kommt K.. Sie können die Anzahl der Blöcke so lange erhöhen, bis Sie ein effizientes Layout erreicht haben. Das ist der effizienteste Wert von k für Ihr Klassifizierungsproblem.

kNN in der Praxis - Code

Wie im letzten Tutorial werden wir das Modul verwenden KNN von ml.js um unseren Klassifikator zu trainieren kNächste Nachbarn. Jedes Problem des maschinellen Lernens benötigt Daten, und wir werden den Datensatz verwenden IRIS in diesem Tutorial.

Der Iris-Datensatz besteht aus 3 verschiedenen Arten von Irisblütenlängen und Kelchblättern (Setosa, Versicolor y Virginica), zusammen mit einem Feld, das den jeweiligen Typ angibt.

Installieren Sie die Bibliotheken

$-Garn ml-knn csvtojson-Eingabeaufforderung hinzufügen

Oder wenn Sie es vorziehen npm:

npm install ml-knn csvtojson Eingabeaufforderung
  • ml-knn: k Nächste Nachbarn
  • csvtojson: Analysedaten
  • im die richtige Zeit: Para permitir que el Nutzername solicite predicciones

Initialisieren Sie die Bibliothek und laden Sie die Daten

Der Iris-Datensatz wird von der University of California, Irvine, bereitgestellt und ist verfügbar Hier. Sin embargo, debido a la forma en que está organizado, tendrás que copiar el Inhalt beim Browser (Seleccionar todo, Copiar) y pegarlo en un archivo llamado iris.csv. Sie können es beliebig benennen, außer dass die Erweiterung sein muss .csv.

Initialisieren Sie nun die Bibliothek und laden Sie die Daten.

const KNN = erfordern ('ml-knn'); const csv = require ('csvtojson'); const prompt = require ('prompt'); lass knn; const csvFilePath = 'iris.csv'; // Daten const names = ['sepalLength', 'sepalWidth', 'petalLength', 'petalWidth', 'type']; // für den Header let seperationSize; // Um Trainings- und Testdaten zu trennen, lassen Sie data = [], X = [], y = []; let trainingSetX = [], trainingSetY = [], testSetX = [], testSetY = [];

Los nombres de los Überschriften se utilizan para la visualización y la comprensión. Se quitarán más adelante.

Was ist mehr, seperationSize Es wird verwendet, um die Daten in Trainings- und Testdatensätze zu unterteilen.

Wir haben das Paket importiert csvto.json, und jetzt werden wir Ihre Methode anwenden aus Datei um die Daten zu laden. (Da unsere Daten keine Kopfzeile haben, geben wir unsere eigenen Kopfnamen an.)

csv ({noheader: true, headers: names}) .fromFile (csvFilePath) .on ('json', (jsonObj) => {data.push (jsonObj); // Jedes Objekt in das Datenarray pushen}) .on ( 'done', (error) => {seperationSize = 0.7 * data.length; data = shuffleArray (data); dressData ();});

Wir verschieben jede Zeile in die Datumsvariable, und wenn der Prozess abgeschlossen ist, passen wir die an seperationSize zu 0.7 mal die Anzahl der Proben in unserem Datensatz. Beachten Sie, dass der Klassifikator möglicherweise nicht so gut funktioniert wie bei einem größeren Satz, wenn die Größe der Trainingsmuster zu klein ist.

Da unser Datensatz in Bezug auf Typen geordnet ist (console.log zur Bestätigung), die Funktion shuffleArray wird verwendet, um den Datensatz zu mischen, um eine Teilung zu ermöglichen. (Wenn Sie nicht mischen, erhalten Sie möglicherweise ein Modell, das für die ersten beiden Klassen gut funktioniert, bei der dritten jedoch fehlschlägt.)

So wird es definiert.

/ ** * https://stackoverflow.com/a/12646864 * Ordnen Sie die vorhandenen Array-Elemente nach dem Zufallsprinzip an. * Verwendung des Durstenfeld-Mischalgorithmus. * / function shuffleArray (array) {für (var i = array.length - 1; i> 0; i--) {var j = Math.floor (Math.random () * (i + 1)); var temp = array [i]; Array [i] = Array [j]; Array [j] = Temp; } return array; }}

Kleidungsdaten (noch einmal)

Unsere Daten sind wie folgt organisiert:

{sepalLength: '5.1', sepalWidth: '3.5', petalLength: '1.4', petalWidth: '0.2', Typ: 'Iris-setosa'}

Es gibt zwei Dinge, die wir mit unseren Daten tun müssen, bevor wir sie an den Klassifikator liefern kNN:

  • Drehen Sie die Zeichenfolgenwerte in Gleitkommazahlen. (parseFloat)
  • Konvertiert den Typ in nummerierte Klassen.
Funktion dressData () {/ ** * Es gibt drei verschiedene Arten von Irisblüten, die in diesem Datensatz * klassifiziert wurden: * * 1. Iris Setosa (Iris-setosa) * 2. Iris Versicolor (Iris-versicolor) * 3. Iris Virginica ( Iris-virginica) * * Ändern wir diese Klassen von Strings in Zahlen. * So dass ein Typwert gleich * 0 setosa bedeuten würde, * 1 versicolor bedeuten würde und * 3 virginica bedeuten würde * / let types = new Set (); // Um EINZIGARTIGE Klassen zu sammeln data.forEach ((row) => {types.add (row.type);}); typesArray = [... types]; // Um die verschiedenen Arten von Klassen aufzuzeichnen. data.forEach ((row) => {let rowArray, typeNumber; rowArray = Object.keys (row) .map (key => parseFloat (row [key])). Slice (0, 4); typeNumber = typesArray.indexOf (row.type); // Typ (String) in Typ (Number) konvertieren X.push (rowArray); y.push (typeNumber);}); trainingSetX = X.slice (0, seperationSize); trainingSetY = y.slice (0, seperationSize); testSetX = X.slice (seperationSize); testSetY = y.slice (seperationSize); Zug (); }}

Wenn Sie nicht vertraut sind Sets, Sie sind wie ihre mathematischen Gegenstücke, da sie keine doppelten Elemente haben können und ihre Elemente keinen Index haben. (Im Gegensatz zu Arrays.)

Und sie können einfach mit dem Spread-Operator oder dem Set-Konstruktor in Arrays konvertiert werden.

Trainieren Sie Ihr Modell und testen Sie es dann

Funktionszug () {knn = neuer KNN (trainingSetX, trainingSetY, {k: 7}); Prüfung(); }}

Die Trainingsmethode verwendet zwei erforderliche Argumente: die Eingabedaten wie Blütenblattlänge, Blütenblattbreite und die tatsächliche Klasse wie die Iris-Setosa, und so weiter. Es ist auch ein optionaler Optionsparameter erforderlich, bei dem es sich lediglich um ein JS-Objekt handelt, das übergeben werden kann, um die internen Parameter des Algorithmus anzupassen. Wir geben den Wert von weiter k als eine Option. Der Standardwert von k ist 5.

Ahora que nuestro modelo ha sido entrenado, veamos cómo funciona en el equipo de pruebas. Principalmente, estamos interesados en el número de errores de clasificación que se producen. (Es decir, el número de veces que predice que la entrada es algo, aunque en realidad Sein otra cosa.)

Funktionstest () {const result = knn.predict (testSetX); const testSetLength = testSetX.length; const VorhersageError = Fehler (Ergebnis, testSetY); console.log (`Test Set Size = $ {testSetLength} und Anzahl der Fehlklassifizierungen = $ {VorhersageError}`); vorhersagen (); }}

Der Fehler wird wie folgt berechnet. Wir verwenden die bescheidene for-Schleife, um den Datensatz zu durchlaufen, und prüfen, ob die vorhergesagte Ausgabe nicht der tatsächlichen Ausgabe entspricht. Es ist eine Fehlklassifizierung.


function error(predicted, expected) {
let misclassifications = 0;
for (var index = 0; index < predicted.length; index++) {
if (predicted[index] !== expected[index]) {
misclassifications++;
}
}
return misclassifications;
}

(Optional) Beginnen Sie mit der Vorhersage

Zeit für einige Hinweise und Vorhersagen.

Funktion Predict () {let temp = []; prompt.start (); prompt.get (['Sepal Length', 'Sepal Width', 'Petal Length', 'Petal Width'], Funktion (err, result) {if (! err) {for (var key in result) {temp.push (parseFloat (result [key]));} console.log (`Mit $ {temp} - type = $ {knn.predict (temp)}`);}}); }}

Überspringen Sie diesen Schritt, wenn Sie das Modell nicht in einem neuen Beitrag testen möchten.

Alles beendet!

Si tú seguiste todos los pasos, así es como debería verse tu Index.js:


const KNN = require('ml-knn');
const csv = require('csvtojson');
const prompt = require('prompt');
let knn;
const csvFilePath = 'iris.csv'; // Datos
const names = ['sepalLength', 'sepalWidth', 'petalLength', 'petalWidth', 'type']; // para el header

let seperationSize; // Para separar los datos de entrenamiento y de prueba

let data = [], X = [], y = [];

let trainingSetX = [], trainingSetY = [], testSetX = [], testSetY = [];

csv({noheader: true, headers: names})
.fromFile(csvFilePath)
.on('json', (jsonObj) => {
data.push(jsonObj); // Empujar cada objeto a la matriz de datos
})
.on('done', (error) => {
seperationSize = 0.7 * data.length;
data = shuffleArray(data);
dressData();
});

function dressData() {

let types = new Set(); // Para reunir clases ÚNICAS

data.forEach((row) => {
types.add(row.type);
});

typesArray = [...types]; // Para grabar los diferentes tipos de clases.

data.forEach((row) => {
let rowArray, typeNumber;

rowArray = Object.keys(row).map(key => parseFloat(row[key])).slice(0, 4);

typeNumber = typesArray.indexOf(row.type); // Para grabar los diferentes tipos de clases.

X.push(rowArray);
y.push(typeNumber);
});

trainingSetX = X.slice(0, seperationSize);
trainingSetY = y.slice(0, seperationSize);
testSetX = X.slice(seperationSize);
testSetY = y.slice(seperationSize);

train();
}

function train() {
knn = new KNN(trainingSetX, trainingSetY, {k: 7});
test();
}

function test() {
const result = knn.predict(testSetX);
const testSetLength = testSetX.length;
const predictionError = error(result, testSetY);
console.log(`Test Set Size = ${testSetLength} and number of Misclassifications = ${predictionError}`);
predict();
}

function error(predicted, expected) {
let misclassifications = 0;
for (var index = 0; index < predicted.length; index++) { if (predicted[index] !== expected[index]) { misclassifications++; } } return misclassifications; } function predict() { let temp = []; prompt.start(); prompt.get(['Sepal Length', 'Sepal Width', 'Petal Length', 'Petal Width'], function (err, result) { if (!err) { for (var key in result) { temp.push(parseFloat(result[key])); } console.log(`With ${temp} -- type = ${knn.predict(temp)}`); } }); } /** * https://stackoverflow.com/a/12646864 * Randomize array element order in-place. * Using Durstenfeld shuffle algorithm. */ function shuffleArray(array) { for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}

Führen Sie den Knoten aus index.js. Es sollte Ihnen dies auf dem Bildschirm zeigen:

$ node index.js Test Set Size = 45 und Anzahl der Fehlklassifizierungen = 2 Eingabeaufforderung: Sepal Length: 1.7 Eingabeaufforderung: Sepal Width: 2.5 Eingabeaufforderung: Petal Length: 0.5 Eingabeaufforderung: Petal Width: 3.4 With 1.7,2.5,0.5,3.4 - type = 2

Gut gemacht. Das ist Ihr kNN-Algorithmus bei der Arbeit.

Ein großer Aspekt des kNN-Algorithmus ist der Wert von k und wird als Hyperparameter bezeichnet. Hyperparameter sind eine "Art von Parametern, die nicht direkt aus dem regulären Trainingsprozess gelernt werden können". Diese Parameter drücken die Eigenschaften des Modells auf "höherer Ebene" aus, z. B. seine Komplexität oder wie schnell es gelernt werden muss. Sie werden "Hyperparameter" genannt.