• 文本分类简介

文本分类是指在给定分类体系,根据文本内容自动确定文本类别的过程。最基础的分类是归到两个类别中,称为二分类问题,例如电影评论分类,只需要分为“好评”或“差评”。分到多个类别中的称为多分类问题,例如,把名字分类为法语名字、英语名字、西班牙语名字等。

一般来说文本分类大致分为如下几个步骤:

  1. 定义阶段:定义数据以及分类体系,具体分为哪些类别,需要哪些数据。
  2. 数据预处理:对文档做分词、去停用词等准备工作。
  3. 数据提取特征:对文档矩阵进行降维,提取训练集中最有用的特征。
  4. 模型训练阶段:选择具体的分类模型以及算法,训练出文本分类器。
  5. 评测阶段:在测试集上测试并评价分类器的性能。
  6. 应用阶段:应用性能最高的分类模型对待分类文档进行分类。
  • 数据集介绍

Large Movie Review Dataset数据集(aclimdb)由斯坦福大学人工智能实验室于2011年推出,包含25000条训练数据和25000条测试数据,另外包含约50000条没有标签的辅助数据。训练集和测试集又分别包含12500条正例(正向评价pos)和12500负例(负向评价neg)。

aclimdb的目录结构:

训练集正例的目录:

这个里面包含了12500篇英文评论,打开第一个评论看一下里面的文本内容:

Bromwell High is a cartoon comedy. It ran at the same time as some other programs about school life, such as "Teachers". My 35 years in the teaching profession lead me to believe that Bromwell High's satire is much closer to reality than is "Teachers". The scramble to survive financially, the insightful students who can see right through their pathetic teachers' pomp, the pettiness of the whole situation, all remind me of the schools I knew and their students. When I saw the episode in which a student repeatedly tried to burn down the school, I immediately recalled ......... at .......... High. A classic line: INSPECTOR: I'm here to sack one of your teachers. STUDENT: Welcome to Bromwell High. I expect that many adults of my age think that Bromwell High is far fetched. What a pity that it isn't!

  • 数据预处理

首先载入数据,得到训练集数据、训练集标签、测试集数据、测试集标签,其中训练集标签和测试集标签可由正例或负例数据载入时生成全0或全1数组得到,正例标签为1,负例标签为0.

import glob
import numpy as np
def get_data(path_neg, path_pos):
    neg_data = []
    pos_data = []
    files_neg = glob.glob(path_neg)
    files_pos = glob.glob(path_pos)
    for neg in files_neg:
        with open(neg, 'r', encoding='utf-8') as neg_f:
            neg_data.append(neg_f.readline())
    for pos in files_pos:
        with open(pos, 'r', encoding='utf-8') as pos_f:
            pos_data.append(pos_f.readline())
    neg_label = np.zeros(len(neg_data)).tolist()
    pos_label = np.ones(len(pos_data)).tolist()
    corpus = neg_data + pos_data
    labels = neg_label + pos_label
    return corpus, labels

然后对数据进行规范化和预处理,包括利用正则表达式去掉特殊字符,利用nltk包的RegexpTokenizer和tokenize分割单词并去掉标点符号,利用nltk包的stopwords去掉停用词,最后得到规范化的语料库。

import re
from nltk.tokenize import RegexpTokenizer
from nltk.corpus import stopwords
def normalize(corpus):
    normalized_corpus = []
    for text in corpus:
        # 转为小写字母
        text = text.lower().strip()
        # 去掉符号
        text = re.sub(r"<br />", r" ", text)
        text = re.sub(' +', ' ', text)
        text = re.sub(r'(\W)(?=\1)', '', text)
        text = re.sub(r"([.!?])", r" \1", text)
        text = re.sub(r"[^a-zA-Z.!?]+", r" ", text)
        # 分词并去掉标点符号
        tokenizer = RegexpTokenizer(r'\w+')
        tokens = tokenizer.tokenize(text)
        # 去掉停用词
        stopword = stopwords.words('english')
        filtered_tokens = [token for token in tokens if token not in stopword]
        # 重新组成字符串
        filtered_text = ' '.join(filtered_tokens)
        normalized_corpus.append(filtered_text)
    return normalized_corpus

在使用分类器之前,需要对文本提取特征,包括以下几种经典方法:

(1)BOW:最原始的特征集,一个单词就是一个特征,往往一个数据集就会有上万个特征,去停用词可以帮助筛选掉一些对分类没帮助的词。

(2)统计特征:包括TF,IDF,以及合并起来的TF-IDF。

(3)N-Gram:考虑词汇顺序,即N阶马尔可夫链。

本文使用两种方式提取特征,一种是词袋模型,另一种是TF-IDF特征。

使用sklearn包的CountVectorizer和TfidfVectorizer可以分别提取出词袋模型和TF-IDF的特征。

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
def bow_extractor(corpus, ngram_range=(1, 1)):
    vectorizer = CountVectorizer(min_df=1, ngram_range=ngram_range)
    features = vectorizer.fit_transform(corpus)
    return vectorizer, features
