В этой статье объясняется концепция целевого кодирования, его значение в разработке функций и реализации кода.
Это последняя часть серии Разработка функций, которую я загружал в течение последних 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. Вы можете пожертвовать мне несколько чашек кофе, если вам нравится моя работа, и я могу ежедневно улучшать качество контента, продвигаясь вперед в этом писательском путешествии.