0 任务概述
任务1:报名并理解赛题任务(9.12~9.13,2天)
任务2:配置环境(9.14,1天)
任务3:baseline实践(9.15,1天)
任务4:数据处理、算法应用等技能学习(9.16~9.17,2天)
任务5:相关知识参考学习(9.18,1天)
大作业:结合学习任务完成一篇学习笔记
1 报名并理解赛题任务
1.1 学习准备任务
学习准备任务主要包括:
①Datawhale报名(完成)
②平台注册:在【华为赛事官网注册网址】 已完成注册
③比赛报名:在【华为赛事官网报名地址】已完成报名
④数据下载:在相应的赛题连接中完成数据的下载
1.2 赛题理解
1.2.1背景
为什么要做CTR预测?——若能准确预测CTR,可丰富用户的行为特征。
1.2.2赛题数据
目标域数据:广告行为本身,即收集广告任务产生的历史数据(收集的数据,质量不好保证,可能数据会很稀疏 → 受数据收集手段的影响)
源域数据:用户另外渠道收获到的数据,用户浏览信息流里的数据,即在其他领域的行为数据
应该将上述两种数据有效结合起来:可通过用户的【u_userid】这个特征,将两种数据结合形成一个更大的数据集
1.2.3 赛题任务
基于用户的行为历史特征,预测该用户是否会产生点击这个行为。
输入:用户的行为历史特征数据
输出:用户是否会产生【点击】这个行为(0:不点击;1:点击)
模型:初步判断,任务的问题可抽象成一个二分类的问题。
1.2.4 评价指标
AUC和GAUC的加权求和。
2 环境配置
2.1 本地配置
①参考教程:https://blog.csdn.net/fan18317517352/article/details/123035625
②配置结果,如下图所示:
2.2 线上配置
按照本期Datawhale组队学习贡献者的建议,对于推荐任务,使用百度飞桨AI Studio即可。
在完成百度飞桨AI Studio账号注册和登录后,可参照其官方提供的新手教程进行新建项目、baseline实践等操作。
部分操作的截图如下图所示。
①找到“项目”选项标签,单击【创建项目】,效果如下图所示;
②按照上图所示,选择【Notebook】,单击【下一步】后,如下图所示
③按照上图所示,完成【配置环境】后,单击【下一步】后界面如下图
④在上图中,填写项目信息后,单击【创建】按钮,会提示【项目创建成功】,进入如下图所示的界面
⑤点击上图中的【启动环境】,即可完成云端环境的配置。
3 baseline实践
3.1 解决机器学习问题的流程
(1)问题分析
根据赛题的描述,可将赛题的问题抽象成二分类问题。
(2)数据探索
数据有两个部分:训练集和测试集,每个包含两个数据文件:一类是广告相关的数据(ads),另外一个是用户的习惯数据(feeds)。
(3)特征工程
①可以去除一些无关的特征
②将一些非数值类型的特征转换为数值型特征
③为了节省内存空间,可将数据类型进行压缩
(4)模型训练
对于二分类问题,可以考虑使用:逻辑回归、决策树、XGBoost等算法进行模型构建。
(5)模型验证:若结果不理想,返回(3),否则进入(6)
(6)结果输出
3.2 代码实现
# ---------------------------------------------------
# 导入库
import pandas as pd
# ----------------数据探索----------------
# 只使用目标域用户行为数据
train_ads = pd.read_csv('./train/train_data_ads.csv',
usecols=['log_id', 'label', 'user_id', 'age', 'gender', 'residence', 'device_name',
'device_size', 'net_type', 'task_id', 'adv_id', 'creat_type_cd'])
test_ads = pd.read_csv('./test/test_data_ads.csv',
usecols=['log_id', 'user_id', 'age', 'gender', 'residence', 'device_name',
'device_size', 'net_type', 'task_id', 'adv_id', 'creat_type_cd'])
# 数据集采样
train_ads = pd.concat([
train_ads[train_ads['label'] == 0].sample(70000),
train_ads[train_ads['label'] == 1].sample(10000),
])
# ----------------模型训练----------------
# 加载训练逻辑回归模型
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()
clf.fit(
train_ads.drop(['log_id', 'label', 'user_id'], axis=1),
train_ads['label']
)
# ----------------结果输出----------------
# 模型预测与生成结果文件
test_ads['pctr'] = clf.predict_proba(
test_ads.drop(['log_id', 'user_id'], axis=1),
)[:, 0]
test_ads[['log_id', 'pctr']].to_csv('submission.csv', index=None)
3.3 运行结果输出
运行结果的部分截图如下
3.4 模型优化
解决机器学习问题的流程,以代码的形式展现如下:
(1)导入库
#导入库
# ——————————————————————————————————————————————————————
# ---------- 数据探索 ---------- #
import pandas as pd
import numpy as np
import os
import gc
import matplotlib.pyplot as plt
import tqdm import *
#----------------核心模型----------------
from catboost import CatBoostClassifier
from sklearn.linear_model import SGDRegressor, LinearRegression, Ridge
#----------------交叉验证----------------
from sklearn.model_selection import StratifiedKFold, KFold
#----------------评估指标----------------
from sklearn.metrics import accuracy_score, f1_score, roc_auc_score, log_loss
#----------------忽略报警----------------
import warnings
warnings.filterwarnings('ignore')
(2)数据预处理
# 数据预处理
# ——————————————————————————————————————————————————————
# ---------- 读取训练数据和测试数据 ----------
train_data_ads = pd.read_csv('./train/train_data_ads.csv')
train_data_feeds = pd.read_csv('./train/train_data_feeds.csv')
test_data_ads = pd.read_csv('./test/test_data_ads.csv')
test_data_feeds = pd.read_csv('./test/test_data_feeds.csv')
# ---------- 合并数据 ----------
# 为数据添加新列istest,便于区分数据
train_data_ads['istest'] = 0
test_data_ads['istest'] = 1
data_ads = pd.concat([train_data_ads, test_data_ads], axis=0, ignore_index=True)
train_data_feeds['istest'] = 0
test_data_feeds['istest'] = 1
data_feeds = pd.concat([train_data_feeds, test_data_feeds], axis=0, ignore_index=True)
# 清除变量、内存
del train_data_ads, test_data_ads, train_data_feeds, test_data_feeds
gc.collect()
# # 删除无意义的特征
# data_ads = data_ads.drop(columns=['log_id'])
(3)特征工程
本项目中的特征工程主要包括:自然数编码、特征提取、内存压缩
# 特征工程:自然数编码、特征提取、内存压缩
# ——————————————————————————————————————————————————————
# 1/3 自然数编码
def label_encode(series, series2):
unique = list(series.unique())
return series2.map(dict(zip(
unique, range(series.nunique())
)))
for col in ['ad_click_list_v001','ad_click_list_v002','ad_click_list_v003','ad_close_list_v001','ad_close_list_v002','ad_close_list_v003','u_newsCatInterestsST']:
data_ads[col] = label_encode(data_ads[col], data_ads[col])
# 2/3 特征提取
# 特征构建部分,均使用训练集数据进行构建,避免测试集使用未来数据
train_feeds = data_feeds[data_feeds.istest==0]
cols = [f for f in train_feeds.columns if f not in ['label','istest','u_userId']]
for col in tqdm(cols):
tmp = train_feeds.groupby(['u_userId'])[col].nunique().reset_index()
tmp.columns = ['user_id', col+'_feeds_nuni']
data_ads = data_ads.merge(tmp, on='user_id', how='left')
cols = [f for f in train_feeds.columns if f not in ['istest','u_userId','u_newsCatInterests','u_newsCatDislike','u_newsCatInterestsST','u_click_ca2_news','i_docId','i_s_sourceId','i_entities']]
for col in tqdm(cols):
tmp = train_feeds.groupby(['u_userId'])[col].mean().reset_index()
tmp.columns = ['user_id', col+'_feeds_mean']
data_ads = data_ads.merge(tmp, on='user_id', how='left')
# 3/3 内存压缩
def reduce_mem_usage(df, verbose=True):
numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
start_mem = df.memory_usage().sum() / 1024**2
for col in df.columns:
col_type = df[col].dtypes
if col_type in numerics:
c_min = df[col].min()
c_max = df[col].max()
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df[col] = df[col].astype(np.int32)
elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
df[col] = df[col].astype(np.int64)
else:
if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
df[col] = df[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df[col] = df[col].astype(np.float32)
else:
df[col] = df[col].astype(np.float64)
end_mem = df.memory_usage().sum() / 1024**2
if verbose: print('Mem. usage decreased to {:5.2f} Mb ({:.1f}% reduction)'.format(end_mem, 100 * (start_mem - end_mem) / start_mem))
return df
# 压缩使用内存
data_ads = reduce_mem_usage(data_ads)
# Mem. usage decreased to 2351.47 Mb (69.3% reduction)
(4)训练集和测试集划分
# 训练集和测试集划分
# ——————————————————————————————————————————————————————
# ---------- 划分训练集和测试集 ----------
# 将数据按照时间戳排序
data_ads = data_ads.sort_values('pt_d')
cols = [f for f in data_ads.columns if f not in ['label','istest']]
x_train = data_ads[data_ads.istest==0][cols]
x_test = data_ads[data_ads.istest==1][cols]
y_train = data_ads[data_ads.istest==0]['label']
# 重置index
for df in [x_train, x_test, y_train]:
df.index = range(0, df.shape[0])
del data_ads, data_feeds
gc.collect()
(5)模型训练
# 训练模型
# ——————————————————————————————————————————————————————
trn_x, val_x, trn_y, val_y = train_test_split(x_train, y_train, test_size=0.33, shuffle=False)
params = {'iterations': 20000, 'learning_rate': 0.3, 'depth': 5, 'l2_leaf_reg': 10, 'bootstrap_type': 'Bernoulli',
'od_type': 'Iter', 'od_wait': 50, 'random_seed': 11, 'allow_writing_files': False}
model = CatBoostClassifier(**params, eval_metric='AUC',task_type="GPU")
model.fit(trn_x, trn_y, eval_set=(val_x, val_y),
cat_features=[],
use_best_model=True,
verbose=1)
(6)结果保存
# 结果保存
# ——————————————————————————————————————————————————————
test_pred = model.predict_proba(x_test)[:, 1]
test_pred
x_test['pctr'] = test_pred
x_test[['log_id','pctr']].to_csv('submission.csv', index=False)
(7)效果输出
第一次模型训练的结果如下:
bestTest = 0.8001283705
bestIteration = 356
Shrink model to first 357 iterations.
代码改动如下:
①添加了处理特征穿越的代码:训练集和测试集的数据在“时间戳”这个特征上有重合
# 处理特征穿越,避免使用未来的数据
minDate = min(test_data_ads.pt_d.min(), test_data_feeds.e_et.min())
train_data_ads = train_data_ads[train_data_ads.pt_d < minDate]
train_data_feeds = train_data_feeds[train_data_feeds.e_et < minDate]
②将数据按照时间戳排序
data_ads = data_ads.sort_values('pt_d')
第二次模型训练的结果如下:
bestTest = 0.7939100862
bestIteration = 363
Shrink model to first 364 iterations.
第二次模型训练的结果文件submission.csv已经提交,观察分数是否提升。
计划后期多了解一些广告业务CTR方面的信息,并在特征构建、模型训练(多尝试几个模型)上下功夫提升赛事的得分。
未完待续~~
参考资料
https://xj15uxcopw.feishu.cn/docx/doxcnw5LGZfH5n1WSwcNV59VxTg
https://datawhale.feishu.cn/docx/doxcn7BjORolb95KWXNBwH1nmhd