В реальной жизни полученные необработанные данные редко имеют формат, который мы можем взять и использовать непосредственно для наших моделей машинного обучения. Следовательно, необходима некоторая предварительная обработка, чтобы привести данные к нужному формату, выбрать информативные данные или уменьшить их размерность, чтобы иметь возможность извлечь из данных максимальную пользу. В этом посте мы поговорим о кодировании, чтобы иметь возможность использовать категориальные данные в качестве функций для наших моделей машинного обучения, типах кодирования и когда они подходят. Другие методы предварительной обработки для масштабирования объектов, выбора объектов и уменьшения размеров — темы для отдельного поста… Давайте начнем с кодирования!

Кодирование категориальных данных

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

Затем мы должны преобразовать данные, содержащие категориальные переменные, в числа, прежде чем мы сможем обучить модель ML. Это называется кодированием. Двумя наиболее популярными методами кодирования являются порядковое кодирование и горячее кодирование.

  • Порядковое кодирование: этот метод используется для кодирования категориальных переменных, имеющих естественный ранговый порядок. Бывший. хорошо, очень хорошо, отлично можно закодировать как 1,2,3.

  • Горячее кодирование: этот метод используется для кодирования категориальных переменных, которые не имеют естественного рангового порядка. Бывший. Мужчина или женщина не имеют никакого порядка между собой.

Порядковое кодирование

В этом методе каждой категории присваивается целочисленное значение. Бывший. Майами — 1, Сидней — 2, а Нью-Йорк — 3. Однако важно понимать, что это ввело порядковый номер в данные, которые модели ML попытаются использовать для поиска взаимосвязей в данных. Следовательно, использование этих данных там, где не существует порядкового отношения (ранжирование между категориальными переменными), не является хорошей практикой. Возможно, как вы уже поняли, пример, который мы только что использовали для городов, на самом деле не очень хорошая идея. Потому что между Майами, Сиднеем и Нью-Йорком нет никакой ранговой связи. В этом случае кодировщик One-Hot будет лучшим вариантом, который мы увидим в следующем разделе. Давайте создадим лучший пример для порядкового кодирования.

Трансформация порядкового кодирования доступна в библиотеке scikit-learn. Итак, давайте воспользуемся классом OrdinalEncoder для создания небольшого примера:

# example of a ordinal encoding
import numpy as np
import pandas as pd
from sklearn.preprocessing import OrdinalEncoder

# define data
data = np.asarray([['good'], ['very good'], ['excellent']])
df = pd.DataFrame(data, columns=["Rating"],  index=["Rater 1", "Rater 2", "Rater 3"])
print("Data before encoding:")
print(df)

# define ordinal encoding
encoder = OrdinalEncoder()

# transform data
df["Encoded Rating"] = encoder.fit_transform(df)
print("\nData after encoding:")
print(df)
Data before encoding:
            Rating
Rater 1       good
Rater 2  very good
Rater 3  excellent

Data after encoding:
            Rating  Encoded Rating
Rater 1       good             1.0
Rater 2  very good             2.0
Rater 3  excellent             0.0

В этом случае кодировщик присвоил целочисленные значения в алфавитном порядке, как в случае с текстовыми переменными. Хотя обычно нам не нужно явно определять порядок категорий, поскольку алгоритмы машинного обучения в любом случае смогут извлечь взаимосвязь, для этого примера мы можем определить явный порядок категорий, используя переменную категорий OrdinalEncoder.

import numpy as np
import pandas as pd
from sklearn.preprocessing import OrdinalEncoder

# define data
data = np.asarray([['good'], ['very good'], ['excellent']])
df = pd.DataFrame(data, columns=["Rating"], index=["Rater 1", "Rater 2", "Rater 3"])
print("Data before encoding:")
print(df)

# define ordinal encoding
categories = [['good', 'very good', 'excellent']]
encoder = OrdinalEncoder(categories=categories)

# transform data
df["Encoded Rating"] = encoder.fit_transform(df)
print("\nData after encoding:")
print(df)
Data before encoding:
            Rating
Rater 1       good
Rater 2  very good
Rater 3  excellent

Data after encoding:
            Rating  Encoded Rating
Rater 1       good             0.0
Rater 2  very good             1.0
Rater 3  excellent             2.0

Кодировка этикетки

Класс LabelEncoder из scikit-learn используется для кодирования целевых меток в наборе данных. На самом деле он делает то же самое, что и OrdinalEncoder, однако ожидает только одномерного ввода, что очень удобно при кодировании целевых меток в наборе данных.

Горячее кодирование

Как мы упоминали ранее, для категориальных данных, в которых нет порядковых отношений, порядковое кодирование не является подходящим методом, поскольку оно приводит к тому, что модель ищет отношения естественного порядка в категориальных данных, которые на самом деле не существуют, что может ухудшить производительность модели.

Здесь в игру вступает кодировка One-Hot. Этот метод работает путем создания нового столбца для каждой уникальной категориальной переменной в данных и представления наличия этой категории с использованием двоичного представления (0 или 1). Глядя на предыдущий пример:

Простая таблица преобразуется в следующую таблицу, в которой у нас есть новый столбец, представляющий каждую уникальную категориальную переменную (мужчину и женщину) и двоичное значение для отметки, если оно существует для этого.

