搜索推荐算法挑战赛OGeek-完整方案及代码(亚军)

2023-10-29 05:30

本文主要是介绍搜索推荐算法挑战赛OGeek-完整方案及代码(亚军),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先很幸运拿到TIANCHI天池-OGeek算法挑战赛大赛的亚军,同时非常感谢大佬队友的带飞,同时希望我的分享与总结能给大家带来些许帮助,并且一起交流学习。(作者:王贺,知乎:鱼遇雨欲语与余

赛题链接:

https://tianchi.aliyun.com/competition/entrance/231688/introduction

Github链接:

https://github.com/fanfanda/OGeek-Competition

640?wx_fmt=jpeg

本文目录

  • 赛题分析

  • 数据分析

  • 赛题难点

  • 特征工程

  • 算法模型

  • 思考总结

1. 赛题分析

此次赛题来自OPPO手机搜索排序优化的一个子场景,并做了相应的简化,意在解决query-title语义匹配的问题。简化后,本次题目内容主要为一个实时搜索场景下query-title的ctr预估问题。

赛题特征:prefix(用户输入,query前缀),query_prediction(根据当前前缀,预测的用户完整需求查询词,最多10条;预测的查询词可能是前缀本身,数字为统计概率),title(文章标题),tag(文章内容标签)

提供数据:初赛复赛一致, 训练数据:200万 验证数据:5万 测试数据1:5万 测试数据2:25万

评估指标:本次竞赛的评价标准采用F1 score 指标,正样本为1,公式如下:

640?wx_fmt=png

2. 数据分析

这一部分将会对部分数据进行分析,另外获取部分特征的点击率分布情况判断特征效果,看分布可以有一个很好的初步验证作用。

640?wx_fmt=jpeg

这四个图是prefix在各自数据集的百分比统计,并以训练集中出现频次top10的prefix画出了每个数据集的占比情况,可以发现valid与testa和testb的分布相似,说明valid与testa和testb的查询时间比较接近,作为验证集线下比较可信。

640?wx_fmt=jpeg

此处更近一步分析了train和testa、testb有较大的差异性。

640?wx_fmt=jpeg

我们对数据特点进行了分析。发现,

1.用户有可能会拼错prefix,如‘抖音’拼写成‘枓音’,分析发现,使用prefix的pinying会比中文大幅度减少不同值的出现次数,当然也有一部分不是拼写错误的,如痘印,所以最后我们中文和拼音的两部分特征都使用了。

2.由于这是实时性比较强的搜索场景,分析发现,测试集中会有很大一部分prefix和title未在训练集中出现过。

640?wx_fmt=jpeg

除基础数据分析外,我们还分析了部分特征,比如prefix的长度特征,其用户输入prefix越详细,整体CTR也随之提高,其他特征的长度也有类似的趋势。

另外,相似度特征是非常重要的特征,prefix和title越相似度,点击的可能就越高。

3. 赛题难点

经过上面的分析以及对业务的理解,本赛题有什么难点呢?对此我们总结了五点:

  • 没有用户/没有时间的信息,因此无法对用户建模,对于同一个query,不同人不同时间段都会有不同的反应。

  • 实事热点转移快,训练集中点击率高的,测试集中不一定高。

  • 训练集和测试集的分布不是单纯的按照时间,因为一些明显的热搜词训练集中没有,但是验证集和测试集里面大量存在。这显然不合理的,所以我们认为,主办方数据抽样的时候,过滤了该词语。

  • 因为是实时性比较强的搜索场景,因此面对新出现的title如何处理?由于同样的query-title,最终都会被模型预测成相同的标签,模型对于高频新词的点击率均值的把握,成为了关键点。

  • 用户的明显拼写错误query,例如刘览器这种如何处理?

4. 特征工程

640?wx_fmt=jpeg
640?wx_fmt=jpeg

这里对CountVector的特征构造进行展示,CountVector特征在复赛提升也是非常大的。

# CountVectorizer
data = data_df[['prefix', 'query_prediction', 'title', 'label']]
data.replace('nan',np.nan,inplace=True)
data['query_prediction'].fillna('{}',inplace=True)
data['title'].fillna('-1',inplace=True)
# prefix,title,query_prediction jieba分词
def get_cv_feature(dt):
df = pd.DataFrame()
for item in ['prefix', 'title']:
print(item)
stat = pd.DataFrame()
stat[item] = dt[item].drop_duplicates().values
stat[item+'_jieba'] = stat[item].apply(lambda x:' '.join(jieba.cut(str(x), cut_all=False)))
df[item+'_jieba'] = pd.merge(dt,stat,how='left',on=item)[item+'_jieba']
stat = pd.DataFrame()
item = 'query_prediction'
print(item)
stat[item] = dt[item].drop_duplicates().values
def getFeature(x):
dct = json.loads(x)
lst = []
for k in dct.keys():
lst.extend(jieba.cut(k,cut_all=False))
return ' '.join(lst)
stat['query_prediction_jieba'] = stat['query_prediction'].apply(getFeature)
df[item+'_jieba'] = pd.merge(dt,stat,how='left',on=item)[item+'_jieba']
return df
df = get_cv_feature(data)
from sklearn.feature_extraction.text import CountVectorizer
from scipy import sparse
cntv=CountVectorizer()
data['label'] = data['label'].astype(int)
vector_feature = ['prefix_jieba','query_prediction_jieba','title_jieba']
train_index = data[data['label']>=0].index.tolist()
test_index = data[data['label']==-1].index.tolist()
train_sp = pd.DataFrame()
test_sp = pd.DataFrame()
for feature in vector_feature:
print(feature)
cntv.fit(df[feature])
train_sp = sparse.hstack((train_sp,cntv.transform(df.loc[train_index][feature]))).tocsr()
test_sp = sparse.hstack((test_sp,cntv.transform(df.loc[test_index][feature]))).tocsr()
print(train_sp.shape)
print(test_sp.shape)
640?wx_fmt=jpeg

相似度特征:prefix,title分别构造与query_prediction中每个key的相似度),并统计max,std,mean相似度。更进一步,统计top3,top5相似度的max,std,mean。

