THUCNews新闻文本分类-tfidf+sklearn2

本文使用的是和鲸社区现有数据集,代码也在和鲸社区公开,fork之后可以直接运行。

本文中所用的数据集清华NLP组提供的THUCNews新闻文本分类数据集的一个子集(原始的数据集大约74万篇文档,训练起来需要花较长的时间)。 本次训练使用了其中的体育, 财经, 房产, 家居, 教育, 科技, 时尚, 时政, 游戏, 娱乐10个分类,每个分类6500条,总共65000条新闻数据。项目在和鲸社区的平台上跑的,数据集直接引用了和鲸的数据集,每个分类6500条,总共65000条新闻数据。

数据集划分如下: cnews.train.txt: 训练集(50000条) cnews.val.txt: 验证集(5000条) cnews.test.txt: 测试集(10000条)

本文使用了较为传统的tfidf算法实现文本的向量化,并使用sklearn中的经典分类算法对文本数据进行分类。

import os
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import metrics
from sklearn.preprocessing import LabelEncoder
from collections import Counter
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn import metrics
from pprint import pprint
from time import time
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline

from sklearn.metrics import classification_report

from data_loader.cnews_loader import *
%config InlineBackend.figure_format = 'retina'
%matplotlib inline

预处理

# 设置数据读取、模型、结果保存路径
base_dir = '/home/kesci/input/new3021'
train_dir = os.path.join(base_dir, 'cnews.train.txt')
test_dir = os.path.join(base_dir, 'cnews.test.txt')
val_dir = os.path.join(base_dir, 'cnews.val.txt')
vocab_dir = os.path.join(base_dir, 'cnews.vocab.txt')
save_dir = 'checkpoints/textcnn'
save_path = os.path.join(save_dir, 'best_validation')

读取数据使用了data_loader.cnews_loader中的read_file读取数据。

train_contents, train_labels = read_file(train_dir)
test_contents, test_labels = read_file(test_dir)
val_counts = Counter(train_labels)
val_counts

    Counter({'体育': 5000,
             '娱乐': 5000,
             '家居': 5000,
             '房产': 5000,
             '教育': 5000,
             '时尚': 5000,
             '时政': 5000,
             '游戏': 5000,
             '科技': 5000,
             '财经': 5000})
             
    time: 577 ms

移除特殊字符

import re
#去除文本中的表情字符(只保留中英文和数字)
def clear_character(sentence):
    pattern1= '\[.*?\]'     
    pattern2 = re.compile('[^\u4e00-\u9fa5^a-z^A-Z^0-9]')   
    line1=re.sub(pattern1,'',sentence)
    line2=re.sub(pattern2,'',line1)   
    new_sentence=''.join(line2.split()) #去除空白
    return new_sentence
train_text=list(map(lambda s: clear_character(s), train_contents))
test_text=list(map(lambda s: clear_character(s), test_contents))

分词

使用了jieba分词。

import jieba
train_seg_text=list(map(lambda s: jieba.lcut(s), train_text))
test_seg_text=list(map(lambda s: jieba.lcut(s), test_text))
    Building prefix dict from the default dictionary ...
    Dumping model to file cache /tmp/jieba.cache
    Loading model cost 0.792 seconds.
    Prefix dict has been built succesfully.
    
    time: 3min 39s

去除停用词

stop_words_path = "/home/kesci/work/data_loader/百度停用词列表.txt"
def get_stop_words():
    file = open(stop_words_path, 'rb').read().decode('gbk').split('\r\n')
    return set(file)
stopwords = get_stop_words()
# 去掉文本中的停用词
def drop_stopwords(line, stopwords):
    line_clean = []
    for word in line:
        if word in stopwords:
            continue
        line_clean.append(word)
    return line_clean
train_st_text=list(map(lambda s: drop_stopwords(s,stopwords), train_seg_text))
test_st_text=list(map(lambda s: drop_stopwords(s,stopwords), test_seg_text))

