Как выполнить one-hot encoding для массива NumPy?

Что такое One-Hot Encoding: объяснение и примеры

One-Hot Encoding (OHE), или прямое кодирование, — это процесс преобразования категориальных признаков в числовой формат, который может быть использован моделями машинного обучения. Каждый уникальный категориальный признак представляется в виде бинарного вектора, где все элементы равны нулю, кроме одного, который равен единице и соответствует индексу данной категории.

Пример: Допустим, у нас есть категориальный признак «Тип кампании» со значениями [«Поиск», «Сеть», «Видео», «Поиск»]. После OHE он будет преобразован следующим образом:

  • «Поиск»: [1, 0, 0]
  • «Сеть»: [0, 1, 0]
  • «Видео»: [0, 0, 1]

Итоговый массив для [«Поиск», «Сеть», «Видео», «Поиск»] будет:

[[1, 0, 0],
 [0, 1, 0],
 [0, 0, 1],
 [1, 0, 0]]

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

Преимущества использования NumPy для One-Hot Encoding

NumPy (Numerical Python) — это фундаментальная библиотека для научных вычислений в Python. Ее основные преимущества при выполнении OHE:

  • Производительность: NumPy операции реализованы на C, что обеспечивает высокую скорость вычислений, особенно на больших массивах.
  • Эффективность памяти: NumPy предоставляет компактные структуры данных (ndarray) для хранения числовых данных.
  • Векторизация: Возможность выполнять операции над целыми массивами без явных циклов Python, что упрощает код и повышает скорость.
  • Интеграция: NumPy массивы являются стандартом де-факто для обмена данными между различными библиотеками машинного обучения и анализа данных (Scikit-learn, Pandas, TensorFlow, PyTorch).

Обзор библиотеки NumPy и ее основные функции

NumPy предоставляет мощный объект ndarray (N-мерный массив) и набор функций для работы с этими массивами. Ключевые функции, полезные для OHE:

  • np.array(): Создание массива NumPy.
  • np.zeros(): Создание массива, заполненного нулями.
  • np.ones(): Создание массива, заполненного единицами.
  • np.eye(): Создание единичной матрицы (идеально для OHE при известном количестве категорий).
  • np.unique(): Нахождение уникальных элементов в массиве.
  • shape: Атрибут массива, возвращающий его размерность.
  • Индексация и срезы: Мощные механизмы для доступа и модификации элементов массива.

Основные подходы к One-Hot Encoding с использованием NumPy

Существует несколько способов реализовать One-Hot Encoding, используя NumPy, как напрямую, так и в сочетании с другими библиотеками.

One-Hot Encoding с использованием np.eye()

Этот метод является одним из самых лаконичных, если у вас уже есть целочисленное представление категорий и известно общее количество уникальных категорий. Функция np.eye(N) создает единичную матрицу размером N x N. Затем, используя целочисленные метки категорий в качестве индексов строк, можно мгновенно получить OHE представление.

One-Hot Encoding с использованием np.zeros() и индексов

Более гибкий подход, который не требует предварительного знания всех категорий (хотя необходимо определить максимальное количество). Сначала создается массив нулей нужного размера (количество образцов x количество категорий). Затем, для каждого образца, в соответствующем столбце (индекс категории) устанавливается значение 1.

One-Hot Encoding с использованием sklearn.preprocessing.OneHotEncoder и NumPy массивов

Библиотека Scikit-learn предоставляет специализированный класс OneHotEncoder, который удобен для интеграции в пайплайны машинного обучения. Он может работать напрямую с NumPy массивами, автоматически определяя категории и выполняя преобразование. Этот подход также включает обработку неизвестных категорий и возможность вывода в виде разреженных матриц для экономии памяти.

Пошаговая реализация One-Hot Encoding в NumPy

Подготовка данных: создание и просмотр NumPy массива

Предположим, у нас есть данные о типах устройств, с которых пользователи посещали сайт:

import numpy as np

# Пример данных: ID пользователя и тип устройства (0: Desktop, 1: Mobile, 2: Tablet)
data: np.ndarray = np.array([
    [101, 0], 
    [102, 1], 
    [103, 0], 
    [104, 2], 
    [105, 1]
])

# Извлекаем столбец с категориальным признаком (тип устройства)
categorical_feature: np.ndarray = data[:, 1]
print(f"Исходный категориальный признак:\n{categorical_feature}")

# Определяем количество уникальных категорий
num_categories: int = len(np.unique(categorical_feature))
print(f"Количество уникальных категорий: {num_categories}") 
Реклама

Применение np.eye(): подробное объяснение с примерами кода

Метод np.eye() создает единичную матрицу. Если наши категории уже представлены целыми числами от 0 до N-1, мы можем использовать их как индексы строк этой матрицы.

import numpy as np

def one_hot_encode_eye(labels: np.ndarray, num_classes: int) -> np.ndarray:
    """Выполняет One-Hot Encoding с использованием np.eye().

    Args:
        labels: Одномерный массив NumPy с целочисленными метками категорий (от 0 до num_classes-1).
        num_classes: Общее количество уникальных категорий.

    Returns:
        Двумерный массив NumPy с One-Hot представлением.
    """
    return np.eye(num_classes, dtype=int)[labels]

