Подготовка признаков

Сырые данные редко готовы к обучению — их нужно привести в понятный модели вид.

Подготовка признаков (feature preprocessing) — приведение данных к виду, удобному для модели: масштабирование чисел и превращение категорий в числа.

Нормализация числовых признаков

Многие алгоритмы (kNN, k-means, нейросети) чувствительны к масштабу. Если возраст измеряется десятками, а зарплата — сотнями тысяч, признак с большими числами «перекричит» остальные. Лечение — привести все признаки к одному масштабу. Популярный способ — min-max нормализация: сжать значения в диапазон от 0 до 1 по формуле (x − min) / (max − min).

# Нормализуем два признака в диапазон [0, 1]
ages = [18, 25, 40, 60, 33]
salaries = [30000, 55000, 90000, 120000, 70000]

def minmax(values):
    lo, hi = min(values), max(values)
    return [round((v - lo) / (hi - lo), 2) for v in values]

print("Возраст ->", minmax(ages))
print("Зарплата ->", minmax(salaries))

Вывод:

Возраст -> [0.0, 0.17, 0.52, 1.0, 0.36]
Зарплата -> [0.0, 0.28, 0.67, 1.0, 0.44]

Теперь оба признака живут в одном диапазоне и вносят сопоставимый вклад в расстояния. Заметьте: важно вычислять min и max по обучающим данным и применять те же числа к тесту — иначе будет утечка информации.

Кодирование категорий

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

  • One-hot кодирование. Для категории без порядка («Москва», «Казань», «Сочи») заводят отдельный столбец-флаг на каждое значение: 1, если оно, иначе 0. Так модель не решит, будто «Сочи больше Москвы».
  • Порядковое кодирование. Если у категории есть естественный порядок («низкий» < «средний» < «высокий»), её можно заменить числами 0, 1, 2.
# One-hot кодирование города вручную
cities = ["Москва", "Казань", "Сочи", "Москва"]
unique = ["Москва", "Казань", "Сочи"]

for city in cities:
    row = [1 if city == u else 0 for u in unique]
    print(city, "->", row)

Вывод:

Москва -> [1, 0, 0]
Казань -> [0, 1, 0]
Сочи -> [0, 0, 1]
Москва -> [1, 0, 0]

Пропуски и выбросы — коротко

  • Пропуски. Пустые значения либо заполняют (средним, медианой, спец-меткой), либо удаляют строку — в зависимости от того, как много их и насколько они важны.
  • Выбросы. Аномальные значения проверяют: это ошибка ввода (исправить/убрать) или реальное редкое событие (оставить, но учесть).

На практике

# Иллюстрация (scikit-learn в браузере не запустится)
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder

scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X_numeric)   # масштабирование чисел

encoder = OneHotEncoder()
X_cat = encoder.fit_transform(X_categories)  # кодирование категорий

Итог

  • Числовые признаки масштабируют (например, min-max в [0,1]), чтобы они вносили сопоставимый вклад.
  • Категории кодируют: one-hot для неупорядоченных, числа по порядку — для упорядоченных.
  • Параметры подготовки считают по обучающим данным и применяют к тесту без пересчёта.
  • Пропуски и выбросы обрабатывают отдельно, осознанно.
Проверьте себя
1. Зачем нормализуют числовые признаки?
AЧтобы признаки с разным масштабом вносили сопоставимый вклад и большой не подавлял остальные
BЧтобы увеличить число признаков
CЧтобы превратить числа в текст
DНормализация нужна только для меток
2. Как правильно закодировать неупорядоченную категорию вроде города?
AПрисвоить городам числа 1, 2, 3 по алфавиту
BOne-hot: отдельный столбец-флаг на каждое значение
CОставить как текст без изменений
DУдалить такой признак
3. Почему параметры нормализации (min и max) берут только по обучающим данным?
AТак быстрее считать
BЧтобы избежать утечки информации из тестовых данных в обучение
CТестовые данные нормализовать вообще нельзя
DЭто не имеет значения
Поддержать проект