标签映射

le = LabelEncoder()
le.fit(train_labels)
LabelEncoder()
label_train_id=le.transform(train_labels)
label_test_id=le.transform(test_labels)
train_c_text=list(map(lambda s: ' '.join(s), train_st_text))
test_c_text=list(map(lambda s: ' '.join(s), test_st_text))
tfidf_model = TfidfVectorizer(binary=False,token_pattern=r"(?u)\b\w+\b")
train_Data = tfidf_model.fit_transform(train_c_text)
test_Data = tfidf_model.transform(test_c_text)

LR模型

逻辑回归(Logistic Regression)是一种用于解决二分类(0 or 1)问题的机器学习方法,用于估计某种事物的可能性。比如某用户购买某商品的可能性,某病人患有某种疾病的可能性,以及某广告被用户点击的可能性等。

逻辑回归(Logistic Regression)与线性回归(Linear Regression)都是一种广义线性模型(generalized linear model)。逻辑回归假设因变量 y 服从伯努利分布,而线性回归假设因变量 y 服从高斯分布。 因此与线性回归有很多相同之处,去除Sigmoid映射函数的话,逻辑回归算法就是一个线性回归。可以说,逻辑回归是以线性回归为理论支持的,但是逻辑回归通过Sigmoid函数引入了非线性因素,因此可以轻松处理0/1分类问题。

from sklearn.linear_model import LogisticRegression
'''LR模型分类训练'''
classifier=LogisticRegression()
classifier.fit(train_Data, label_train_id)
pred = classifier.predict(test_Data)
from sklearn.metrics import classification_report
print(classification_report(label_test_id, pred,digits=4))
                  precision    recall  f1-score   support
    
               0     0.9970    0.9950    0.9960      1000
               1     0.9850    0.9850    0.9850      1000
               2     0.9651    0.8560    0.9073      1000
               3     0.8963    0.9080    0.9021      1000
               4     0.9680    0.9070    0.9365      1000
               5     0.9676    0.9850    0.9762      1000
               6     0.9251    0.9630    0.9437      1000
               7     0.9682    0.9750    0.9716      1000
               8     0.9438    0.9910    0.9668      1000
               9     0.9457    0.9920    0.9683      1000
    
        accuracy                         0.9557     10000
       macro avg     0.9562    0.9557    0.9553     10000
    weighted avg     0.9562    0.9557    0.9553     10000
    
    time: 1min 9s

SGDClassifier

与其他线性分类器类似,采用了随机梯度下降法,以mini-batch来做梯度下降,在处理大数据的情况下收敛更快。
随机梯度下降法。每次迭代都随机从训练集中抽取出1个样本,在样本量极其大的情况下,可能不用抽取出所有样本,就可以获得一个损失值在可接受范围之内的模型了。缺点是由于单个样本可能会带来噪声,导致并不是每次迭代都向着整体最优方向前进。
主要应用在大规模稀疏数据问题上,经常用在文本分类及自然语言处理。假如数据是稀疏的,该模块的分类器可轻松解决如下问题:超过105的训练样本、超过105的features。

from sklearn.linear_model import SGDClassifier

clf = SGDClassifier(loss="hinge", penalty="l2")
clf.fit(train_Data, label_train_id)
pred = clf.predict(test_Data)
print(classification_report(label_test_id, pred,digits=4))
                  precision    recall  f1-score   support
    
               0     0.9980    1.0000    0.9990      1000
               1     0.9841    0.9880    0.9860      1000
               2     0.9793    0.8500    0.9101      1000
               3     0.9105    0.9160    0.9133      1000
               4     0.9755    0.9160    0.9448      1000
               5     0.9519    0.9900    0.9706      1000
               6     0.9370    0.9660    0.9513      1000
               7     0.9771    0.9820    0.9796      1000
               8     0.9447    0.9910    0.9673      1000
               9     0.9403    0.9930    0.9660      1000
    
        accuracy                         0.9592     10000
       macro avg     0.9598    0.9592    0.9588     10000
    weighted avg     0.9598    0.9592    0.9588     10000
    
    time: 4.24 s