def tfidf_extractor(corpus, ngram_range=(1, 1)):
    vectorizer = TfidfVectorizer(min_df=1, norm='l2', smooth_idf=True, use_idf=True, ngram_range=ngram_range)
    features = vectorizer.fit_transform(corpus)
    return vectorizer, features
  • 训练分类器

常见的分类器有逻辑斯蒂回归(LR),支持向量机(SVM),K近邻(KNN),决策树(DT),神经网络(NN)等,可以根据场景选择合适的文本分类器。上述大型电影评论数据集的特征数量很多,可以选择LR或线性SVM。

导入sklearn包的SGDClassifier并指定参数loss='hinge'使用软边际的线性SVM分类器,导入LogisticRegression使用逻辑斯蒂回归分类器。

# 导入分类器
svm = SGDClassifier(loss='hinge', max_iter=100)
lr = LogisticRegression(solver='liblinear')

使用训练集特征和训练集标签训练分类器,并在测试集上预测结果。

def train_predict_evaluate_model(classifier,
                                 train_features, train_labels,
                                 test_features, test_labels):
    # 训练模型
    classifier.fit(train_features, train_labels)
    # 在测试集上预测结果
    predictions = classifier.predict(test_features)
    return predictions

导入sklearn包中的metrics模块并利用测试集的真实标签和预测标签来评估模型的性能,评价指标包括分类的准确率、精度、召回率和F1值。

设TP为真正例,FP为假正例,FN为假反例,TN为真反例:

精度(Accuracy)=(TP+TN)/(TP+FP+FN+TN)

准确率(P,Precision)=TP/(TP+FP),在所有被判断为正确的文档中,有多大比例是正确的。

召回率(R,Recall)=TP/(TP+TN),在所有正确的文档中,有多大比例被我们判为正确。

F1值(F-measure)=2PR/(P+R),既考虑准确率,又考虑召回率。

准确率和召回率是互相影响的,理想情况下是两者都高,即F1值高。

