На конкурсе IJCAI Alimama по прогнозированию коэффициента конверсии в поиске рекламы в начале года я столкнулся с проблемой CTR. рейтинг кликов(click-through-rate)
Рейтинг кликов — это отношение фактического количества кликов по рекламе к фактическому объему показа рекламы. Это важный показатель для измерения эффекта рекламы.
Идея трансферного обучения, использованная чемпионом этого конкурса, заставила меня засиять. Я на платформе DF, CCFПрогноз покупок пользователей China Merchants BankЭтот метод используется в , и значение auc увеличивается на одну тысячу пунктов. На самом деле, в то время я был всего в нескольких тысячах очков от чемпиона.Видно, что улучшение, принесенное этим методом, является значительным. В этой статье мы познакомим вас с этим методом, исходя из принципов и реальных боевых идей, а также дадим демонстрацию и подробное объяснение, которое я на самом деле сделал.
Что такое трансферное обучение
Целью трансферного обучения является применение знаний, полученных в одной среде, в новой среде. его значениеОтсутствие размеченных данных в полеЗатем мы используем данные из аналогичных задач, чтобы помочь в обучении.
Например: У нас есть десять тысяч изображений разных видов кошек и сто изображений персидских кошек. Теперь хочу обучить классификатор, который сможет различать персидских кошек. Очевидно, что если мы будем использовать 10 000 изображений напрямую, классификатор не будет работать должным образом из-за разницы между исходными данными и целевыми. И если мы откажемся от использования 10 000 изображений и вместо этого будем использовать эти 100 изображений персидских кошек, это приведет к слишком маленькому объему данных и неполной подгонке классификатора.
Чтобы решить эту проблему, мы используем 10 000 изображений для обученияОпределите, кошка ли это, и на этой основе использовать эти сотни изображений персидских кошек, чтобы помочь нам в дальнейшем изучении кошек.Определите, является ли это персидской кошкой. Таким образом, мы можем использовать большие данные для обслуживания сценариев, в которых данных не хватает. На этом этапе используется основная идея трансферного обучения. Я думаю, что следующая картинка может очень хорошо описать этот процесс:
На приведенном выше рисунке показано, что мы можем перенести их общность из исходного домена в целевой домен. Красная рамка представляет собой общность, то есть знания, полученные в ходе другой аналогичной задачи.Почему трансферное обучение можно использовать для задач прогнозирования
Мы все знаем, что проблемы с классами прогнозирования часто встречаются в практических сценариях.
Конечно, предсказание, о котором мы говорим, не является буквально проблемой «предсказания размера опухоли человека или того, есть ли у него рак», потому что я все еще хочу разделить его на общую проблему регрессии и классификации в стиле контролируемого обучения.
В основном я хочу сослаться на прогнозирование проблем временных рядов и прогнозирование будущего, которое может отражать слово «до». Мы очень мало знаем о будущем, что соответствует основной цели нашего трансферного обучения — отсутствие достоверных данных в целевой области.
Мы определенным образом сопоставляем определенные атрибуты прошлого с будущим, что эквивалентно передаче знаний о будущем, так что можно судить об определенных характеристиках будущего, и эффект будет лучше.
Тогда мы также теоретически доказали, что этот метод осуществим. Далее начинаем доказывать это на практических примерах.
Представьте этот пример
Чтобы выделить ключевые моменты, я провел серию предобработок, и предварительно обработанные данные были переданы вОблако Байду. Я добавил много новых возможностей в свой препроцессинг.Чтобы лучше понять, что я делаю, я предлагаю вам перейти по ссылке конкурса, чтобы увидеть, что делать.
Основное содержание этих данных:original.csv
поле | значение | поле | значение |
---|---|---|---|
V1-v30 | Неотъемлемые атрибуты пользователей, означающие неизвестные | USRID | ID пользователя, уникальный идентификатор |
Flag | Теги, купил ли пользователь, предсказанные цели | next_time_{} | Четыре поля, которые представляют собой среднее значение, стандартное отклонение, минимальное и максимальное значение различных интервалов поведения пользователя при нажатии. |
user_tch_cnt | Три поля, количество переходов пользователей по трем уровням страниц | user_evt1_cnt | 21 поле, количество кликов по каждой из 21 страниц первого уровня |
xx_week_cnt | Количество кликов по неделям | xx_week_user_click_rate | Количество кликов за первую неделю в процентах от общего количества кликов за четыре недели |
xx_week_max_click | Недели с наибольшим количеством кликов на странице | love_LBl | Любимые страницы пользователя |
last_click_day | дата последнего клика | first_click_day | дата первого клика |
Суммировать: эти данные представляют собой ситуацию, когда пользователи нажимали на страницу в прошлом месяце. Цель состоит в том, чтобы предсказать, будут ли такие пользователи покупать на следующей неделе, что соответствует полю FLAG в данных.
считать: Мы можем легко построить контролируемое обучение, но эффект не очень хороший. Тщательный анализ данных показывает, что доступные данные относятся к предыдущему месяцу, и мы очень мало знаем о неделе, на которую нужно прогнозировать. В конце концов, поведение по клику для покупки чувствительно ко времени, а клик в день является наиболее точным, чтобы определить, стоит ли покупать в этот день. Можем ли мы описать поведение пользователя при нажатии на прогнозируемую неделю?
начать
Очисти свой разум: мы хотим построить контролируемое обучение, которое сопоставляет особенности предыдущего месяца со следующей неделей. Но нам нужны данные для перекрестной проверки, чтобы получить лучшую модель контролируемого обучения. Поэтому мы используем первые три недели месяца в качестве данных для обучения, а последнюю неделю — в качестве данных для проверки. Затем обученная модель использует последние три недели месяца в качестве тестовых данных для создания пользовательских функций на следующую неделю. Это немного похоже на нашу обычно используемую операцию скользящего окна. Если четвертая неделя прогнозируется для первых трех недель, выходом следующих трех недель является следующая неделя.
Далее, давайте рассмотрим демо шаг за шагом:
Получить данные за первые три недели и последние три недели
first_three_week_data = data.drop(['last_week_cnt', 'last_week_user_click_rate', 'last_week_max_click'], axis=1).values
last_three_week_data = data.drop(['first_week_cnt', 'first_week_user_click_rate', 'first_week_max_click'], axis=1).values
Чтобы получить признаки первых трех недель, мы вычтем несколько признаков четвертой недели из всех данных, чтобы получить обучающие данные. По сравнению с извлечением данных за первые три недели из общих данных в качестве обучающих данных преимущество первого состоит в том, что имеется больше обучающих функций.
Начать обучение модели
last_week_cnt = data['last_week_cnt'].values
new_week_cnt = xgboost_for_feature(first_three_week_data, last_week_cnt, last_three_week_data)
Мы используем данные первых трех недель в качестве обучающего набора и четвертой недели в качестве набора тестовых данных и делаем прогнозы после обучения модели. Здесь мы используем xgboost в качестве модели обучения. Ниже то, что я написалxgboost_for_feature
функция:
def xgboost_for_feature(X, y, test):
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1729)
xlf = xgb.XGBRegressor(max_depth=10,
learning_rate=0.01,
n_estimators=500,
silent=True,
objective='reg:linear',
nthread=-1,
gamma=0,
min_child_weight=1,
max_delta_step=0,
subsample=0.85,
colsample_bytree=0.7,
colsample_bylevel=1,
reg_alpha=0,
reg_lambda=1,
scale_pos_weight=1,
seed=1440,
missing=None)
xlf.fit(x_train, y_train, eval_metric='rmse', verbose=True, eval_set=[(x_test, y_test)], early_stopping_rounds=50)
predictions = xlf.predict(test, ntree_limit=xlf.best_ntree_limit)
return predictions
В этой функции я по-прежнему выполняю раздельный процесс перекрестной проверки привычных обучающих данных. Для параметров мы выбираем линейную регрессию, потому что я хочу получить более точную модель, и причина выбора самой простой линейной регрессии заключается в уменьшении вычислительных потерь. Фактически мы переходим на другие методы регрессии, и разрыв в производительности невелик. Берем данные за последние три недели какtest
Набор данных, первые три недели предсказывают четвертую, затем выход четвертой недели - следующая неделя.
data['new_week_cnt'] = list(new_week_cnt)
Затем после этого обучения функция прогнозируемого результата добавляется в новый столбец исходных данных, а имя столбцаnew_week_cnt
. На этом мы завершили «миграцию».
посмотри, как это работает
Мы провели последний эксперимент и обнаружили, что модель, которая добавляла данные о кликах за следующую неделю, закончиласьрезультат auc 0,9046523660309632Напротив, окончательныйцена 0,866629382497686
Конечно, это оффлайн результат, а онлайн имеет улучшение только на тысячные, что кажется несколько завышенным. Но в любом случае прибавка к тысячным в финальном этапе соревнований все равно значительна.
Ниже моя демонстрация этой части
import pandas as pd
from sklearn.model_selection import StratifiedKFold
import lightgbm as lgb
from sklearn.metrics import roc_auc_score, mean_squared_error
from sklearn.cross_validation import train_test_split
import xgboost as xgb
def xgboost_for_feature(X, y, test):
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=1729)
xlf = xgb.XGBRegressor(max_depth=10,
learning_rate=0.01,
n_estimators=500,
silent=True,
objective='reg:linear',
nthread=-1,
gamma=0,
min_child_weight=1,
max_delta_step=0,
subsample=0.85,
colsample_bytree=0.7,
colsample_bylevel=1,
reg_alpha=0,
reg_lambda=1,
scale_pos_weight=1,
seed=1440,
missing=None)
xlf.fit(x_train, y_train, eval_metric='rmse', verbose=True, eval_set=[(x_test, y_test)], early_stopping_rounds=50)
predictions = xlf.predict(test, ntree_limit=xlf.best_ntree_limit)
return predictions
def lgb_model(X, y, test):
print('///////////////////////////', X.dtype)
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
auc_score = []
predictions = []
params = {
'boosting_type': 'gbdt',
'objective': 'binary',
'metric': {'auc'},
'num_leaves': 15,
'learning_rate': 0.02,
'feature_fraction': 0.8,
'bagging_fraction': 0.9,
'bagging_freq': 8,
'verbose': 0,
}
for train_in, test_in in skf.split(X, y):
X_train, X_test, y_train, y_test = X[train_in], X[test_in], y[train_in], y[test_in]
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)
print('Start training...')
gbm = lgb.train(params, lgb_train, num_boost_round=40000,
valid_sets=lgb_eval, verbose_eval=250, early_stopping_rounds=50)
print('Start predicting...')
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration)
auc_score.append(roc_auc_score(y_test,y_pred))
predictions.append(gbm.predict(test, num_iteration=gbm.best_iteration))
return auc_score, predictions
def create_pre_week_features(data):
first_three_week_data = data.drop(['last_week_cnt', 'last_week_user_click_rate', 'last_week_max_click'], axis=1)
last_three_week_data = data.drop(['first_week_cnt', 'first_week_user_click_rate', 'first_week_max_click'], axis=1)
first_three_week_data = first_three_week_data.values
last_three_week_data = last_three_week_data.values
last_week_cnt = data['last_week_cnt'].values
new_week_cnt = xgboost_for_feature(first_three_week_data, last_week_cnt, last_three_week_data)
data['new_week_cnt'] = list(new_week_cnt)
last_week_user_click_rate = data['last_week_user_click_rate'].values
new_week_user_click_rate = xgboost_for_feature(first_three_week_data, last_week_user_click_rate, last_three_week_data)
data['new_week_user_click_rate'] = list(new_week_user_click_rate)
last_week_max_click = data['last_week_max_click'].values
new_week_max_click = xgboost_for_feature(first_three_week_data, last_week_max_click, last_three_week_data)
data['new_week_max_click'] = list(new_week_max_click)
return data
if __name__ == "__main__":
data = pd.read_csv('./data_transfer/data.csv')
data = create_pre_week_features(data)
# 开始预测未来一周的点击数据,如果不使用未来一周的数据,则注释此句
train = data[data['FLAG'] != -1]
test = data[data['FLAG'] == -1]
train_userid = train.pop('USRID') # 这里将USRID 保存,以便提交结果时候要按照USRID排序
y = train.pop('FLAG')
col = train.columns
X = train[col].values
test_userid = test.pop('USRID')
test_y = test.pop('FLAG')
test = test[col].values # 这部分是我将预测目标与s训练数据分离的代码
auc_score, predictions = lgb_model(X, y, test) # 获取到5折交叉验证的5个结果
print(max(auc_score))
Весь код предобработки и построения модели завершен, я поместил его вgithubНа, кроме того, я положил исходные данные вОблако Байду