DecisionTreeClassifier

决策树是一种树型结构,其中每个内部节结点表示在一个属性上的测试,每一个分支代表一个测试输出,每个叶结点代表一种类别。
决策树学习是以实例为基础的归纳学习,采用的是自顶向下的递归方法,其基本思想是以信息熵为度量构造一棵熵值下降最快的树。到叶子节点的处的熵值为零,此时每个叶结点中的实例都属于同一类。在学习的过程中,不需要使用者了解过多知识背景,只需要对训练实例进行较好的标注,就能够进行学习了。

from sklearn.tree import DecisionTreeClassifier

clf = DecisionTreeClassifier(criterion = 'entropy' ,random_state = 0)
clf.fit(train_Data, label_train_id)
pred = clf.predict(test_Data)
print(classification_report(label_test_id, pred,digits=4))
                 precision    recall  f1-score   support
    
               0     0.9619    0.9850    0.9733      1000
               1     0.9360    0.9070    0.9213      1000
               2     0.8000    0.5440    0.6476      1000
               3     0.9681    0.9700    0.9690      1000
               4     0.7939    0.7240    0.7573      1000
               5     0.8329    0.9170    0.8729      1000
               6     0.7935    0.8070    0.8002      1000
               7     0.8624    0.9090    0.8851      1000
               8     0.8170    0.8930    0.8533      1000
               9     0.8458    0.9710    0.9041      1000
    
        accuracy                         0.8627     10000
       macro avg     0.8612    0.8627    0.8584     10000
    weighted avg     0.8612    0.8627    0.8584     10000
    
    time: 1min 45s

RandomForestClassifier

随机森林是一个元估计器,它适合数据集的各个子样本上的多个决策树分类器,并使用平均值来提高预测精度和控制过度拟合。 子样本大小始终与原始输入样本大小相同,但如果bootstrap = True(默认值),则会使用替换来绘制样本。

from sklearn.ensemble import RandomForestClassifier
import numpy as np
clf = RandomForestClassifier(criterion='gini')  
clf.fit(train_Data,label_train_id)
pred = clf.predict(test_Data)
print(classification_report(label_test_id, pred,digits=4))
                  precision    recall  f1-score   support
    
               0     0.9831    0.9870    0.9850      1000
               1     0.9221    0.9700    0.9454      1000
               2     0.7577    0.5690    0.6499      1000
               3     0.8127    0.9330    0.8687      1000
               4     0.8690    0.7960    0.8309      1000
               5     0.9248    0.9220    0.9234      1000
               6     0.8408    0.8660    0.8532      1000
               7     0.8966    0.9020    0.8993      1000
               8     0.9325    0.9390    0.9357      1000
               9     0.8962    0.9760    0.9344      1000
    
        accuracy                         0.8860     10000
       macro avg     0.8835    0.8860    0.8826     10000
    weighted avg     0.8835    0.8860    0.8826     10000
    
    time: 31.6 s

svm

支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机;SVM还包括核技巧,这使它成为实质上的非线性分类器。SVM的的学习策略就是间隔最大化,可形式化为一个求解凸二次规划的问题,也等价于正则化的合页损失函数的最小化问题。SVM的的学习算法就是求解凸二次规划的最优化算法。

