Экскурсия по методам преобразования признаков

Согласно исследованию Gartner, 87% проектов по науке о данных никогда не запускаются в производство. И снова исследования показывают, что подготовка набора данных для модели — самая трудоемкая задача (80%). Кажется, что самая ответственная и сложная часть проекта — это подготовительная часть. Здесь вложено много усилий, потрачено время, но результат зачастую недостаточно хорош для запуска в производство. По словам Педро Домингоса, самое главное в модели машинного обучения — это функции. Поэтому мы должны быть очень осторожны при работе с функциями, чтобы мы могли добиться успеха на этапе предварительной обработки и проекта в целом.

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

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

Зачем трансформировать?

  • Для правильной работы моделей необходимо оцифровать категориальные признаки. Это называется кодированием.
  • Масштаб между функциями в наборе данных может сильно отличаться друг от друга (или они могут иметь разные единицы измерения). Например, в то время как функция «Возраст» варьируется от 0 до 100, «Цена автомобиля» может варьироваться от 0 до 1000000. Эти различия масштабов влияют на некоторые методы машинного обучения, поэтому нормализация разницы будет способствовать успеху модели.
  • Такие модели, как KNN и SVM, являются алгоритмами, основанными на расстоянии, что означает, что расстояние между точками используется для получения кластеров или для выявления сходства. Расстояние до немасштабированных объектов также будет немасштабированным и будет вводить модель в заблуждение. Кроме того, немасштабированные данные негативно влияют на модели, использующие оптимизацию градиентного спуска, такие как линейная регрессия, логистическая регрессия или нейронные сети. На коэффициенты линейных моделей также влияют немасштабированные признаки. (Вообще нам не нужно масштабировать объекты в ансамблевых методах, так как глубина, вероятно, не изменится.)
  • Преобразование уменьшает влияние выбросов, поскольку изменчивость уменьшается за счет масштабирования.
  • Это улучшает производительность модели в отношении нелинейной связи между целевым элементом и независимым элементом.
  • Некоторые модели машинного обучения основаны на предположении, что функции распределены нормально. Однако в реальных задачах данные обычно не распределяются нормально. В этом случае мы применяем преобразования, чтобы приблизить эти искаженные данные к нормальному распределению, чтобы модели могли давать лучшие результаты.

Масштабирование

Мин Макс Скалер

Он масштабирует значения от 0 до 1 (по умолчанию). В случаях по умолчанию минимальное значение в ряду будет равно нулю. Если мы не хотим, чтобы минимальное значение равнялось нулю, мы также можем определить другой диапазон.

x_scaled = (x-x_min) / (x_max-x_min)

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
x_scaled = scaler.fit_transform(x)

Нормализация (диапазон [0,1]) важна, если диапазон каждого признака сильно отличается друг от друга. И не нужно предполагать, что распределение признаков нормальное. Это может увеличить переоснащение.

Стандартный масштабатор

Также называется нормализацией Z-оценки. Он масштабирует значения между двумя диапазонами стандартных отклонений, изменяет размеры значений в диапазоне 1 стандартного отклонения и делает медиану равной 0. Этот метод предполагает, что функция имеет нормальное распределение. Это помогает уменьшить переоснащение при правильном использовании.

x_scaled =x-среднее/стандартное значение

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
x_scaled = scaler.fit_transform(x)

Скалер MaxAbs

Все значения функции делятся на абсолютное максимальное значение этой функции. Таким образом, диапазон становится [-1,1]. Если мы хотим сохранить 0 значений как 0, мы можем использовать этот метод.

from sklearn.preprocessing import MaxAbsScaler
scaler = MaxAbsScaler()
df_scaled = scaler.fit_transform(df)

Надежный скейлер

Когда мы выполняем операцию масштабирования с постоянными значениями (среднее, максимальное значение и т. д.), операция становится уязвимой для значений выбросов. Если в данных много выбросов, масштабирование по IQR может обеспечить более надежное распределение. Он масштабирует значения между медианой 0.

x_scaled = (x-медиана)/IQR = (x-Q1)/(Q3-Q1)

from sklearn.preprocessing import RobustScaler
scaler = RobustScaler()
x_scaled = scaler.fit_transform(x)

Квантильный преобразователь масштабирования

Он преобразует распределение признаков в нормальное распределение. Таким образом, он также заботится о выбросах. Он использует кумулятивную функцию распределения. Лучше использовать этот масштабатор для нелинейных отношений, потому что он может нарушить линейные отношения при масштабировании и преобразовании распределения. Он масштабирует значения в диапазоне от 0 до 1.

