以BBC新闻文章为例:应用XGBoost等算法进行文本分类
原标题:以BBC新闻文章为例:应用XGBoost等算法进行文本分类
来源:今日头条 链接:https://www.toutiao.com/a6722243537355670030/
本文将以BBC新闻文章分类为例,讨论不同的文本分类技术。同时,本文将讨论如何用不同向量空间模型代表文本数据。
为解决此问题,将使用到Python、Sci-kit-learn、Genism和Xgboost库等工具。
获取数据
本问题涉及到的数据可以在Kaggle上找到(https://www.kaggle.com/yufengdev/bbc-fulltext-and-category)。本数据集包含BBC新闻文本及其双栏CSV格式的分类列表,展示如下:
import pandas as pd bbc_text_df = pd.read_csv('../data/bbc-text.csv') bbc_text_df.head()
表中似乎含有许多长文本。后续章节将对其作详细论述。现在的问题是:若给定一个“文本”,就需要预测其类别。这无疑是一个多累文本分类的问题。
数据探索及视觉化呈现
首先,我们需要知道有哪些类别。
%matplotlib inline import seaborn as sns import matplotlib.pyplot as plt plt.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 utils import gensim.parsing.preprocessing as gsp filters = [ 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 inline from wordcloud import WordCloud def 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, Doc2Vec from sklearn.base import BaseEstimator from sklearn import utils as skl_utils from tqdm import tqdm import multiprocessing import numpy as np class 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 Pipeline from sklearn.linear_model import LogisticRegression from sklearn.model_selection import cross_val_score pl_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 xgb pl_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 TfidfVectorizer class 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',Text2TfIdfTransformer()), ('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---------------------------
一THE END一
免责声明:本文来自互联网新闻客户端自媒体,不代表本网的观点和立场。
合作及投稿邮箱:E-mail:editor@tusaishared.com
热门资源
应用笔画宽度变换...
应用背景:是盲人辅助系统,城市环境中的机器导航...
端到端语音识别时...
从上世纪 50 年代诞生到 2012 年引入 DNN 后识别效...
人体姿态估计的过...
人体姿态估计是计算机视觉中一个很基础的问题。从...
GAN之根据文本描述...
一些比较好玩的任务也就应运而生,比如图像修复、...
谷歌发布TyDi QA语...
为了鼓励对多语言问答技术的研究,谷歌发布了 TyDi...
智能在线
400-630-6780
聆听.建议反馈
E-mail: support@tusaishared.com