from sklearn import svm
import numpy as np
clf = svm.SVC()       # kernel = 'linear' or 'rbf' (default) or 'poly' or custom kernels; penalty C = 1.0 (default)
# Option 2: NuSVC()
# clf = svm.NuSVC() 
# Option 3: LinearSVC()
# clf = svm.LinearSVC()     # penalty : str, ‘l1’ or ‘l2’ (default=’l2’)
clf.fit(train_Data,label_train_id)
pred = clf.predict(test_Data)
print(classification_report(label_test_id, pred,digits=4))

                  precision    recall  f1-score   support
    
               0     1.0000    0.6530    0.7901      1000
               1     0.9913    0.6850    0.8102      1000
               2     0.6515    0.7030    0.6763      1000
               3     0.9700    0.3880    0.5543      1000
               4     1.0000    0.2690    0.4240      1000
               5     1.0000    0.6090    0.7570      1000
               6     0.6097    0.9450    0.7412      1000
               7     0.9927    0.1360    0.2392      1000
               8     0.2565    0.9990    0.4082      1000
               9     1.0000    0.7170    0.8352      1000
    
        accuracy                         0.6104     10000
       macro avg     0.8472    0.6104    0.6236     10000
    weighted avg     0.8472    0.6104    0.6236     10000
    
    time: 2h 16min 32s

核支持向量分类,和SVC类似,不同的是通过一个参数空值支持向量的个数。

from sklearn import svm
import numpy as np
# clf = svm.SVC()       # kernel = 'linear' or 'rbf' (default) or 'poly' or custom kernels; penalty C = 1.0 (default)
# Option 2: NuSVC()
clf = svm.NuSVC() 
# Option 3: LinearSVC()
# clf = svm.LinearSVC()     # penalty : str, ‘l1’ or ‘l2’ (default=’l2’)
clf.fit(train_Data,label_train_id)
pred = clf.predict(test_Data)
print(classification_report(label_test_id, pred,digits=4))

                  precision    recall  f1-score   support
    
               0     0.9979    0.9430    0.9697      1000
               1     0.9862    0.9290    0.9567      1000
               2     0.3267    0.8180    0.4669      1000
               3     0.7879    0.7060    0.7447      1000
               4     0.9816    0.6920    0.8117      1000
               5     0.9949    0.7810    0.8751      1000
               6     0.8250    0.8060    0.8154      1000
               7     0.9891    0.4550    0.6233      1000
               8     0.2503    0.2460    0.2481      1000
               9     0.9564    0.7680    0.8519      1000
    
        accuracy                         0.7144     10000
       macro avg     0.8096    0.7144    0.7364     10000
    weighted avg     0.8096    0.7144    0.7364     10000
    
    time: 1h 7min 16s

使用’linear’核方法,计算速度比SVM快很多。

from sklearn import svm
import numpy as np
# clf = svm.SVC()       # kernel = 'linear' or 'rbf' (default) or 'poly' or custom kernels; penalty C = 1.0 (default)
# Option 2: NuSVC()
# clf = svm.NuSVC() 
# Option 3: LinearSVC()
clf = svm.LinearSVC()     # penalty : str, ‘l1’ or ‘l2’ (default=’l2’)
clf.fit(train_Data,label_train_id)
pred = clf.predict(test_Data)
print(classification_report(label_test_id, pred,digits=4))

                  precision    recall  f1-score   support
    
               0     0.9970    1.0000    0.9985      1000
               1     0.9889    0.9840    0.9865      1000
               2     0.9627    0.8780    0.9184      1000
               3     0.9147    0.9110    0.9128      1000
               4     0.9660    0.9100    0.9372      1000
               5     0.9725    0.9900    0.9812      1000
               6     0.9467    0.9590    0.9528      1000
               7     0.9666    0.9840    0.9752      1000
               8     0.9521    0.9940    0.9726      1000
               9     0.9377    0.9930    0.9645      1000
    
        accuracy                         0.9603     10000
       macro avg     0.9605    0.9603    0.9600     10000
    weighted avg     0.9605    0.9603    0.9600     10000
    
    time: 4.99 s

ComplementNB

贝叶斯决策理论的核心思想,即选择具有最高概率的决策。朴素贝叶斯分类器的训练过程就是基于训练集D来估计类先验概率p©,并为每个属性估计条件概率P(xi|c)。补码朴素贝叶斯(ComplementNB,cNB)是标准多项式朴素贝叶斯(MNB)算法的一种自适应算法,特别适用于不平衡的数据集。

