Ответ
Генерация признаков — это творческий и критически важный этап, который сильно влияет на качество модели. Вот методы, которые я регулярно использую:
1. Работа с датой и временем:
Из одной колонки timestamp можно извлечь десятки информативных признаков.
import pandas as pd
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['hour'] = df['timestamp'].dt.hour
df['day_of_week'] = df['timestamp'].dt.dayofweek
df['is_weekend'] = df['day_of_week'].isin([5, 6]).astype(int)
df['part_of_day'] = pd.cut(df['hour'], bins=[0, 6, 12, 18, 24], labels=['night', 'morning', 'afternoon', 'evening'])
2. Статистические агрегаты по группам: Добавление информации о группе, к которой принадлежит объект.
# Средняя цена в категории товара
df['mean_price_in_category'] = df.groupby('category_id')['price'].transform('mean')
# Отклонение цены товара от средней по категории
df['price_deviation_from_category'] = df['price'] - df['mean_price_in_category']
3. Взаимодействие признаков (Feature Cross): Комбинирование существующих признаков для выявления нелинейных зависимостей.
df['price_per_sq_meter'] = df['price'] / df['area']
df['income_to_credit_ratio'] = df['monthly_income'] / df['credit_amount']
# Для категориальных признаков можно создать пересечение
df['city_x_product_category'] = df['city'].astype(str) + '_' + df['product_category'].astype(str)
4. Полиномиальные признаки и преобразования: Для линейных моделей это способ уловить нелинейность.
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
poly_features = poly.fit_transform(df[['age', 'income']])
5. Работа с текстом:
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
# Базовые признаки
tfidf = TfidfVectorizer(max_features=500)
tfidf_features = tfidf.fit_transform(df['text_review'])
# Признаки на основе N-грамм
cv = CountVectorizer(ngram_range=(1, 2), max_features=300)
ngram_features = cv.fit_transform(df['product_title'])
6. Целевое кодирование (Target Encoding): Эффективный способ кодировки категориальных признаков с высокой кардинальностью.
target_mean = df.groupby('category')['target'].mean()
df['category_target_enc'] = df['category'].map(target_mean)
# Важно: чтобы избежать data leakage, расчет нужно делать на трейне, а маппинг применять на валидации/тесте
7. Признаки временных рядов (для транзакционных данных):
df = df.sort_values(['user_id', 'timestamp'])
df['days_since_last_purchase'] = df.groupby('user_id')['timestamp'].diff().dt.days
df['purchase_count_7d'] = df.groupby('user_id').rolling('7D', on='timestamp')['amount'].count().values
Ключ к успеху — глубокое понимание доменной области (domain knowledge). Например, для e-commerce можно создать признаки «скидка в процентах» или «сезонность товара».
Ответ 18+ 🔞
Слушай, а вот эта вся кухня с генерацией признаков — это, блядь, вообще отдельный вид искусства. Прям как алхимия какая-то: из дерьма конфетку слепить. Если на этом этапе накосячить, то хоть какую супер-пупер модель впендюрь — нихуя не выйдет, будет как мартышлюшка с гранатой. Так что давай разберём, как это делают не пидоры шерстяные, а те, кто реально в теме.
1. Дата и время — золотая жила, ёпта.
Из одной ебучей колонки timestamp можно высосать признаков овердохуища. Это же просто пиздец, сколько всего лежит на поверхности.
import pandas as pd
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['hour'] = df['timestamp'].dt.hour
df['day_of_week'] = df['timestamp'].dt.dayofweek
df['is_weekend'] = df['day_of_week'].isin([5, 6]).astype(int)
df['part_of_day'] = pd.cut(df['hour'], bins=[0, 6, 12, 18, 24], labels=['night', 'morning', 'afternoon', 'evening'])
Вот смотри: люди ночью покупают одно, днём — другое, в пятницу вечером вообще третье. Не использовать это — просто грех, ебать мои старые костыли.
2. Агрегаты по группам — мощнейший приём. Тут всё просто: ты смотришь не на объект в вакууме, а на то, как он выглядит на фоне своих. Это ж логично, как божий день.
# Средняя цена в категории товара
df['mean_price_in_category'] = df.groupby('category_id')['price'].transform('mean')
# Отклонение цены товара от средней по категории
df['price_deviation_from_category'] = df['price'] - df['mean_price_in_category']
Представь: видишь ты кроссовки за 30 тысяч. Сам от себя охуел. Но если это люксовый бренд, и средняя цена по их категории — 50к, то эти внезапно выглядят как распродажа! А если средняя цена — 5к, то это уже пизда рулю и явный перец. Модель без такого признака этого не поймёт, будет тупить как хуй в пальто.
3. Скрещивание признаков (Feature Cross). Иногда магия рождается, когда ты две простые фичи берёшь и скрещиваешь, как ебучих мутантов. Получается хитрая жопа, которая ловит нелинейные связи.
df['price_per_sq_meter'] = df['price'] / df['area']
df['income_to_credit_ratio'] = df['monthly_income'] / df['credit_amount']
# Для категориальных признаков можно создать пересечение
df['city_x_product_category'] = df['city'].astype(str) + '_' + df['product_category'].astype(str)
Например, цена за квадрат — это же классика. А вот что люди в Питере сносят на раз-два, а в Урюпинске на это даже не смотрят — это уже знание домена, чувак.
4. Полиномы и преобразования. Особенно для линейных моделей — без этого они слепые, как кот сука собака. Им надо явно дать понять, что мир нелинеен.
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
poly_features = poly.fit_transform(df[['age', 'income']])
Типа, доход в 30 лет с доходом в 50 — это две большие разницы, и зависимость от возраста может быть квадратичной. Не дашь полиномы — модель будет строить прямую линию через всю эту хуйню, и точность будет, ядрёна вошь, никакая.
5. Работа с текстом — тут просто поле непаханое.
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
# Базовые признаки
tfidf = TfidfVectorizer(max_features=500)
tfidf_features = tfidf.fit_transform(df['text_review'])
# Признаки на основе N-грамм
cv = CountVectorizer(ngram_range=(1, 2), max_features=300)
ngram_features = cv.fit_transform(df['product_title'])
Отзыв «норм» и «просто бомба, всем советую» — это ведь, ёперный театр, разные вещи! N-граммы ловят словосочетания типа «быстро сел» или «не рекомендую». Без этого ты теряешь кучу смысла.
6. Целевое кодирование (Target Encoding). Спасение для категориальных признаков, где уникальных значений, как говна за баней. One-Hot кодировать их — самоубийство, получится разреженная хуйня.
target_mean = df.groupby('category')['target'].mean()
df['category_target_enc'] = df['category'].map(target_mean)
# Важно: чтобы избежать data leakage, расчет нужно делать на трейне, а маппинг применять на валидации/тесте
Суть проста: заменяешь название категории на среднее значение целевой переменной по ней. Например, категория «электробритвы» — конверсия 2%, а «подарочные сертификаты» — 15%. Модель сразу видит разницу! Но тут, бля, доверия ебать ноль — если не следить за утечкой данных, всё накроется медным тазом.
7. Признаки для временных рядов. Для транзакций это вообще святое. Надо смотреть на историю.
df = df.sort_values(['user_id', 'timestamp'])
df['days_since_last_purchase'] = df.groupby('user_id')['timestamp'].diff().dt.days
df['purchase_count_7d'] = df.groupby('user_id').rolling('7D', on='timestamp')['amount'].count().values
Понятно же: если чувак покупал каждый день, а потом затих на месяц — это тревожный звоночек. Или наоборот — учащает покупки, значит, скоро вмантит крупную сумму. Не считать такие признаки — это просто распиздяйство.
Короче, главный секрет — это глубокое понимание предметки (domain knowledge). Ты должен думать головой, как бизнес, а не как бездушный скрипт. Для e-commerce — это скидка в процентах, сезонность товара (ёлки в декабре, купальники в июне). Без этого твои признаки будут технически правильными, но пустыми, как обещания политика. Э, бошка, думай!