StumbleUpon Evergreen Classification Challenge
------2013/08/16 -- 2013/10/31
Build a classifier to categorize webpages as evergreen or non-evergreen
Stumbleupon是美国的UGC网站,用户分享内容,网站通过用户行为数据构建兴趣图谱和对用户喜好进行一个个性化定位。
Stumbleupon 发布一个比赛,公司提供数据集,包括有标记的训练集和待预测的测试集,根据StumbleUpon提供历史数据,设计分类模型,预测StumbleUpon提供的网页是否是长期流行,还是短暂流行。
训练集是网页的内容和标记(网页是否是evergreen-长期备受欢迎)
测试集是网页内容,
预测目标y:0,1 (0:non-evergreen,1:evergreen)
官网上数据集格式如下:
FieldName |
Type |
Description |
url |
string |
Url of the webpage to be classified |
urlid |
integer |
StumbleUpon's unique identifier for each url |
boilerplate |
json |
Boilerplate text |
alchemy_category |
string |
Alchemy category (per the publicly available Alchemy API found at www.alchemyapi.com) |
alchemy_category_score |
double |
Alchemy category score (per the publicly available Alchemy API found at www.alchemyapi.com) |
avglinksize |
double |
Average number of words in each link |
commonLinkRatio_1 |
double |
# of links sharing at least 1 word with 1 other links / # of links |
commonLinkRatio_2 |
double |
# of links sharing at least 1 word with 2 other links / # of links |
commonLinkRatio_3 |
double |
# of links sharing at least 1 word with 3 other links / # of links |
commonLinkRatio_4 |
double |
# of links sharing at least 1 word with 4 other links / # of links |
compression_ratio |
double |
Compression achieved on this page via gzip (measure of redundancy) |
embed_ratio |
double |
Count of number of <embed> usage |
frameBased |
integer (0 or 1) |
A page is frame-based (1) if it has no body markup but have a frameset markup |
frameTagRatio |
double |
Ratio of iframe markups over total number of markups |
hasDomainLink |
integer (0 or 1) |
True (1) if it contains an <a> with an url with domain |
html_ratio |
double |
Ratio of tags vs text in the page |
image_ratio |
double |
Ratio of <img> tags vs text in the page |
is_news |
integer (0 or 1) |
True (1) if StumbleUpon's news classifier determines that this webpage is news |
lengthyLinkDomain |
integer (0 or 1) |
True (1) if at least 3 <a> 's text contains more than 30 alphanumeric characters |
linkwordscore |
double |
Percentage of words on the page that are in hyperlink's text |
news_front_page |
integer (0 or 1) |
True (1) if StumbleUpon's news classifier determines that this webpage is front-page news |
non_markup_alphanum_characters |
integer |
Page's text's number of alphanumeric characters |
numberOfLinks |
integer |
Number of <a> markups |
numwords_in_url |
double |
Number of words in url |
parametrizedLinkRatio |
double |
A link is parametrized if it's url contains parameters or has an attached onClick event |
spelling_errors_ratio |
double |
Ratio of words not found in wiki (considered to be a spelling mistake) |
label |
integer (0 or 1) |
User-determined label. Either evergreen (1) or non-evergreen (0); available for train.tsv only |
分类结果的AUC值,AUC值越高,排名越靠前。AUC值是分类问题中比较常见的评估指标,尤其针对二分类中正负类别不平衡的情况。
训练集样本数目:6706
测试集样本大小: 3171
(1) 提取样本中文本词
提取样本中三个字段title,body, url中文本字段
(2) 提取数字特征
提取22个数字特征avglinksize,alchemy_category_score,linkwordscore,numwords_in_url等等。
(3) 文本特征预处理
对文本进行相应的预处理,比如去除停用词,低频和高频词,分词等等,然后,对文本特征特征选择。
特征选择代码如下:
fs_num = 75000
term_set_fs= feature_selection.feature_selection(train_doc_terms_list, labels, fs_method)
term_set_fs = term_set_fs[:fs_num]
其中特征选择采用的是信息增益的方法,当然还有互信息和卡方检验的方法。
文本预处理采用对方法如下:
vectorizer = TfidfVectorizer(min_df = 3, max_df = 1, token_pattern=r'\w{1,}', strip_accents = 'unicode', ngram_range=(1, 2), stop_words = 'english',sublinear_tf = True )
(4) 文本特征tf-idf向量化
对训练集和测试集的预处理后的文本进行tf-idf向量化,产生稀疏向量特征。
X_train = vectorizer.transform(train_doc_str_list)
X_test = vectorizer.transform(test_doc_str_list)
(5) 数字特征归一化
这里是把训练集和测试集的数字特征放在一起,然后进行norm归一化。
all_num_feature=sparse.vstack((train_num_feature_matrix, test_num_feature_matrix)).tocsr()
all_num_feature = normalize(all_num_feature, axis = 0)
train_num_feature_matrix= all_num_feature[0:train_num_feature_matrix._shape[0],:]
test_num_feature_matrix= all_num_feature[train_num_feature_matrix._shape[0]:all_num_feature._shape[0],:]
(6) 组合文本tf-idf向量特征和数字特征
X_train= sparse.hstack((X_train,train_num_feature_matrix)).tocsr()
X_test= sparse.hstack((X_test,test_num_feature_matrix)).tocsr()
(1) navie bayes
Navie bayes是在文本分类上一个常用的算法。这也是我本次比赛中第一次尝试的分类算法。
Navie bayes分类时候,我们采用的特征和上面描述有点出入。Bayes 分类只是去文本的特征,不计算tf-idf值,是二值特征。
CountVectorizer(min_df = 3, max_df = 1, token_pattern=r'\w{1,}', strip_accents = 'unicode', ngram_range=(1, 2), stop_words = 'english', binary=True)
分类采用 model = BernoulliNB(alpha=a),
词特征为6000时候,a = 0.5, 10级cv的AUC平均值是0.87.
Leaderboard表现大约0.85左右。
(2) Logistic Regression
LR方法所采用的特征就是如4.1所说。
模型如下:
model = LogisticRegression(penalty='l2', dual=True, tol=0.0001,
C=1, fit_intercept=True, intercept_scaling=1.0,
class_weight='auto')
10级cv的平均结果:0.886
在最开始Leaderboard的表现是0.884左右,可是到最后公布结果是0.87894,出现了over-fit. 更滑级的是当时的第一名也掉到200名左右。
对于overfit的原因,一方面样本量不够大,特征变量数目高于样本数,另外一方面是测试集中有些词未出现在训练集中,尤其在词特征选择的过程中,更根据训练踢出了一些对分类相关性差的词,但是这些词在测试集中会对分类产生误差,导致一些测试集的词特征量过少。所以在词特征选择时候,不能选最优的词个数,不然会造成严重的over-fit。
(3) Ensemble
最后的时候其实有把不用参数的lr模型进行的一个集成,每个模型分配不同的权重,这个权重是人工设定的,非学习方式。
有想过用线性模型把LR,RandomForest, GBT,SVM,几种模型进行加权,学习权重,不过后来因为在GBT,RandomForeset调参上经验不足,后来放弃了。
对于这种分类问题,基本上方法和过程都类似,如上面所说。
一个特征预处理和提取,建立cv集合,在cv上训练和测试。方法上就是单个模型+ensemble,自己在ensemble上水平还有待提高。