В этой статье объясняется концепция целевого кодирования, его значение в разработке функций и реализации кода.

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

Случаи использования целевого кодирования

Целевое кодирование отлично подходит для:

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

Функции, ориентированные на предметную область. Исходя из предыдущего опыта, вы можете предположить, что категориальная функция должна быть важной, даже если она имеет низкую оценку с помощью метрики функции. Целевое кодирование может помочь выявить истинную информативность функции.

Реализация кода целевой кодировки

Мы изучим набор данных о ценах на жилье ames, чтобы понять применение целевого кодирования.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
import warnings
from category_encoders import MEstimateEncoder
from sklearn.model_selection import cross_val_score
from xgboost import XGBRegressor

# Set Matplotlib defaults
plt.style.use("seaborn-whitegrid")
plt.rc("figure", autolayout=True)
plt.rc(
    "axes",
    labelweight="bold",
    labelsize="large",
    titleweight="bold",
    titlesize=14,
    titlepad=10,
)
warnings.filterwarnings('ignore')


# Model scoring
def score_dataset(X, y, model=XGBRegressor()):
    # Label encoding for categoricals
    for colname in X.select_dtypes(["category", "object"]):
        X[colname], _ = X[colname].factorize()
    # Metric for Housing competition is RMSLE (Root Mean Squared Log Error)
    score = cross_val_score(
        model, X, y, cv=5, scoring="neg_mean_squared_log_error",
    )
    score = -1 * score.mean()
    score = np.sqrt(score)
    return score


df = pd.read_csv("ames.csv")

Приведенный выше код — это тот, который мы использовали в предыдущей части PCA. Выполняется оценка модели, и в этом случае также используется RMSLE . Давайте выберем, к каким функциям можно применить целевое кодирование. Категорические объекты с большим количеством категорий (высокая кардинальность) часто являются хорошими кандидатами.

df.select_dtypes(["object"]).nunique()


MSSubClass       16
MSZoning          7
Street            2
Alley             3
LotShape          4
LandContour       4
Utilities         3
LotConfig         5
LandSlope         3
Neighborhood     28
Condition1        9
Condition2        8
BldgType          5
HouseStyle        8
OverallQual      10
OverallCond       9
RoofStyle         6
RoofMatl          8
Exterior1st      16
Exterior2nd      17
MasVnrType        5
ExterQual         4
ExterCond         5
Foundation        6
BsmtQual          6
BsmtCond          6
BsmtExposure      5
BsmtFinType1      7
BsmtFinType2      7
Heating           6
HeatingQC         5
CentralAir        2
Electrical        6
KitchenQual       5
Functional        8
FireplaceQu       6
GarageType        7
GarageFinish      4
GarageQual        6
GarageCond        6
PavedDrive        3
PoolQC            5
Fence             5
MiscFeature       6
SaleType         10
SaleCondition     6
dtype: int64

Здесь функциями с высокой кардинальностью являются Neighborhood, MSSubClass, Exterior2nd, Exterior1st и SaleType. Теперь, чтобы проверить количество категорий одной из этих функций (скажем, SaleType), это код.

df["SaleType"].value_counts()

WD       2536
New       239
COD        87
ConLD      26
CWD        12
ConLI       9
ConLw       8
Oth         7
Con         5
VWD         1
Name: SaleType, dtype: int64

К объекту применяется целевое кодирование. Теперь, чтобы избежать переобучения, нам нужно подогнать кодировщик к данным, взятым из обучающего набора.

# Encoding split
X_encode = df.sample(frac=0.20, random_state=0)
y_encode = X_encode.pop("SalePrice")

# Training split
X_pretrain = df.drop(X_encode.index)
y_train = X_pretrain.pop("SalePrice")

Применение целевого кодирования к выбору категориальных признаков. В этом случае используется параметр сглаживания m=1.

# Create the MEstimateEncoder
# Choose a set of features to encode and a value for m
encoder = MEstimateEncoder(
    cols=["Neighborhood"],
    m=1.0,
)


# Fit the encoder on the encoding split
encoder.fit(X_encode, y_encode)


# Encode the training split
X_train = encoder.transform(X_pretrain, y_train)
feature = encoder.cols

plt.figure(dpi=90)
ax = sns.distplot(y_train, kde=True, hist=False)
ax = sns.distplot(X_train[feature], color='r', ax=ax, hist=True, kde=False, norm_hist=True)
ax.set_xlabel("SalePrice");

Показатель RMSLE закодированного набора данных по сравнению с базовым набором данных.

X = df.copy()
y = X.pop("SalePrice")
score_base = score_dataset(X, y)
score_new = score_dataset(X_train, y_train)

print(f"Baseline Score: {score_base:.4f} RMSLE")
print(f"Score with Encoding: {score_new:.4f} RMSLE")


Baseline Score: 0.1428 RMSLE
Score with Encoding: 0.1402 RMSLE 

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

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

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

# Try experimenting with the smoothing parameter m
# Try 0, 1, 5, 50
m = 5

X = df.copy()
y = X.pop('SalePrice')

# Create an uninformative feature
X["Count"] = range(len(X))
X["Count"][1] = 0  # actually need one duplicate value to circumvent error-checking in MEstimateEncoder

# fit and transform on the same dataset
encoder = MEstimateEncoder(cols="Count", m=m)
X = encoder.fit_transform(X, y)

# Results
score =  score_dataset(X, y)
print(f"Score: {score:.4f} RMSLE")

Score: 0.0291 RMSLE
plt.figure(dpi=90)
ax = sns.distplot(y, kde=True, hist=False)
ax = sns.distplot(X["Count"], color='r', ax=ax, hist=True, kde=False, norm_hist=True)
ax.set_xlabel("SalePrice");

На этот раз RMSLE улучшился, и график распределения также хорошо подходит по сравнению с предыдущим случаем.

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

Единственная причина, по которой это сработало, заключается в том, что мы обучили XGBoost на том же наборе, который использовали для обучения кодировщика. Если бы вместо этого мы использовали удерживаемый набор, ни одна из этих «фальшивых» кодировок не передалась бы в обучающие данные.

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

Это конец всей серии курсов Feature Engineering от Kaggle. Часть целевой кодировки находится здесь.

Просмотрите эту записную книжку и поэкспериментируйте, чтобы лучше понять Feature Engineering. Это даст возможность опробовать последние наборы данных.

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