from sklearn.preprocessing import QuantileTransformer
scaler = QuantileTransformer()
x_scaled = scaler.fit_transform(x)

Преобразования Гаусса

Многие модели машинного обучения работают лучше всего, если функции имеют распределение Гаусса. Существует множество методов преобразования признаков в нормальное распределение.

Я буду использовать приведенную ниже функцию для построения гистограммы и распределения Q-Q.

Графики Q-Q используются для сравнения двух распределений. Если бы два распределения были идентичными, то этот график был бы линией непосредственно на y=x. В нашем случае можно сказать, что если все точки лежат на прямой, то они распределены совершенно нормально.

Преобразование журнала

Преобразование журнала является одним из наиболее часто используемых методов преобразования Гаусса. Журнал каждого значения берется в функции, что является хорошим способом работы с большими числами (логарифм 1 000 000 - это всего 6). Таким образом, снижается влияние как высоких, так и низких значений функций.

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

x_log = np.log(x)

Показанная ниже функция немного смещена вправо (верхние графики). После логарифмического перехода лучше в точке распределения Гаусса.

Взаимное преобразование

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

Давайте используем обратное преобразование для вышеуказанной функции.

x_recip = 1 / data["sepal width (cm)"]
plot_gauss(x_recip)

Квадратная трансформация

Обычно он применяется к данным с перекосом влево.

Давайте сгенерируем левосторонние данные для изучения.

plot_gauss(x)
plot_gauss(x**(2))

Преобразование квадратного корня

Он действителен только для положительных чисел и обычно применяется к данным с перекосом вправо.

Давайте сгенерируем данные с асимметрией вправо для исследования (просто установите положительное значение асимметрии в приведенном выше коде генерации данных).

plot_gauss(x)
plot_gauss(x**(1/2))

Силовые преобразования

Может использоваться, когда есть гетероскедастичность, которая вызывает беспокойство в линейных отношениях. Это означает, что дисперсия остатков не постоянна (значит, в дисперсии есть закономерность).

Преобразование мощности делает данные более гауссовыми. Эти методы используют параметр с именем лямбда. Этот параметр помогает уменьшить асимметрию и стабилизировать дисперсию.

Преобразование Бокса-Кокса

Это входит в понятие силовых преобразований. Данные должны быть положительными. Лямбда, λ — это значение от -5 до 5. Следует выбрать оптимальное значение лямбда (например, при настройке гиперпараметров).

T(Y) = (Y exp(λ)-1)/λ

Мы также можем использовать scipy.stats для расчета лямбда.

x_boxcox, lda = stat.boxcox(x)
print(lda)
#0.7964531473656952

Преобразование Йео-Джонсона

Метод преобразования степени, если данные содержат нулевые или отрицательные значения.

from sklearn.preprocessing import PowerTransformer
transformer = PowerTransformer(method='yeo-johnson')
data = transformer.fit_transform(data)

Нормализатор единичного вектора или масштабатор

Интересно, что этот метод нормализует или масштабирует строки.

Биннинг

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

#Numerical Feature
df['Age_bin'] = pd.cut(df['Age'], bins=[0,30,70,100], labels=["Young", "Mid", "Old"])
#Out:
0      Young
1        Mid
2      Young
3        Mid
4        Mid
       ...  
886    Young
887    Young
888    Young
889    Young
890      Mid
Name: Age_bin, Length: 891, dtype: category
Categories (3, object): ['Young' < 'Mid' < 'Old']
#Categorical Feature
conditions = [
    data['Item'].str.contains('Bmw'),
    data['Item'].str.contains('Hp'),
    data['Item'].str.contains('Iphone'),
    data['Item'].str.contains('Audi')]
choices = ['Car', 'Computer', 'Phone', 'Car']
data['Item_Group'] = np.select(conditions, choices, default='Other')

Биннинг обеспечивает улучшение переобучения, но при этом теряется некоторая информация. При группировке по категорийным данным лучше создать отдельную группу «другие», объединив группы с низким процентом в общем итоге (0,01%).

Кодировщики

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

Целочисленное/меточное кодирование

Каждой уникальной группе в объекте присваивается номер. Между приведенными номерами и группами нет связи с информационной точки зрения.