# Данные из предыдущего шага
categorical_feature: np.ndarray = np.array([0, 1, 0, 2, 1])
num_categories: int = 3

# Применение функции
one_hot_encoded_eye: np.ndarray = one_hot_encode_eye(categorical_feature, num_categories)

print(f"One-Hot Encoding с помощью np.eye():\n{one_hot_encoded_eye}")

Результат:

One-Hot Encoding с помощью np.eye():
[[1 0 0]
 [0 1 0]
 [1 0 0]
 [0 0 1]
 [0 1 0]]

Этот метод очень эффективен, но требует, чтобы категории были представлены числами от 0 до num_classes - 1.

Применение np.zeros() и индексации: подробное объяснение с примерами кода

Этот метод более универсален, так как не зависит от строгой нумерации категорий с 0.

import numpy as np

def one_hot_encode_zeros(labels: np.ndarray, num_classes: int) -> np.ndarray:
    """Выполняет One-Hot Encoding с использованием np.zeros() и индексации.

    Args:
        labels: Одномерный массив NumPy с целочисленными метками категорий.
        num_classes: Общее количество уникальных категорий.

    Returns:
        Двумерный массив NumPy с One-Hot представлением.
    """
    num_samples: int = len(labels)
    # Создаем массив нулей размером (количество_образцов x количество_классов)
    one_hot: np.ndarray = np.zeros((num_samples, num_classes), dtype=int)

    # Используем расширенную индексацию для установки единиц
    # np.arange(num_samples) генерирует индексы строк [0, 1, 2, ...]
    # labels содержит индексы столбцов для каждой строки
    one_hot[np.arange(num_samples), labels] = 1
    return one_hot

# Данные
categorical_feature: np.ndarray = np.array([0, 1, 0, 2, 1])
num_categories: int = 3

# Применение функции
one_hot_encoded_zeros: np.ndarray = one_hot_encode_zeros(categorical_feature, num_categories)

print(f"One-Hot Encoding с помощью np.zeros():\n{one_hot_encoded_zeros}")

Результат: Идентичен предыдущему методу.

One-Hot Encoding с помощью np.zeros():
[[1 0 0]
 [0 1 0]
 [1 0 0]
 [0 0 1]
 [0 1 0]]

Этот метод требует явного указания количества классов, но более гибок в отношении значений labels.

Применение sklearn.preprocessing.OneHotEncoder: подробное объяснение с примерами кода

Scikit-learn предоставляет удобный и мощный инструмент для OHE.

import numpy as np
from sklearn.preprocessing import OneHotEncoder

# Исходные данные (могут быть и строковыми)
data_str: np.ndarray = np.array([['Desktop'], ['Mobile'], ['Desktop'], ['Tablet'], ['Mobile']])

# Создание и обучение кодировщика
# sparse_output=False для получения плотного NumPy массива
# handle_unknown='ignore' позволяет обрабатывать новые категории при предсказании (заполняя нулями)
encoder = OneHotEncoder(sparse_output=False, dtype=int, handle_unknown='ignore') 

# Обучаем кодировщик и трансформируем данные
one_hot_encoded_sklearn: np.ndarray = encoder.fit_transform(data_str)

print(f"One-Hot Encoding с помощью sklearn.preprocessing.OneHotEncoder:\n{one_hot_encoded_sklearn}")

# Посмотреть обнаруженные категории
print(f"Обнаруженные категории: {encoder.categories_}")

# Пример трансформации новых данных (с известной и неизвестной категорией)
new_data = np.array([['Mobile'], ['Desktop'], ['Wearable']]) # 'Wearable' - неизвестная категория
transformed_new_data = encoder.transform(new_data)
print(f"Трансформация новых данных:\n{transformed_new_data}")

Результат:

One-Hot Encoding с помощью sklearn.preprocessing.OneHotEncoder:
[[1 0 0]
 [0 1 0]
 [1 0 0]
 [0 0 1]
 [0 1 0]]
Обнаруженные категории: [array(['Desktop', 'Mobile', 'Tablet'], dtype='<U7')]
Трансформация новых данных:
[[0 1 0]
 [1 0 0]
 [0 0 0]]

OneHotEncoder из sklearn является наиболее предпочтительным вариантом для большинства задач машинного обучения благодаря своей гибкости, возможности интеграции в пайплайны и обработке неизвестных значений.

Продвинутые техники и оптимизация One-Hot Encoding в NumPy

Обработка неизвестных значений при One-Hot Encoding

При работе с реальными данными часто возникает ситуация, когда на этапе предсказания появляются категории, которых не было в обучающей выборке. sklearn.preprocessing.OneHotEncoder решает эту проблему с помощью параметра handle_unknown:

  • 'error' (по умолчанию): Выбрасывает ошибку при встрече с неизвестной категорией.
  • 'ignore': Кодирует неизвестную категорию вектором из нулей.
  • 'infrequent_if_exist': Позволяет объединять редкие категории в одну общую во время fit (требует доп. параметров min_frequency или max_categories), а затем обрабатывать неизвестные так же, как эту общую категорию.

При использовании np.eye или np.zeros необходимо вручную реализовать логику обработки неизвестных категорий, например, добавив дополнительный столбец для


Добавить комментарий