640?wx_fmt=jpeg

这些也是CTR问题传统特征,同时对于这些特征的构造也是直接照办之前的开源

鱼遇雨欲语与余:2018腾讯广告算法大赛总结/0.772229/Rank11

链接:https://zhuanlan.zhihu.com/p/38034501

640?wx_fmt=jpeg

由于赛题的特殊性,给了我们验证集,通过观察训练集和验证集的数据,我们发现存在热点转移的情况,例如关于某个明星,title 1是高热点转换网页,可是到了验证集中,这位明星的高热点title是另外的一些网页,说明实时热点性比较强。因此我们对CTR的使用方法进行如下调研。

640?wx_fmt=jpeg

我们这边采用了多种方式来防止过拟合,分别是多折交叉提取特征,平滑,以及采样。

从表格中(5)可以看出,不使用五折交叉提取特征,训练集的auc比验证集的auc高很多,这就非常容易过拟合,导致线上结果很差,

(2)->(3)的过程就是相差了一个平滑,从而导致训练集和验证集上的auc都有所下降;此外,在我们的方法中加入了0.5的采样,是为了使得训练集和验证集结果都不会过拟合。

上表(4)所示,对训练集和验证集均加入0.5的采样之后,训练集和验证集的auc都会有所降低,当然对非常近的数据可能不利,但是对训练集和测试集相隔比较远的数据,随热点的转移,CTR也会有所改善。

640?wx_fmt=jpeg

经过调研,我们使用0.5sample构造CTR特征,主要目的是目的是为了削弱ctr的特征重要度。

5. 算法模型

对于此次比赛我们对传统机器学习模型以及深度模型都进行了尝试。

640?wx_fmt=jpeg
640?wx_fmt=jpeg

TextCNN是经典的文本特征提取网络,TextCNN Concat模型 输入是tag,prefix,title,query_prediction(query_prediction对其进行拆分成10条,查询词为文本,查询词概率为权重)+特征工程中的统计特征, 接着将所有基础的文本特征通过TextCNN来提取,非文本特征通过全连接层来提取,上述几部分结合作为最终的特征层。由于模型过于简单,并没有特征之间(title,prefix)的深层次关联,导致效果很一般。

640?wx_fmt=jpeg

因为只用TextCNN结构的网络缺少prefix和title之间相似度的衡量,所以另外加了孪生网络或伪孪生网络来度量prefix和title之间相似度,以及prefix和query,title和query之间的相似度,并同样加入统计概率作为权重

640?wx_fmt=jpeg