from sklearn import metrics
import numpy as np
def get_metrics(true_labels, predicted_labels):
    print('精度:', np.round(
        metrics.accuracy_score(true_labels,
                               predicted_labels),
    print('准确率:', np.round(
        metrics.precision_score(true_labels,
                                predicted_labels,
                                average='weighted'),
    print('召回率:', np.round(
        metrics.recall_score(true_labels,
                             predicted_labels,
                             average='weighted'),
    print('F1值:', np.round(
        metrics.f1_score(true_labels,
                         predicted_labels,
                         average='weighted'),

主函数如下:

from data_normalize import get_data, normalize
from feature_extractor import bow_extractor, tfidf_extractor
from train_predict_evaluate import train_predict_evaluate_model
from sklearn.linear_model import SGDClassifier
from sklearn.linear_model import LogisticRegression
if __name__ == "__main__":
    train_corpus, train_labels = get_data('./train/neg/*.txt', './train/pos/*.txt')
    test_corpus, test_labels = get_data('./test/neg/*.txt', './test/pos/*.txt')
    norm_train_corpus = normalize(train_corpus)
    norm_test_corpus = normalize(test_corpus)
    # 词袋模型特征
    bow_vectorizer, bow_train_features = bow_extractor(norm_train_corpus)
    bow_test_features = bow_vectorizer.transform(norm_test_corpus)
    # tfidf 特征
    tfidf_vectorizer, tfidf_train_features = tfidf_extractor(norm_train_corpus)
    tfidf_test_features = tfidf_vectorizer.transform(norm_test_corpus)
    # 导入分类器
    svm = SGDClassifier(loss='hinge', max_iter=100)
    lr = LogisticRegression(solver='liblinear')
    # 基于词袋模型特征的逻辑斯蒂回归模型
    print("基于词袋模型特征的逻辑斯蒂回归模型")
    lr_bow_predictions = train_predict_evaluate_model(classifier=lr,
                                                      train_features=bow_train_features,
                                                      train_labels=train_labels,
                                                      test_features=bow_test_features,
                                                      test_labels=test_labels)
    # 基于词袋模型的支持向量机模型
    print("基于词袋模型的支持向量机模型")
    svm_bow_predictions = train_predict_evaluate_model(classifier=svm,
                                                       train_features=bow_train_features,
                                                       train_labels=train_labels,
                                                       test_features=bow_test_features,
                                                       test_labels=test_labels)
    # 基于tfidf的逻辑斯蒂回归模型
    print("基于tfidf的逻辑斯蒂回归模型")
    lr_tfidf_predictions = train_predict_evaluate_model(classifier=lr,
                                                        train_features=tfidf_train_features,
                                                        train_labels=train_labels,
                                                        test_features=tfidf_test_features,
                                                        test_labels=test_labels)
    # 基于tfidf的支持向量机模型
    print("基于tfidf的支持向量机模型")
    svm_tfidf_predictions = train_predict_evaluate_model(classifier=svm,
                                                         train_features=tfidf_train_features,
                                                         train_labels=train_labels,
                                                         test_features=tfidf_test_features,
                                                         test_labels=test_labels)

训练结果如下:

基于词袋模型特征的逻辑斯蒂回归模型
精度: 0.86
准确率: 0.86
召回率: 0.86
F1值: 0.86
基于词袋模型的支持向量机模型
精度: 0.85
准确率: 0.85
召回率: 0.85
F1值: 0.85
基于tfidf的逻辑斯蒂回归模型
精度: 0.88
准确率: 0.88
召回率: 0.88
F1值: 0.88
基于tfidf的支持向量机模型
精度: 0.88
准确率: 0.88
召回率: 0.88
F1值: 0.88

从训练结果中可以看出,TF-IDF稍微好于词袋模型,而使用逻辑斯蒂回归或支持向量机分类器的效果差别不大。

首先,文本数据属于非结构化数据,一般要转换成结构化的数据,一般是将文本转换成“文档-词频矩阵”,矩阵中的元素使用词频或者TF-IDFTF-IDF的主要思想是:如果某一个词或短语在一篇文章中出现的频率高,并且在其他文章中很少出现,则认为此词或短语具有很好的类别区分能力,适合用于分类。TF-IDF=TF*IDF IDF主要思想:如果包含词条t的文档越少,也就是n越小,IDF越到,则说明词条t具 import pandas as pd from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression from sklearn.naive_bayes import MultinomialNB from sklearn.svm TF-IDF概述 TF-IDF是Term Frequency - Inverse Document Frequency的缩写,即“词频-逆文本频率”。它由两部分组成,TF和IDF。 前面的TF也就是我们前面说到的词频,我们之前做的向量化也就是做了文本中各个词的出现频率统计,并作为文本特征,这个很好理解。关键是后面的这个IDF,即“逆文本频率”如何理解。在上一节中,我们讲到几乎所有文本都会出现... 这几周因为在做竞赛所以没怎么看论文刷题写博客,今天抽时间把竞赛用到的东西总结一下。先试水了一个很小众的比赛–文因互联,由AI100举办,参赛队不足20个,赛题类型是文本分类。选择参赛的主要原因是其不像阿里们举办的竞赛那样,分分钟就干一件事就是特征工程和调参,然后数据又多又乱,不适合入门。其次一个原因就是目前我的研究方向就是NLP,之前也做过一个文本分类的东西,所以就参赛了。这里将主要介绍我在比赛中用 logistic回归虽然说是回归,但确是为了解决分类问题,是二分类任务的首选方法,简单来说,输出结果不是0就是1 举个简单的例子: 癌症检测:这种算法输入病理图片并且应该辨别患者是患有癌症(1)或没有癌症(0) 2.logistic回归和线性回归的关系 逻辑回归(Logistic Regression)与线性回归(Linear Regression)都是一种广义线性模型(generalized linear model)。 逻辑回归假设因变量 y 服从二项分布,而线性回归假 本项目应用应用两种特征提取方法进行支持向量机模型中文邮件分类研究,通过数据预处理、特征工程、模型构建、模型评估等工作,最终模型的F1分值达到0.97,这在文本分类领域,是非常棒的效果,可以应用于实际工作中。本次机器学习项目实战所需的资料,项目资源如下项目说明链接https提取码bcbp网盘如果失效,可以添加博主微信zy10178083httpshttpshttpshttpshttpshttpshttpshttpshttpshttpshttpshttps。...... 文本情感分类 文本分类是自然语言处理的一个常见任务,它把一段不定长的文本序列变换为文本的类别。本节关注它的一个子问题:使用文本情感分类来分析文本作者的情绪。这个问题也叫情感分析,并有着广泛的应用。 同搜索近义词和类比词一样,文本分类也属于词嵌入的下游应用。在本节中,我们将应用预训练的词向量和含多个隐藏层的双向循环神经网络与卷积神经网络,来判断一段不定长的文本序列中包含的是正面还是负面的情... 中文分词(Chinese Word Segmentation)指的是将一个汉字序列切分成一个一个单独的词。中文分词是文本挖掘的基础,对于输入的一段中文,成功的进行中文分词,可以达到电脑自动识别语句含义的效果。   TF-IDF(term frequency–inverse document frequency)是一种用于信息搜索和信息挖掘的常用加权技术。在搜索、文献分类和其他相关领域有广泛的 简单文本分类实战 项目所需的数据都已经爬取完毕,大部分爬到的文本都是和主题相关的,少部分文本和主题无关。受垃圾邮件分类的启发,我准备标注部分数据训练一个简单的分类器,来判断文本相关与否,以便对数据做一个简单的清洗。 连接数据库,导入数据 import pymysql from sklearn import model_selection import numpy as np def prepare_datasets(): conn = pymysql.connect(host='localhost' Pytorch官方实验的食用方法 pytorch官网上关于NLP的实验有两类,https://pytorch.org/tutorials/index.html#text和https://pytorch.org/tutorials/beginner/deep_learning_nlp_tutorial.html,两份教程的风格比较类似,倾向于快速原型,不需要下载,预处理数据集,而是通过几个简单的样例...