В этом посте мы собираемся обсудить категориальные функции в машинном обучении и методы обработки этих функций с использованием двух наиболее эффективных методов.
Категорические признаки
В машинном обучении функции можно разделить на две основные категории:
- Числовые характеристики (возраст, цена, площадь и т. д.)
- Категориальные признаки (пол, семейное положение, профессия и т.д.)
Все те признаки, которые состоят из определенного количества категорий, известны как категориальные признаки. Категориальные признаки можно разделить на два основных типа:
- Номинальный
- Порядковый номер
Номинальные функции – это функции, относящиеся к двум или более категориям без определенного порядка. Например, если пол имеет два значения, мужской и женский, его можно рассматривать как номинальный признак.
С другой стороны, порядковые функции имеют категории в определенном порядке. Например, если у нас есть функция с именем «Уровень», имеющая значения «высокий», «средний» и «низкий», она будет считаться порядковой функцией, потому что порядок здесь имеет значение.
Обработка категориальных признаков
Итак, первый вопрос, который возникает, заключается в том, почему нам нужно обрабатывать категориальные признаки отдельно? почему бы нам просто не передать их в качестве входных данных для нашей модели, как и числовые признаки? Ответ заключается в том, что, в отличие от людей, машины и, в частности, модели машинного обучения в данном случае не понимают текстовые данные. Нам нужно преобразовать текстовые значения в соответствующие числа, прежде чем вводить их в нашу модель.
Этот процесс преобразования категорий в числа называется кодированием. Двумя наиболее эффективными и широко используемыми методами кодирования являются:
- Кодировка этикетки
- Одно горячее кодирование
Кодировка ярлыка
Кодирование метки — это процесс присвоения числовой метки каждой категории объекта. Если N — количество категорий, всем значениям категории будет присвоен уникальный номер от 0 до N-1.
Если у нас есть функция с именем «Цвета», имеющая значения красный, синий, зеленый и желтый, ее можно преобразовать в числовое отображение следующим образом.
Category : Label "red" : 0 "blue" : 1 "green" : 2 "yellow" : 3
Примечание. Как мы видим здесь, метки, созданные для категорий, не нормализованы, т. е. не между 0 и 1. Из-за этого ограничения кодирование меток не следует использовать с линейными моделями, в которых величина признаков играет важную роль. Поскольку древовидные алгоритмы не требуют нормализации признаков, кодирование меток можно легко использовать с такими моделями, как:
- Деревья решений
- Случайный лес
- XGBoost
- СветGBM
Мы можем реализовать кодировку меток, используя класс LabelEncoder scikit-learn. Мы увидим реализацию в следующем разделе.
Одно горячее кодирование
Ограничение кодирования меток можно преодолеть путем бинаризации категорий, т. е. представления категорий, использующих только 0 и 1. Здесь мы представляем каждую категорию вектором размера N, где N — количество категорий в этой функции. Каждый вектор имеет один 1, а все остальные значения равны 0. Следовательно, это называется горячим кодированием.
Предположим, у нас есть столбец с именем температуры. Он имеет четыре значения: «Заморозка», «Холодный», «Теплый» и «Горячий». Каждая категория будет представлена следующим образом:
Category Encoded vector Freezing 0 0 0 1 Cold 0 0 1 0 Warm 0 1 0 0 Hot 1 0 0 0
Как вы можете видеть здесь, каждая категория представлена вектором длины 4, поскольку 4 — это количество уникальных категорий в функции. Каждый вектор имеет одну 1, а все остальные значения равны 0.
Поскольку горячее кодирование генерирует нормализованные функции, его можно использовать с линейными моделями, такими как:
- Линейная регрессия
- Логистическая регрессия
Теперь, когда у нас есть общее представление об обоих методах кодирования, давайте посмотрим на реализацию обоих из них на Python для лучшего понимания.
Реализация на Python
Прежде чем применять кодирование к категориальным функциям, важно обработать значения NaN. Простой и эффективный способ — рассматривать значения NaN как отдельную категорию. Делая это, мы удостоверяемся, что не теряем никакой важной информации.
Итак, шаги, которые мы выполняем при обработке категориальных признаков:
- Заполните значения NaN новыми категориями (например, NONE)
- Преобразование категорий в числовые значения с помощью кодирования меток для древовидных моделей и горячего кодирования для линейных моделей.
- Постройте модель, используя числовые и закодированные функции.
Мы будем использовать общедоступный набор данных под названием Cat in the Dat на kaggle. Ссылка здесь. Это проблема бинарной классификации, которая состоит из множества категориальных признаков.
Сначала мы создадим 5 складок для проверки, используя класс StratifiedKFold в scikit-learn. Этот вариант KFold используется для обеспечения одинакового соотношения целевых переменных в каждой кратности.
import pandas as pd from sklearn import model_selection #read training data df = pd.read_csv('../input/train.csv') #create column for kfolds and fill it with -1 df['kfold'] = -1 #randomize the rows df = df.sample(frac=1).reset_index(drop=True) #fetch the targets y = df['target'].values #initiatre StratifiedKFold class from model_selection kf = model_selection.StratifiedKFold(n_splits=5) #fill the new kfold column for f,(t_,v_) in enumerate(kf.split(X=df,y=y)): df.loc[v_,'kfold'] = f #save the new csv with kfold column df.to_csv('../input/train_folds.csv',index=False)
Кодировка ярлыка
Далее давайте определим функцию для запуска обучения и проверки для каждой складки. В этом примере мы будем использовать LabelEncoder со случайным лесом.
import pandas as pd from sklearn import ensemble from sklearn import metrics from sklearn import preprocessing def run(fold): #read training data with folds df = pd.read_csv('../input/train_folds.csv') #get all relevant features excluding id, target and kfold columns features = [feature for feature in df.columns if feature not in ['id','target','kfold']] #fill all nan values with NONE for feature in features: df.loc[:,feature] = df[feature].astype(str).fillna('NONE') #Label encoding the features for feature in features: #initiate LabelEncoder for each feature lbl = preprocessing.LabelEncoder() #fit the label encoder lbl.fit(df[feature]) #transform data df.loc[:,feature] = lbl.transform(df[feature]) #get training data using folds df_train = df[df['kfold']!=fold].reset_index(drop=True) #get validation data using folds df_valid = df[df['kfold']==fold].reset_index(drop=True) #get training features X_train = df_train[features].values #get validation features X_valid = df_valid[features].values #initiate Random forest model model = ensemble.RandomForestClassifier(n_jobs=-1) #fit the model on train data model.fit(X_train,df_train['target'].values) #predict the probabilities on validation data valid_preds = model.predict_proba(X_valid)[:,1] #get auc-roc score auc = metrics.roc_auc_score(df_valid['target'].values,valid_preds) #print AUC score for each fold print(f'Fold ={fold}, AUC = {auc}')
Наконец, давайте вызовем этот метод, чтобы выполнить метод запуска для каждой складки.
if __name__=='__main__': for fold_ in range(5): run(fold_)
Выполнение этого кода даст результат, как показано ниже.
Fold =0, AUC = 0.7163772816343564 Fold =1, AUC = 0.7136206487083182 Fold =2, AUC = 0.7171801474337066 Fold =3, AUC = 0.7158938474390842 Fold =4, AUC = 0.7186004462481813
Здесь следует отметить, что мы не выполняли настройку гиперпараметров модели случайного леса. Вы можете настроить параметры, чтобы повысить точность проверки. Еще одна вещь, которую следует упомянуть в приведенном выше коде, заключается в том, что мы используем показатель AUC ROC в качестве метрики для проверки. Это связано с тем, что целевые значения искажены, и такие показатели, как Точность, не дадут нам правильных результатов.
Одно горячее кодирование
Теперь давайте посмотрим на реализацию одного горячего кодирования с логистической регрессией.
Ниже приведена модифицированная версия метода run для этого подхода.
import pandas as pd from sklearn import linear_model from sklearn import metrics from sklearn import preprocessing def run(fold): #read training data with folds df = pd.read_csv('../input/train_folds.csv') #get all relevant features excluding id, target and folds columns features = [feature for feature in df.columns if feature not in ['id','target','kfold']] #fill all nan values with NONE for feature in features: df.loc[:,feature] = df[feature].astype(str).fillna('NONE') #get training data using folds df_train = df[df['kfold']!=fold].reset_index(drop=True) #get validation data using folds df_valid = df[df['kfold']==fold].reset_index(drop=True) #initiate OneHotEncoder from sklearn ohe = preprocessing.OneHotEncoder() #fit ohe on training+validation features full_data = pd.concat([df_train[features],df_valid[features]],axis=0) ohe.fit(full_data[features]) #transform training data X_train = ohe.transform(df_train[features]) #transform validation data X_valid = ohe.transform(df_valid[features]) #initiate logistic regression model = linear_model.LogisticRegression() #fit the model on train data model.fit(X_train,df_train['target'].values) #predict the probabilities on validation data valid_preds = model.predict_proba(X_valid)[:,1] #get auc-roc score auc = metrics.roc_auc_score(df_valid['target'].values,valid_preds) #print AUC score for each fold print(f'Fold ={fold}, AUC = {auc}')
Метод зацикливания всех складок остается прежним.
if __name__=='__main__': for fold_ in range(5): run(fold_)
Вывод этого кода будет таким, как показано ниже:
Fold =0, AUC = 0.7872262099199782 Fold =1, AUC = 0.7856877416085041 Fold =2, AUC = 0.7850910855093067 Fold =3, AUC = 0.7842966593706009 Fold =4, AUC = 0.7887711592194284
Как мы видим здесь, простая логистическая регрессия дает нам приличную точность, просто применяя кодирование признаков для категориальных признаков.
Одно различие, которое следует отметить в реализации обоих методов, заключается в том, что LabelEncoder должен быть установлен для каждой категориальной функции отдельно, в то время как OneHotEncoder может быть установлен для всех функций вместе.
Вывод
В этом блоге я обсудил, что такое категориальные функции в машинном обучении, и почему важно обрабатывать эти функции. Мы также рассмотрели два наиболее важных метода кодирования категориальных признаков в числовые вместе с реализацией.
Надеюсь, я помог вам лучше понять затронутые здесь темы. Пожалуйста, дайте мне знать ваши отзывы в комментариях и хлопните, если вам понравилось. Здесь — это ссылка на мой профиль в Linkedin, если вы хотите подключиться.
Спасибо за чтение.:)