from sklearn.naive_bayes import ComplementNB

clf = ComplementNB()
clf.fit(train_Data,label_train_id)
pred = clf.predict(test_Data)
print(classification_report(label_test_id, pred,digits=4))
                  precision    recall  f1-score   support
    
               0     0.9940    0.9990    0.9965      1000
               1     0.9482    0.9890    0.9682      1000
               2     0.9798    0.7260    0.8340      1000
               3     0.8016    0.9210    0.8571      1000
               4     0.9413    0.9300    0.9356      1000
               5     0.9722    0.9810    0.9766      1000
               6     0.9525    0.9220    0.9370      1000
               7     0.9879    0.9790    0.9834      1000
               8     0.9441    0.9960    0.9693      1000
               9     0.9477    0.9960    0.9712      1000
    
        accuracy                         0.9439     10000
       macro avg     0.9469    0.9439    0.9429     10000
    weighted avg     0.9469    0.9439    0.9429     10000
    
    time: 386 ms

决策树集成

AdaBoost是adaptive boosting的缩写,boosting是一种与bagging很类似的技术,将原始数据集选择S次后得到S个新数据集,新数据集与原始数据集大小相等,每个数据集都是通过在原始数据集中随机选择一个样本来替换得到的,这就意味着可以多次选择同一个样本。在S个数据集建好之后,将某个学习算法分别作用于每个数据集就得到了S个分类器,当我们要对新数据分类时,就可以用这S个分类器进行分类,选择分类器投票结果最多的类别作为最后分类结果。boosting通过集中关注被已有分类器错分的数据来获得新的分类器,boosting给每个分类器的权重不相等,每个权重代表的是对应的分类器在上一轮迭代中的成功度,分类结果是基于所有分类器的加权求和得到的。

# 决策树集成
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier

adaboost_dt_clf = AdaBoostClassifier(
                                    DecisionTreeClassifier(
                                        max_depth=2,   # 决策树最大深度,默认可不输入即不限制子树深度
                                        min_samples_split=20, # 内部结点再划分所需最小样本数,默认值为2,若样本量不大,无需更改,反之增大
                                        min_samples_leaf=5    # 叶子节点最少样本数,默认值为1,若样本量不大,无需更改,反之增大
                                        ),
                                    algorithm="SAMME", # boosting 算法 {‘SAMME’, ‘SAMME.R’}, 默认为后者
                                    n_estimators=200,  # 最多200个弱分类器,默认值为50
                                    learning_rate=0.8  # 学习率,默认值为1
                                     )
clf.fit(train_Data,label_train_id)
pred = clf.predict(test_Data)
print(classification_report(label_test_id, pred,digits=4))
                  precision    recall  f1-score   support
    
               0     0.9940    0.9990    0.9965      1000
               1     0.9482    0.9890    0.9682      1000
               2     0.9798    0.7260    0.8340      1000
               3     0.8016    0.9210    0.8571      1000
               4     0.9413    0.9300    0.9356      1000
               5     0.9722    0.9810    0.9766      1000
               6     0.9525    0.9220    0.9370      1000
               7     0.9879    0.9790    0.9834      1000
               8     0.9441    0.9960    0.9693      1000
               9     0.9477    0.9960    0.9712      1000
    
        accuracy                         0.9439     10000
       macro avg     0.9469    0.9439    0.9429     10000
    weighted avg     0.9469    0.9439    0.9429     10000
    
    time: 386 ms

GradientBoostingClassifier

和Adaboost不同,Gradient Boosting 在迭代的时候选择梯度下降的方向来保证最后的结果最好。损失函数用来描述模型的“靠谱”程度,假设模型没有过拟合,损失函数越大,模型的错误率越高。如果我们的模型能够让损失函数持续的下降,则说明我们的模型在不停的改进,而最好的方式就是让损失函数在其梯度方向上下降。

