仔细看了关键词分类项目的冠军队HadoopEagleEye的代码,这里做个总结。
项目的目标是对搜索关键词进行分类(共33类),可以利用的辅助信息包括每个关键词的搜索结果(前10条搜索结果的标题),以及广告主与其购买的搜索关键词的对应关系(多对多的关系,并且并非每个关键词都被购买)。已标注的数据约100W条,需要进行预测的数据约1000W。
HadoopEagleEye只用到了关键词文件(keyword_class.txt,仅包含关键词keyword以及标注结果label),大致处理流程如下:
1.数据预处理
- 分词
它采用了两种分词方式,分别用nchar和perm代替,这两种方式是这样的
- nchar: 对关键词按字处理,将相邻的4字及以内的字都组合成一个词。举个例子,比如:我和小明。分词结果就变成了:我,我和,我和小,我和小明,和,和小,和小明,小,小明,明。
- perm: 对关键词进行分词,分词之后在保留分词结果的基础上,将分词结果两两组合(不相邻的两个词也组合在一起)。还是上面那个我和小明。因为分词的结果是我,和,小明。在保留分词结果并两两结合之后变成了:我,和,小明,我和,我小明,和小明。
两种分词方式的结果分别输出到两个文件中备用。为了方便下面的流程解释,姑且暂记第一种的输出文件为seg_nchar.txt,第二种的输出文件为seg_perm.txt。文件格式都是一样的:行号 词1词2词3......。行号就是该行的关键词在原始关键词文件中的行号。
2. 选特征
这一步对上面的分词结果文件进行了处理。以seg_nchar.txt的处理为例。每一行的行号后面的词(为了方便,下面都记做gram) 都可以看作是一维特征,但是都保留的话显然太多了。选出相对重要的gram的方法大致如下:
首先统计每个gram出现的行数(一行里出现多次的话仅计1次),保留出现次数超过10行(可以看成初选)的这些gram,对这些经过初选的gram分别计算idf值(idf: log(文本总行数/出现该gram的行数)),保留idf值大于log(1/0.9)的。把这些经过第二次筛选后的gram以及对应的idf值输出到一个相当于是特征词典的文件dictkwnch中。
对set_perm.txt的处理同上面类似,只是初选的阈值更低一些,是2,输出到dictkwp中。
3.特征量化
根据第2步产生的特征词典对第1步输出的分词结果文件进行处理,对于分词结果文件的每一行,踢去那些不在特征词典中的词之后,有两种量化方式,一种将出现在本行中的gram对应的维度的特征值量化为1;另一种是将出现在本行中的每个gram对应的维度的特征值量化为tfidf值。之后对于每一行的特征值进行归一化处理(比如1,1,1,1归一化变成了1/2,1/2,1/2,1/2)。根据分词方式的不同,这一步也是输出了两个文件:rfrea_kwnch和rfea_kwperm。格式是这样的:
keywordId dictID1:normValue1dictID2:normValue2......
现在把通过两种分词方式得到的两个特征值文件(rfrea_kwnch和rfea_kwperm)按行合并起来就完成了所有的预处理工作。输出文件rfea.hsvm
2.训练模型
1.把rfea.hsvm按是否标注分开到两个文件fea_train.hsvm和fea_test.hsvm中。
2.训练
训练用的是liblinear dual L2的方法。因为百度那个hadoop平台各种限制,没有直接调liblinear的jar包提供的训练函数,而是自己实现了训练过程。基本的方法和论文里都是一致的,只是由于考虑到节点内存限制,这里并没有一次加载全部的训练数据,而是指定了一个bufSize,每次仅对bufSize大小的数据进行训练。在对第一批数据训练完毕,得到w之后,对这部分数据进行分值计算(wxy-1)。分值>0的表明该数据不是支持向量,那么就继续读一条新的数据,来替换掉这条数据。完成第一批数据的所有替换之后,我们现在有了第二批数据(第一批的支持向量+新数据),用第二批数据进行训练得到新的w,重复以上步骤,知道处理完所有的数据,得到了最终的w。
这是一个多分类问题,可以用多个二分类的分类器解决。因此在整个训练过程结束后,我们得到了33个二分类器的特征权重。
3.预测
预测这一步没什么特别的,就不详细说了。