from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
encoder.fit_transform(["Bmw","Mercedes","Bmw","Audi"])
#Out: array([1, 2, 1, 0])

Один горячий энкодер

Целочисленное значение, присвоенное уникальным группам, само по себе преобразуется в двоичное значение. Будет столько двоичных значений, сколько групп. Каждые данные принимают значение 1 в этом столбце для своей группы и 0 в других столбцах.

from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder()
encoder.fit_transform(x).toarray()
#Out: 
array([[0., 1.],
       [1., 0.],
       [1., 0.],
       ...,
       [1., 0.],
       [0., 1.],
       [0., 1.]])

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

Подсчет и частотное кодирование

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

Для этого мы можем использовать библиотеку feature_engine.

from feature_engine.encoding import CountFrequencyEncoder
encoder = CountFrequencyEncoder(encoding_method='frequency',variables=['Cabin'])
encoder.fit(df)
df_encoded = encoder.transform(df)

Среднее кодирование

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

from feature_engine.encoding import MeanEncoder
encoder = MeanEncoder(variables=['cabin'])
# fit the encoder
encoder.fit(X, y)
# transform the data
X_encoded = encoder.transform(X)
encoder.encoder_dict_
#Out:
{'cabin': {'A': 0.5294117647058824,
  'B': 0.7619047619047619,
  'C': 0.5633802816901409,
  'D': 0.71875,
  'E': 0.71875,
  'F': 0.6666666666666666,
  'G': 0.5,
  'T': 0.0,
  'n': 0.30484330484330485}}

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

Если мы сможем установить отношение порядка между категориальными значениями, то мы сможем выполнить порядковое кодирование. Например, рассмотрим ответ на вопрос опроса, варианты «никогда, иногда и всегда». В диапазоне [0,2] мы можем присвоить 0 для «никогда», 1 для «иногда» и 2 для «всегда».

Кодировщик веса доказательств

Мы можем объяснить WoE с точки зрения события. Событие означает, является ли пример действительным (например, человек «выжил» или, если не событие, «не выжил»). Затем мы вычисляем его, взяв натуральный логарифм отношения событий. Обратите внимание, что целевая функция должна быть двоичной.

WOE = ln (% событий / % отсутствия событий)

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

import category_encoders as ce
columns = [col for col in data.columns]
woe_encoder = ce.WOEEncoder(cols=columns)
x_encoded = woe_encoder.fit_transform(data[columns], y).add_suffix('_woe')

Кодирование отношения вероятностей

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

from sunbird.categorical_encoding import probability_ratio_encoding
probability_ratio_encoding(data, 'Cabin', 'Survived')

Кодирование хеширования

В этом методе категориальные переменные преобразуются в набор многомерных чисел. Однако, поскольку общее количество измерений будет меньше, чем у метода One Hot Encoding, метод хеширования можно попробовать в случае проблемы с высокой кардинальностью.

Мы можем ограничить количество измерений, установив аргумент n_component. Однако некоторая информация явно приносится в жертву из-за ограничения размерного пространства. Hashing Encoder по умолчанию использует алгоритм хеширования md5.

import category_encoders as ce
encoder=ce.HashingEncoder(cols='Cabin',n_components=4)

В Windows мы должны запустить Hash Encoder в основной функции, потому что он использует несколько процессов:

from category_encoders.hashing import HashingEncoder
def hash_encode(df_train, col, n = 4):
    encoder=HashingEncoder(cols=col,n_components=n)
    encoder.fit(df_train[col])
    x_encoded = encoder.transform(df_train[col])
    return x_encoded
from multiprocessing import Process, freeze_support
if __name__ == '__main__':
    freeze_support()
    x_endeod = hash_encode()

Заключение

Предварительная обработка данных — самая длинная и важная фаза проекта машинного обучения. Работа по преобразованию признаков также является одним из наиболее важных этапов этапа предварительной обработки. Кодирование, масштабирование или преобразование — в литературе и на практике описано множество методов и исследований. Я думаю, что очень важно иметь знания об этих методах и уметь чувствовать, где и какой из них может работать.

Читать далее…











Рекомендации

https://scikit-learn.org/stable/data_transforms.html

https://scikit-learn.org/stable/modules/preprocessing.html

https://scikit-learn.org/0.21/data_transforms.html

https://docs.scipy.org/doc/scipy/reference/stats.html

https://contrib.scikit-learn.org/category_encoders/



Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Присоединяйтесь к нашему сообществу Discord.