实验结果发现,由于prefix和title的长度有一些差别,反而用伪孪生网络比孪生网络取得了更好一些的效果,所以在上述模型中,prefix,title和query_prediction中并没有用共享权值(伪孪生网络)。该模型结合了TextCNN,DeepFM,AFM等相关操作。

具体流程如下:输入分为两部分,对于prefix,title和query_prediction进行TextCNN操作提取文本特征,tag和统计特征通过全连接层获取对应的Embedding特征。

接着一部分是DeepFM模型,来获取浅层特征和交叉特征,其中query_prediction的统计概率作为query文本向量的权重。

另外一部分是AFM相关操作,就是Bi-Interaction Pooling && Attention,对每两两Field的文本特征向量进行交叉,由于不同文本向量交叉的特征重要性不同,所以此处加入Attention,简单来说就是对不同文本向量交叉的特征加权平均得到向量再放入Deep层进行更深层次的训练。

主要进行了以上几种深度学习模型,经过试验对比,尝试3能取得最好的效果,但由于数据量不是特别大,并没有取得比LightGBM模型更好的效果,虽然该模型与LightGBM模型融合有所提高,但是作为NN模型在200万规模的数据集上稳定性不够强,结果值会产生一定的波动,且模型受限于2个,所以最终提交的成绩并没有使用该模型。

640?wx_fmt=jpeg

我们最终融合方案也比较简单,主要进行加权融合,权重的确定看的是线下分数。

6. 思考总结

640?wx_fmt=jpeg

优点:

  • 能够对数据和业务经过细致的分析,挖掘更深层次的特征,更好的描述实体关系。

  • 在模型方面仅使用稳定性比较高的LightGBM,并且具有很好的解释性。

  • 从特征提取到模型训练仅使用三个小时完成,可以更高效的生成结果。

  • 单模型取得top2的成绩,从特征提取到模型训练可以短时间完成。

不足:

  • 为了保证模型的泛化性没有对特征集合进行精细选择,从而损失一定的准确性。

  • 没有构造出较大差异性的第二模型,导致最终成绩在单模0.7486的成绩上未能

  • 获得很大的提升。

欢迎指正与交流,有问题直接加作者qq418811687。

Github链接:

https://github.com/fanfanda/OGeek-Competition

可以“阅读原文”进入作者知乎查看。


640?wx_fmt=png



这篇关于搜索推荐算法挑战赛OGeek-完整方案及代码(亚军)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/298560

相关文章

利用Python调试串口的示例代码

《利用Python调试串口的示例代码》在嵌入式开发、物联网设备调试过程中,串口通信是最基础的调试手段本文将带你用Python+ttkbootstrap打造一款高颜值、多功能的串口调试助手,需要的可以了... 目录概述:为什么需要专业的串口调试工具项目架构设计1.1 技术栈选型1.2 关键类说明1.3 线程模

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

Java Response返回值的最佳处理方案

《JavaResponse返回值的最佳处理方案》在开发Web应用程序时,我们经常需要通过HTTP请求从服务器获取响应数据,这些数据可以是JSON、XML、甚至是文件,本篇文章将详细解析Java中处理... 目录摘要概述核心问题:关键技术点:源码解析示例 1:使用HttpURLConnection获取Resp

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

Java实现优雅日期处理的方案详解

《Java实现优雅日期处理的方案详解》在我们的日常工作中,需要经常处理各种格式,各种类似的的日期或者时间,下面我们就来看看如何使用java处理这样的日期问题吧,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言一、日期的坑1.1 日期格式化陷阱1.2 时区转换二、优雅方案的进阶之路2.1 线程安全重构2

SpringBoot多数据源配置完整指南

《SpringBoot多数据源配置完整指南》在复杂的企业应用中,经常需要连接多个数据库,SpringBoot提供了灵活的多数据源配置方式,以下是详细的实现方案,需要的朋友可以参考下... 目录一、基础多数据源配置1. 添加依赖2. 配置多个数据源3. 配置数据源Bean二、JPA多数据源配置1. 配置主数据

SpringBoot中配置Redis连接池的完整指南

《SpringBoot中配置Redis连接池的完整指南》这篇文章主要为大家详细介绍了SpringBoot中配置Redis连接池的完整指南,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以... 目录一、添加依赖二、配置 Redis 连接池三、测试 Redis 操作四、完整示例代码(一)pom.

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各