Press "Enter" to skip to content

以BBC新闻文章为例:应用XGBoost等算法进行文本分类

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

 

图片来源:unsplash.com/@knightwill

 

本文将以BBC新闻文章分类为例,讨论不同的文本分类技术。同时,本文将讨论如何用不同向量空间模型代表文本数据。

 

为解决此问题,将使用到Python、Sci-kit-learn、Genism和Xgboost库等工具。

 

 

获取数据

 

 

本问题涉及到的数据可以在Kaggle上找到(https://www.kaggle.com/yufengdev/bbc-fulltext-and-category)。本数据集包含BBC新闻文本及其双栏CSV格式的分类列表,展示如下:

 

import pandas as pdbbc_text_df = pd.read_csv('../data/bbc-text.csv')bbc_text_df.head()

 

 

表中似乎含有许多长文本。后续章节将对其作详细论述。现在的问题是:若给定一个“文本”,就需要预测其类别。这无疑是一个多累文本分类的问题。

 

 

数据探索及视觉化呈现

 

首先,我们需要知道有哪些类别。

 

%matplotlib inlineimport seaborn as
 snsimport matplotlib.pyplot as pltplt.figure
(figsize=(12,5))sns.countplot(x=bbc_text_df.category, 
color='green')plt.title('BBC text class distribution', 
fontsize=16)plt.ylabel('Class Counts', fontsize=16)plt.
xlabel('Class Label', fontsize=16)plt.xticks(rotation='vertical');

 

 

由图可知,有五个类别。可将其称为“类”。显然,该类别的分配并无太多偏斜。

 

下一步是弄清数据集该“文本”领域中包含何种内容。因此需要先清理文本。

 

文本清理通常包含以下步骤:

 

1. 英文字母小写化

 

2. 去除标点

 

3. 去除整数、数字

 

4. 去除多余空格

 

5. 去除标签(如<html>, <p>等)

 

6. 去除停用词(如and、to、the等)

 

7. 词干提取(将单词转换至词源形式

 

此次使用了Python的“genism”库进行文本清理工作。

 

from gensim import utilsimport gensim.parsing.preprocessing as gspfilters = [           
gsp.strip_tags,            
gsp.strip_punctuation,           
gsp.strip_multiple_whitespaces,           
gsp.strip_numeric,           
gsp.remove_stopwords,            
gsp.strip_short,            
gsp.stem_text          ]def clean_text(s):    
s = s.lower()    
s = utils.to_unicode(s)    
for f in filters:        s = f(s)    return s

 

可应用“clean_text”功能完成这项任务。

 

把记录的文本领域的第一段内容打印出来。

 

bbc_text_df.iloc[2,1]

 

 

清理后

 

clean_text(bbc_text_df.iloc[2,1])

 

 

文本可能稍微缺乏语法逻辑,但这是为了便于理解。

 

接下来会编写一个功能,将“文本”内容视觉化呈现为“文字云”。

 

%matplotlib inlinefrom wordcloud import WordClouddef plot_word_cloud(text):    
wordcloud_instance = WordCloud(width = 800, height = 800,                 
background_color ='black',                 
stopwords=None,                
min_font_size = 10).generate(text)                  
plt.figure(figsize = (8, 8), facecolor = None)     
plt.imshow(wordcloud_instance)     
plt.axis("off")     
plt.tight_layout(pad = 0) plt.show()

 

需要连结所有文本,并将其导入此功能。

 

texts = ''for index, item in bbc_text_df.iterrows():   
 texts = texts + ' ' + clean_text(item['text'])   
 plot_word_cloud(texts)

 

会出现如下结果:

 

 

单词越大,意味着其出现频率越高。所以“年 (year) ”、“时间 (time) ”、“人 (peopl) ”是出现频率最高的词。

 

现在进行更深入的分析:在某一特定“类别”理,“文本”的“文字云”。

 

为其编写一项一般/通用功能。

 

def plot_word_cloud_for_category(bbc_text_df, category):    
text_df = bbc_text_df.loc[bbc_text_df['category'] == str(category)]    
texts = ''    for index, item in text_df.iterrows():        
texts = texts + ' ' + clean_text(item['text'])    
plot_word_cloud(texts)

 

比如,“技术”这一“类别”的“文字云”

 

plot_word_cloud_for_category(bbc_text_df,'tech')

 

 

因此,“技术”这一类别中最常出现的词是“人 (peopl)”、“techlog”、“游戏 (game)”等。

 

而对于“”类别:

 

plot_word_cloud_for_category(bbc_text_df,'sport')

 

 

最常出现的词是“plai”、“游戏 (game) ”、“运动员 (player) ”、“胜利 (win) ”、“比赛 (match) ”、“英格兰 (England) ”等。

 

对于“政治”类别:

 

plot_word_cloud_for_category(bbc_text_df,'politics')

 

 

最常出现的词是“治理 (govern) ”、“人 (people) ”、“布莱尔 (blair) ”、“国家 (countri) ”、“部长 (Minist) ”等。

 

毫无疑问,每一个类别中都有自己独有的词汇。也可以这样理解:每一个“文本”的内容都在暗示某个语境,从而决定其类别。

 

需要进行向量空间分析,并将其应用于模型,以证实以上推断。

 

 

 

向量空间建模及构建管道

 

对于任何自然语言处理问题,都有必要进行向量空间建模。以两个最常见的向量空间模型为例:Doc2Vec和Tf-Idf。首先,把数据分成特征和类别。

 

df_x = bbc_text_df['text']df_y = bbc_text_df['category']

 

Doc2Vec

 

使用“Genism”库的Doc2Vec编写一般/通用“Doc2VecTransfoemer”。

 

from gensim.models.doc2vec import TaggedDocument, Doc2Vecfrom sklearn.base import 
BaseEstimatorfrom sklearn import utils as skl_utilsfrom tqdm import tqdmimport 
multiprocessingimport numpy as npclass Doc2VecTransformer(BaseEstimator):   
 def __init__(self, vector_size=100, learning_rate=0.02, epochs=20):        
self.learning_rate = learning_rate        
self.epochs = epochs        
self._model = None        
self.vector_size = vector_size        
self.workers = multiprocessing.cpu_count() - 1    
def fit(self, df_x, df_y=None):        
tagged_x = [TaggedDocument(clean_text(row).split(), 
[index]) for index, row in enumerate(df_x)]       
model = Doc2Vec(documents=tagged_x, vector_size=self.vector_size,
 workers=self.workers)        
for epoch in range(self.epochs):            
model.train(skl_utils.shuffle([x for x in tqdm(tagged_x)]), 
total_examples=len(tagged_x), epochs=1)            
model.alpha -= self.learning_rate            
model.min_alpha = model.alpha        
self._model = model        
return self    
def transform(self, df_x):        
return np.asmatrix(np.array([self._model.
infer_vector(clean_text(row).split())                                     
for index, row in enumerate(df_x)]))

 

应用该转换器,可以看到“DocVec”如下:

 

doc2vec_trf = Doc2VecTransformer()doc2vec_features = doc2vec_trf.fit(df_x).
transform(df_x)doc2vec_features

 

 

因此,这是一组文本数据的数字化呈现。可以把这个数字特征应用到机器学习算法中。下面以LogisticRegression, RandomForest和XGBoost为例进行操作。

 

对于每一个案例,都应用数据集对模型进行五层/级交叉验证并试运行。精确度得分将会是五个层级的平均分。

 

Doc2Vec和LogisticRegression管道

 

 

精确度变得非常低!!

 

再来看其它分类器。

 

Doc2Vec和RandomForest管道

 

from sklearn.pipeline import Pipelinefrom sklearn.linear_model import 
LogisticRegressionfrom sklearn.model_selection import cross_val_scorepl_
log_reg = Pipeline(steps=[('doc2vec',Doc2VecTransformer()),                             
('log_reg', LogisticRegression(multi_class='multinomial', solver='saga',
 max_iter=100))])scores = cross_val_score(pl_log_reg, df_x, df_y, cv=5,scoring='accuracy')
print('Accuracy for Logistic Regression: ', scores.mean())

 

 

精确度也不是很高!!

 

Doc2Vec和XGBoost管道

 

import xgboost as xgbpl_xgb = Pipeline(steps=[('doc2vec',
Doc2VecTransformer()),                         
('xgboost', xgb.XGBClassifier(objective='multi:softmax'))])
scores = cross_val_score(pl_xgb, df_x, df_y, cv=5)
print('Accuracy for XGBoost Classifier : ', scores.mean())

 

 

精确度并未提高多少。

 

“Doc2Vec”运行状况并不良好。

 

下面看“Tf-Idf”向量空模型。

 

Tf-Idf

 

为“Tf-Idf”编写一个相似的转换器。

 

from sklearn.feature_extraction.text import TfidfVectorizerclass 
Text2TfIdfTransformer(BaseEstimator):    
def __init__(self):        
self._model = TfidfVectorizer()        
pass    def fit(self, df_x, df_y=None):       
 df_x = df_x.apply(lambda x : clean_text(x))        
self._model.fit(df_x)        
return self    
def transform(self, df_x):        
return self._model.transform(df_x)

 

那幺,文本会变成什幺样呢?

 

tfidf_transformer = Text2TfIdfTransformer()tfidf_vectors = 
tfidf_transformer.fit(df_x).transform(df_x)

 

将其维数打印出来。

 

tfidf_vectors.shape

 

 

[“0”]标记总计出现18754次。

 

print(tfidf_vectors)

 

 

现在把此模型运用到实际机器学习模型中。

 

Tf-Idf & LogisticRegression

 

pl_log_reg_tf_idf = Pipeline(steps=[('tfidf',Text2TfIdf
Transformer()),                             
('log_reg', LogisticRegression(multi_class='multinomial', 
solver='saga', max_iter=100))])scores = cross_val_score(pl_log_reg_tf_idf, df_x, 
df_y, cv=5,scoring='accuracy')print('Accuracy 
for Tf-Idf & Logistic Regression: ', scores.mean())

 

 

精确度很高!!

 

Tf-Idf & RandomForest

 

pl_random_forest_tf_idf =
 Pipeline(steps=[('tfidf',Text2TfIdfTransformer()),                                   
('random_forest', RandomForestClassifier())])scores =
 cross_val_score(pl_random_forest_tf_idf, df_x, df_y, cv=5,scoring='accuracy')
print('Accuracy for Tf-Idf & RandomForest : ', scores.mean())

 

 

Tf-Idf & XGBoost

 

pl_xgb_tf_idf = Pipeline(steps=[('tfidf',Text2TfIdfTransformer()),                         
('xgboost', xgb.XGBClassifier(objective='multi:softmax'))])
scores = cross_val_score(pl_xgb_tf_idf, df_x, df_y, cv=5)
print('Accuracy for Tf-Idf & XGBoost Classifier : ', scores.mean())

 

 

最后这一个精确度最高!!

 

毫无疑问,使用Tf-Idf & XGBoost结合模型能够解决本案例的问题。

 

 

结果解读

 

尽管在自然语言处理中,“DocVec”模型比“Tf-Idf”模型更高级,但我们的案例证明,后者效果更佳。我们分别使用了基于线性、袋状以及推进型的分类器。

 

原因可以这幺理解。在我们的数据集中,每一个“文本”领域包含了一些决定其类别的高频单词/。因此,应用一个对语境/上下文敏感的模型会使问题更为复杂、(或者)混淆信息。某些文本类别包含一些高频出现的标记,这些标记提供了大量数值以定义“Tf-Idf”模型。同时,“文本”是细分领域的。

 

比如,“布莱尔 (blair) ”一词更可能出现在“政治”类别,而非“运动”类别。因此,像这样的词对“Tf-Idf”模型起了作用。

 

而且,“Doc2Vec”模型更适合应用于语法正确的文本中。

 

而我们的案例文本本质上过于粗糙。

 

“维基百科”文本就是一个语法正确的文本。

 

同时,大量案例和数据科学家的实验证明,虽然“Tf-Idf”模型次于”DocVec”模型,但前者对于细分领域的文本分类更为有效。

 

结论

 

实验结束。我们对所有分类器和向量空间模型的组合进行了测试。GitHub上有关于这一实验的Jupyter笔记。

 

传送门:https://github.com/avisheknag17/public_ml_models/blob/master/bbc_articles_text_classification/notebook/text_classification_xgboost_others.ipynb?source=post_page

Be First to Comment

发表评论

邮箱地址不会被公开。 必填项已用*标注