from sklearn.ensemble import GradientBoostingClassifier

clf = GradientBoostingClassifier(max_depth=4,   # 决策树最大深度,默认可不输入,即不限制子树深度
                                max_features="auto",  # 寻找最优分割的特征数量,可为int,float,"auto","sqrt","log2",None:
                                n_estimators=100 # Boosting阶段的数量,默认值为100。
                                )
clf.fit(train_Data,label_train_id)
pred = clf.predict(test_Data)
print(classification_report(label_test_id, pred,digits=4))
                  precision    recall  f1-score   support
    
               0     0.9980    0.9970    0.9975      1000
               1     0.9810    0.9800    0.9805      1000
               2     0.8911    0.8760    0.8835      1000
               3     0.9910    0.9930    0.9920      1000
               4     0.9412    0.8970    0.9186      1000
               5     0.9437    0.9720    0.9576      1000
               6     0.9309    0.9430    0.9369      1000
               7     0.9832    0.9340    0.9579      1000
               8     0.9315    0.9660    0.9485      1000
               9     0.9613    0.9940    0.9774      1000
    
        accuracy                         0.9552     10000
       macro avg     0.9553    0.9552    0.9550     10000
    weighted avg     0.9553    0.9552    0.9550     10000
    
    time: 1h 16min 36s
  • 0
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是基于TF-IDF和KNN的中文文本分类代码示例: ```python import jieba import os import numpy as np from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.neighbors import KNeighborsClassifier # 读取文件,返回文本和标签列表 def load_data(path): texts = [] labels = [] for label in os.listdir(path): label_path = os.path.join(path, label) for file_name in os.listdir(label_path): file_path = os.path.join(label_path, file_name) with open(file_path, 'r', encoding='utf-8') as f: text = f.read() texts.append(text) labels.append(label) return texts, labels # 分词 def cut_words(texts): cut_texts = [] for text in texts: cut_text = ' '.join(jieba.cut(text)) cut_texts.append(cut_text) return cut_texts # 构建词向量 def build_tfidf_vectorizer(texts): tfidf_vectorizer = TfidfVectorizer() tfidf_vectorizer.fit_transform(texts) return tfidf_vectorizer # 计算相似度矩阵 def compute_similarity(tfidf_vectorizer, texts): tfidf_matrix = tfidf_vectorizer.transform(texts) similarity_matrix = tfidf_matrix * tfidf_matrix.T return similarity_matrix.toarray() # 基于KNN的文本分类 def text_classification(train_texts, train_labels, test_texts, n_neighbors=5): # 分词 train_cut_texts = cut_words(train_texts) test_cut_texts = cut_words(test_texts) # 构建词向量 tfidf_vectorizer = build_tfidf_vectorizer(train_cut_texts) # 计算相似度矩阵 similarity_matrix = compute_similarity(tfidf_vectorizer, train_cut_texts) # 构建KNN模型 knn_model = KNeighborsClassifier(n_neighbors=n_neighbors, metric='precomputed') # 训练KNN模型 knn_model.fit(similarity_matrix, train_labels) # 预测测试集标签 test_similarity_matrix = compute_similarity(tfidf_vectorizer, test_cut_texts) predict_labels = knn_model.predict(test_similarity_matrix) return predict_labels # 测试代码 if __name__ == '__main__': path = 'data' # 数据集路径 train_texts, train_labels = load_data(os.path.join(path, 'train')) test_texts, test_labels = load_data(os.path.join(path, 'test')) predict_labels = text_classification(train_texts, train_labels, test_texts) print(predict_labels) # 输出预测的标签 ``` 需要注意的是,该代码中使用的是基于文件夹的数据集格式,即每个文件夹代表一个类别,文件夹中包含若干个文本文件。如果您的数据集格式不同,需要根据实际情况进行修改。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值