One-hot encoding вручную на JavaScript

One-hot encoding — это метод представления категориальных данных в виде бинарных векторов. Каждое уникальное значение категориальной переменной преобразуется в вектор, где все элементы равны 0, кроме одного, соответствующего текущему значению, который равен 1. Этот подход широко используется в машинном обучении и нейронных сетях, включая библиотеку Synaptic для JavaScript, где входные данные сети должны быть числовыми и нормализованными.

Преобразование категориальных данных в числовые векторы

Для ручного создания one-hot кодирования сначала необходимо определить множество уникальных категорий. Например, если есть массив цветов:

const colors = ["red", "green", "blue", "green", "red"];

Следующий шаг — формирование словаря уникальных значений:

const uniqueColors = [...new Set(colors)];
console.log(uniqueColors); // ["red", "green", "blue"]

Каждой категории присваивается индекс:

const colorIndex = {};
uniqueColors.forEach((color, idx) => {
    colorIndex[color] = idx;
});
console.log(colorIndex); // { red: 0, green: 1, blue: 2 }

Теперь можно создать функцию, которая преобразует категорию в one-hot вектор:

function oneHotEncode(value, categories) {
    const vector = new Array(categories.length).fill(0);
    const idx = categories.indexOf(value);
    if (idx !== -1) vector[idx] = 1;
    return vector;
}

Пример использования:

const encodedRed = oneHotEncode("red", uniqueColors);
console.log(encodedRed); // [1, 0, 0]

Обработка массивов данных

Для преобразования всего массива категориальных данных удобно использовать метод map:

const encodedColors = colors.map(color => oneHotEncode(color, uniqueColors));
console.log(encodedColors);
// [[1,0,0],[0,1,0],[0,0,1],[0,1,0],[1,0,0]]

Такой формат данных полностью совместим с входом нейронной сети Synaptic, где каждый элемент массива можно подать на соответствующий нейрон.

Интеграция с Synaptic

Библиотека Synaptic работает с входными и выходными данными в виде числовых массивов. Например, для создания сети с 3 входными нейронами, 4 скрытыми и 3 выходными можно использовать следующий код:

const synaptic = require('synaptic');
const { Layer, Network } = synaptic;

const inputLayer = new Layer(3);
const hiddenLayer = new Layer(4);
const outputLayer = new Layer(3);

inputLayer.project(hiddenLayer);
hiddenLayer.project(outputLayer);

const myNetwork = new Network({
    input: inputLayer,
    hidden: [hiddenLayer],
    output: outputLayer
});

Для обучения сети данные нужно подавать в формате, полученном после one-hot кодирования:

const trainingSet = [
    { input: oneHotEncode("red", uniqueColors), output: [1,0,0] },
    { input: oneHotEncode("green", uniqueColors), output: [0,1,0] },
    { input: oneHotEncode("blue", uniqueColors), output: [0,0,1] }
];

const trainer = new synaptic.Trainer(myNetwork);
trainer.train(trainingSet, {
    rate: 0.1,
    iterations: 2000,
    error: 0.005,
    shuffle: true
});

Преимущества ручного кодирования

  1. Контроль над процессом: каждый шаг можно адаптировать под специфические требования данных.
  2. Минимальные зависимости: нет необходимости использовать внешние библиотеки для кодирования.
  3. Простота отладки: структура one-hot векторов полностью прозрачна, легко выявить ошибки.

Оптимизация для больших наборов данных

При работе с большим количеством категорий имеет смысл использовать словари для быстрого поиска индекса категории вместо поиска через indexOf. Пример оптимизированной функции:

function oneHotEncodeFast(value, indexMap) {
    const vector = new Array(Object.keys(indexMap).length).fill(0);
    if (value in indexMap) vector[indexMap[value]] = 1;
    return vector;
}

Использование:

const encoded = oneHotEncodeFast("green", colorIndex);
console.log(encoded); // [0,1,0]

Этот метод значительно ускоряет преобразование массивов данных с тысячами записей.

Вывод

One-hot encoding вручную на JavaScript позволяет полностью контролировать процесс подготовки категориальных данных к обучению нейронных сетей в Synaptic. Такой подход обеспечивает гибкость, прозрачность и совместимость с форматом входных и выходных массивов сети. В сочетании с оптимизацией через словари можно эффективно обрабатывать большие объемы данных, не прибегая к сторонним библиотекам.