Las siglas kNN significa k-Nearest-Neighbours, que es un algoritmoUn algoritmo es un procedimiento o conjunto de reglas a seguir en los cálculos u otras operaciones de resolución de problemas, fundamentalmente por un PC. Apps Un ejemplo de la vida cotidiana es una receta para hornear un pastel. Siguiendo los pasos de la receta se obtiene el pastel deseado al final. Otras apps conocidas son la búsqueda y clasificación. ¿Cómo se puede hallar un canal de televisión de la más de aprendizaje supervisado. Se puede utilizar para la clasificación, así como para problemas de regresión.
¿Cómo funciona el algoritmo kNN?
kNN decide la clase del nuevo punto de datos basándose en el número máximo de vecinos que tiene el punto de datos que pertenecen a la misma clase.
Si los vecinos de un nuevo punto de datos son los siguientes, NY: 7, NJ: 0, IN: 4, entonces la clase del nuevo punto de datos será NY.
Digamos que trabajas en una oficina de correos y tu trabajo es organizar y distribuir cartas entre los carteros para minimizar el número de viajes a los diferentes barrios. Y como sólo estamos imaginando cosas, podemos asumir que sólo hay siete vecindarios diferentes. Este es un tipo de problema de clasificación. Necesitas dividir las letras en clases, donde las clases aquí se refieren al Upper East Side, Downtown Manhattan, y así sucesivamente.
Si te gusta perder tiempo y recursos, puedes dar una carta de cada vecindario a cada cartero, y esperar que se conozcan en el mismo vecindario y descubran tu plan corrupto. Ese es el peor tipo de distribución que se puede lograr.
Por otro lado, puedes organizar las cartas en función de qué direcciones están más cerca unas de otras.
Podrías empezar con «Si está dentro de un rango de tres manzanas, dáselo al mismo cartero». Ese número de bloques más cercanos es de donde viene K. Puedes seguir aumentando el número de bloques hasta que llegues a una distribución eficiente. Ese es el valor más eficiente de k para tu problema de clasificación.
kNN en la práctica – Código
Como hicimos en el último tutorial, vamos a usar el módulo KNN de ml.js para entrenar a nuestro clasificador kNearestNeighbors. Cada problema de Aprendizaje de Máquina necesita datos, y vamos a usar el conjunto de datos IRIS en este tutorial.
El conjunto de datos del iris consiste en 3 tipos diferentes de longitud de pétalos y sépalos de iris (Setosa, Versicolor y Virginica), junto con un campo que indica su tipo respectivo.
Instalar las bibliotecas
$ yarn add ml-knn csvtojson prompt
O si prefieres npm:
npm install ml-knn csvtojson prompt
- ml-knn: k Vecinos más cercanos
- csvtojson: Datos de análisis
- en el momento oportuno: Para permitir que el usuario solicite predicciones
Inicializar la biblioteca y cargar los datos
El conjunto de datos Iris es proporcionado por la Universidad de California, Irvine y está disponible aquí. Sin embargo, debido a la forma en que está organizado, tendrás que copiar el contenidoEl contenido puede ser muy difícil de definir con precisión. Es una definición que se refiere a las declaraciones contenidas en un documento o publicación de cualquier tipo y puede incluir las tecnologías de la información y la comunicación. Esto cubre todos los tipos de medios como imágenes y texto. A parte de esto, en el campo de la optimización de motores de búsqueda, los términos duplicar contenido, contenido único, más en el navegadorUn navegador (además: browser) es una herramienta informática que te permite ver documentos y datos y navegar por la red. Los navegadores pueden mostrar distintos tipos de recursos de información; principalmente documentos HTML, a pesar de todo, además son posibles otros tipos de archivos y contenido multimedia, como PDF, JPEG, MPEG, GIF o el lenguaje de meta marcado. A través el uso de complementos especiales y la configuración respectivo, los más (Seleccionar todo, Copiar) y pegarlo en un archivo llamado iris.csv. Puedes nombrarlo como quieras, excepto que la extensión debe ser .csv.
Ahora, inicializa la biblioteca y carga los datos.
const KNN = require('ml-knn');
const csv = require('csvtojson');
const prompt = require('prompt');
let knn;
const csvFilePath = 'iris.csv'; // Data
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 = [];
Los nombres de los encabezadosConcepto de Encabezados¿Qué son los Encabezados?Los Encabezados, además conocidos como headers en inglés, son una parte fundamental del diseño de cualquier web, dado que consiste en la parte principal que se ve de esta al acceder, la parte de arriba de cualquier página. El lugar más visible y al que todos los usuarios que visitan un lugar de Internet acceden cuando entran en él, pudiendo tener así una imagen rápida más se utilizan para la visualización y la comprensión. Se quitarán más adelante.
Además, seperationSize se utiliza para dividir los datos en conjuntos de datos de formación y de prueba.
Hemos importado el paquete csvto.json, y ahora vamos a usar su método fromFile para cargar los datos. (Ya que nuestros datos no tienen una fila de encabezado, estamos proporcionando nuestros propios nombres de encabezado.)
csv({noheader: true, headers: names})
.fromFile(csvFilePath)
.on('json', (jsonObj) => {
data.push(jsonObj); // Push each object to data Array
})
.on('done', (error) => {
seperationSize = 0.7 * data.length;
data = shuffleArray(data);
dressData();
});
Estamos empujando cada fila a la variable de dates, y cuando el proceso ha terminado, estamos ajustando el seperationSize a 0.7 veces el número de muestras en nuestro conjunto de datos. Ten en cuenta que, si el tamaño de las muestras de capacitación es demasiado pequeño, es posible que el clasificador no funcione tan bien como lo haría con un conjunto más grande.
Dado que nuestro conjunto de datos está ordenado con respecto a los tipos (console.log para confirmar), la función shuffleArray se utiliza para, barajar el conjunto de datos para permitir la división. (Si no barajas, puedes terminar con un modelo que funcione bien para las dos primeras clases, pero que falle con la tercera.)
Así es como se define.
/**
* https://stackoverflow.com/a/12646864
* Ordenar al azar los elementos de la matriz en el lugar.
* Usando el algoritmo de barajar de Durstenfeld.
*/
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;
}
Datos del Vestido (una vez más)
Nuestros datos están organizados de la siguiente manera:
{
sepalLength: ‘5.1’,
sepalWidth: ‘3.5’,
petalLength: ‘1.4’,
petalWidth: ‘0.2’,
type: ‘Iris-setosa’
}
Hay dos cosas que necesitamos hacer con nuestros datos antes de entregarlos al clasificador kNN:
- Gira los valores de la cadena a flotantes. (parseFloat)
- Convierte el tipo en clases numeradas.
function dressData() {
/**
* Hay tres tipos diferentes de flores de Iris que este conjunto
*de datos clasificados:
*
* 1. Iris Setosa (Iris-setosa)
* 2. Iris Versicolor (Iris-versicolor)
* 3. Iris Virginica (Iris-virginica)
*
* Vamos a cambiar estas clases de Strings a números.
* Tal que, un valor de tipo igual a
* 0 significaría setosa,
* 1 significaría versicolor, y
* 3 significaría virginica
*/
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); // Convertir tipo (String) a tipo (Number)
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();
}
Si no estás familiarizado con los Sets, son como sus contrapartes matemáticas, ya que no pueden tener elementos duplicados, y sus elementos no tienen un índice. (A diferencia de los Arrays.)
Y pueden ser fácilmente convertidos a Arrays usando el operador de spread o usando el constructor de Set.
Entrena a tu modelo y luego pruébalo
function train() {
knn = new KNN(trainingSetX, trainingSetY, {k: 7});
test();
}
El método de entrenamiento toma dos argumentos obligatorios, los datos de entrada, como la longitud del pétalo, la anchura del pétalo, y su clase real, como el Iris-setosa, y así sucesivamente. También toma un parámetro opcional de opciones, que es sólo un objeto JS que se puede pasar para ajustar los parámetros internos del algoritmo. Estamos pasando el valor de k como una opción. El valor por defecto de k es 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 sea otra cosa.)
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();
}
El error se calcula de la siguiente manera. Usamos el humilde bucle for para hacer un bucle sobre el conjunto de datos, y ver si la salida pronosticada no es igual a la salida real. Es una clasificación errónea.
function error(predicted, expected) {
let misclassifications = 0;
for (var index = 0; index < predicted.length; index++) {
if (predicted[index] !== expected[index]) {
misclassifications++;
}
}
return misclassifications;
}
(Opcional) Comenzar a predecir
Es hora de tener algunas indicaciones y predicciones.
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)}`);
}
});
}
Siéntete libre de omitir este paso, si no desea probar el modelo en una nueva entrada.
¡Todo terminado!
Si tú seguiste todos los pasos, así es como debería verse tu indexUn index o índice es generalmente un directorio en un orden específico que se usa con fines de orientación. En términos de motores de búsqueda, un índice es la lista de páginas web que es emitido por el motor de búsqueda en respuesta a una solicitud de búsqueda del usuario. Información general La lista que se muestra posteriormente de introducir una solicitud de búsqueda específica se llama SERPs (Search Engine más.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;
}
Ejecuta el nodo index.js. Debería mostrarte esto en pantalla:
$ node index.js Test Set Size = 45 and number of Misclassifications = 2 prompt: Sepal Length: 1.7 prompt: Sepal Width: 2.5 prompt: Petal Length: 0.5 prompt: Petal Width: 3.4 With 1.7,2.5,0.5,3.4 -- type = 2
Bien hecho. Ese es tu algoritmo kNN en el trabajo.
Un aspecto enorme del algoritmo kNN es el valor de k, y se le llama hiperparámetro. Los hiperparámetros son un, «tipo de parámetros que no pueden ser aprendidos directamente del proceso de entrenamiento regular». Estos parámetros expresan propiedades de «nivel superior» del modelo, como su complejidad o la rapidez con la que debe aprenderse. Se llaman «hiperparámetros».