Как и класс OrdinalEncoder, библиотека scikit-learn также предоставляет нам класс OneHotEncoder, который мы можем использовать для кодирования категориальных данных. Давайте используем его для кодирования простого примера:

from sklearn.preprocessing import OneHotEncoder

# define data
data = np.asarray([['Miami'], ['Sydney'], ['New York']])
df = pd.DataFrame(data, columns=["City"], index=["Alex", "Joe", "Alice"])
print("Data before encoding:")
print(df)

# define onehot encoding
categories = [['Miami', 'Sydney', 'New York']]
encoder = OneHotEncoder(categories='auto', sparse=False)

# transform data
encoded_data = encoder.fit_transform(df)

#fit_transform method return an array, we should convert it to dataframe
df_encoded = pd.DataFrame(encoded_data, columns=encoder.categories_, index= df.index)
print("\nData after encoding:")
print(df_encoded)
Data before encoding:
           City
Alex      Miami
Joe      Sydney
Alice  New York

Data after encoding:
      Miami New York Sydney
Alex    1.0      0.0    0.0
Joe     0.0      0.0    1.0
Alice   0.0      1.0    0.0

Как мы видим, кодировщик сгенерировал новый столбец для каждой уникальной категориальной переменной и присвоил 1, если она существует для этого конкретного образца, и 0, если ее нет. Это мощный метод кодирования непорядковых категориальных данных. Однако у него также есть свои недостатки… Как вы можете себе представить, для набора данных со многими уникальными категориальными переменными однократное горячее кодирование приведет к огромному набору данных, потому что каждая переменная должна быть представлена ​​новым столбцом. Например, если бы у нас был столбец/функция с 10 000 уникальных категориальных переменных (высокая кардинальность), однократное кодирование привело бы к 10 000 дополнительных столбцов, что привело бы к очень разреженной матрице и значительному увеличению потребления памяти и вычислительных затрат (что также называется проклятие размерности). Для работы с категориальными функциями с высокой кардинальностью мы можем использовать целевое кодирование…

Целевое кодирование

Целевое кодирование или также называемое средним кодированием — это метод, при котором количество вхождений категориальной переменной учитывается вместе с целевой переменной для кодирования категориальных переменных в числовые значения. По сути, это процесс, в котором мы заменяем категориальную переменную средним значением целевой переменной. Мы можем объяснить это лучше, используя простой пример набора данных…

Сгруппируйте таблицу для каждой категориальной переменной, чтобы рассчитать ее вероятность для цели = 1:

Затем мы берем эти вероятности, которые мы рассчитали для цели = 1, и используем их для кодирования данной категориальной переменной в наборе данных:

Подобно порядковому кодированию и горячему кодированию, мы можем использовать класс TargetEncoder, но на этот раз мы импортируем его из библиотеки category_encoders:

from category_encoders import TargetEncoder

# define data
fruit = ["Apple", "Banana", "Banana", "Tomato", "Apple", "Tomato", "Apple", "Banana", "Tomato", "Tomato"]
target = [1, 0, 0, 0, 1, 1, 0, 1, 0, 0]
df = pd.DataFrame(list(zip(fruit, target)), columns=["Fruit", "Target"])
print("Data before encoding:")
print(df)

# define target encoding
encoder = TargetEncoder(smoothing=0.1) #smoothing effect to balance categorical average vs prior.Higher value means stronger regularization.

# transform data
df["Fruit Encoded"] = encoder.fit_transform(df["Fruit"], df["Target"])
print("\nData after encoding:")
print(df)
Data before encoding:
    Fruit  Target
0   Apple       1
1  Banana       0
2  Banana       0
3  Tomato       0
4   Apple       1
5  Tomato       1
6   Apple       0
7  Banana       1
8  Tomato       0
9  Tomato       0

Data after encoding:
    Fruit  Target  Fruit Encoded
0   Apple       1       0.666667
1  Banana       0       0.333333
2  Banana       0       0.333333
3  Tomato       0       0.250000
4   Apple       1       0.666667
5  Tomato       1       0.250000
6   Apple       0       0.666667
7  Banana       1       0.333333
8  Tomato       0       0.250000
9  Tomato       0       0.250000

Мы получили ту же таблицу, которую рассчитали вручную сами…

Преимущества целевой кодировки

Целевое кодирование — это простой и быстрый метод, который не добавляет дополнительной размерности набору данных. Следовательно, это хороший метод кодирования для набора данных, включающего функции с высокой кардинальностью (уникальные категориальные переменные более 10 000).

Недостатки целевой кодировки

Целевое кодирование использует распределение целевой переменной, что может привести к переоснащению и утечке данных. Утечка данных в том смысле, что мы используем целевые классы для кодирования функции, может привести к предвзятому отображению функции. Вот почему существует параметр сглаживания при инициализации класса. Этот параметр помогает нам уменьшить эту проблему (в нашем примере выше мы намеренно установили его на очень маленькое значение, чтобы получить те же результаты, что и при ручном расчете).

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

Если вам понравился этот контент, не стесняйтесь следовать за мной для получения дополнительных бесплатных руководств и курсов по машинному обучению!