比赛地址:https://challenge.xfyun.cn/2019/gamedetail?type=detail/classifyApp
赛题任务:简单来说就是应用分类,其中初赛是要根据应用描述进行应用分类,而复赛是要根据应用名称和应用包名自行爬取数据进行应用分类,这种类型的赛题应该是非常少见的。然后初赛的训练集30000条,测试集99999条,复赛训练集20000条,测试集80000条。这里顺便吐下槽,这个比赛的得分并没有说具体怎么算的,原则上来说应该是准确率,但一个整数除以99999乘以100显然不可能得到79.86419(我的初赛分数)这样的得分,一个整数除以80000乘以100也不可能得到80.28436(我的复赛分数)这样的得分。
这个仓库包含的是我复赛第一名的方案(初赛我本来只水了一小段时间就不做了,结果最后运气好以第22名的成绩意外进入复赛)。其中本文档是我的方案介绍,code文件夹中包含的是我的进行数据处理与模型训练的代码及相关介绍,code/spider文件夹中包含的是我的爬虫代码及相关介绍。
比赛的原始数据、我爬到的数据和我最高分对应的提交文件我已经放到了百度网盘上(链接: https://pan.baidu.com/s/1aeXb4wB_ZYecA2cR5wxWvg 提取码: ke22),有需要的可以下载。
数据清洗方面我做的工作不是很多,主要就是处理了一些这样的数据:
处理前的应用名称 | 处理前的应用包名 | 处理后的应用名称 | 处理后的应用包名 |
---|---|---|---|
百度手机助手(天猫) | com.baidu.appsearch | 天猫 | (无) |
百度手机助手(作业帮) | com.baidu.appsearch | 作业帮 | (无) |
百度手机助手(全民K歌) | com.baidu.appsearch | 全民K歌 | (无) |
应用市场(扫描全能王) | com.mobiletool.appstore | 扫描全能王 | (无) |
应用市场(掌上公交) | com.mobiletool.appstore | 掌上公交 | (无) |
应用市场(个人所得税) | com.mobiletool.appstore | 个人所得税 | (无) |
应用商店(QQ音乐) | com.sogo.appmall | QQ音乐 | (无) |
应用商店(美图秀秀) | com.sogo.appmall | 美图秀秀 | (无) |
应用商店(微信) | com.sogo.appmall | 微信 | (无) |
接着是数据爬取,我爬取了两个类别的数据:
在复赛阶段,我爬取了两个类别的数据:
- 应用描述数据:数据来自七麦网,七麦网中包含了来自百度手机助手、360手机助手、应用宝等流行应用商店的安卓APP数据。根据七麦网的sitemap可以找到七麦网中所有安卓APP的链接网址,总共有近10万个。再考虑同一个应用可能在多个应用商店都有信息,总共爬到了约37万条数据。
- 搜索引擎结果数据:将应用名称输入搜索引擎,得到对应的搜索结果,再提取搜索结果中的网页标题和摘要。一个应用在同一个搜索引擎最多可以得到10条数据。为了增加数据的多样性,我不止使用一个搜索引擎,而是使用了来自百度和必应的搜索结果。这样除了极少数应用名称(一两百个)之外,几乎数据集中的每个应用名称都可以找到对应的搜索结果(即使不一定非常靠谱)。
而接下来的问题是如何将爬取到的信息匹配到样本上面:
- 应用描述数据:对于这部分数据,如果直接根据apk包名和应用名称去匹配得到应用描述数据会匹配到多条(其实是使用应用名称匹配时)。一个效果比较好的方法是如果有多条就全部保留,然后在最终预测的时候分别预测再进行将得到的结果融合。但这样的代价就是预测成本较高,相反我只保留一条应用描述数据(这正是我的方案中的一个可以改进的点,多保留几条的提升性能),选取的标准是:选取非ASCII字符最多的应用描述。同时,我优先通过apk包名匹配,匹配不到再通过应用名称匹配。
- 搜索引擎结果数据:根据应用名称可以直接匹配到对应的最多10条搜索结果(单个搜索引擎),每条搜索结果长度不长,但如果全部拼起来就太长了,因此我将10条搜索结果随机分为两等分,然后分别拼接起来。也就是说每个原始样本对于单个搜索引擎会有两条文本。
之后就是训练模型,总共有三个训练模型的数据集,而模型我使用了BERT和XLNet,所以总共有六个模型。
- 应用描述数据模型:使用初赛训练集作为训练集,而最终预测时使用从七麦网爬到的数据。这样做的原因是初赛训练集有3w条,而复赛训练集只有2w条,其中可以匹配到应用描述的就更少了。这个模型训练了6个epoch,最终结果使用第五和第六个epoch的结果做融合。
- 百度搜索结果数据:2w条原始样本,总共4w条文本也就是4w条训练集样本进行训练。预测的时候每个测试集样本的2条文本一起测试,之后结果做融合。这个模型训练了3个epoch,最终使用了第二个epoch的结果做融合。(主要是没做什么调参工作,epoch数也设得比较随意,训练了3个epoch,到最终发现的第二个epoch的结果好一些,原则上可以只训练两个epoch,但也不完全等价)。
- 必应搜索结果数据:同上
最终模型的预测结果为:
- 如果可以匹配到应用描述数据:使用所有6个模型的结果做融合
- 如果匹配不到应用描述数据:使用搜索引擎数据的4个模型的结果做融合
但这并还不是最终的预测结果,我又通过一定规则对模型预测结果进行了修改。具体来说:
- 在初赛训练集中,通过正则匹配从应用描述中提取出应用名称。经过观察可以发现应用名称主要通过两种方式出现在应用描述中,第一种是用书名号括起来,第二种是在应用描述的开头有类似于这样的一段表述:XXXX(应用名称)是YYYY(相关的应用简介),如“平行空间是一款极简、免费的黑科技双开助手”。而我的提取方式也主要是依赖于这两种模式。提取出来后和对应的应用分类一起和复赛训练集合并。最终综合起来得到应用名称到应用分类(也就是label)的唯一映射。
- 使用上一步得到的唯一映射,如果测试集中的应用名称可以得到匹配,则将对应的应用类别的概率改到最高(也就是说两个预测结果中一定会有一个为对应的应用类别)