# 读取训练集和测试集,并进行分词处理 # train_text[0]是新闻文本 train_text[1]是类别标签 train_text = pd . read_table ( "data/新闻标题文本分类/4分类_72000/train_4_72000.txt" , header = None , sep = " " ) test_text = pd . read_table ( "data/新闻标题文本分类/4分类_72000/test_4_4000.txt" , header = None , sep = " " ) print ( train_text . head ( 5 ) ) print ( "*" * 50 ) print ( test_text . head ( 5 ) )

本次演示使用的是4分类的数据集。运行上面代码,得到下面的输出:

0 中华女子学院:本科层次仅 1 专业招男生 3 1 卡佩罗:告诉你德国脚生猛的原因 不希望英德战踢点球 7 2 《赤壁OL》攻城战诸侯战硝烟又起 8 3 上海 2010 上半年四六级考试报名 4 8 日前完成 3 4 李永波称李宗伟难阻林丹取胜 透露谢杏芳有望出战 7 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 0 词汇阅读是关键 08 年考研暑期英语复习全指南 3 1 中国人民公安大学 2012 年硕士研究生目录及书目 3 2 日本地震:金吉列关注在日学子系列报道 3 3 名师辅导: 2012 考研英语虚拟语气三种用法 3 4 自考经验谈:自考生毕业论文选题技巧 3

可以看到数据集主要由两部分组成,前面部分是新闻标题文本,后面部分是类别标签。

使用pandas加载后train_text[0]和test_text[0]代表的就是新闻标题文本,train_text[1]和test_text[1]代表的是类别标签。

使用 jieba 对新闻标题文本分词。jieba一共提供了四种分词模式,默认使用的是精确模式,效果还不错。此外,jieba还提供了paddle模式的分词,我自己使用下来的效果是和精确模式差不多。(不过paddle模式的分词感觉确实要比精确模式好一点的。)

import jieba
# 使用jieba分词
def new_cut(text):
    return " ".join(list(jieba.cut(train_text)))
train_text["分词结果"] = train_text[0].map(new_cut)
test_text["分词结果"] = test_text[0].map(new_cut)
print(train_text["分词结果"].head(5))

分词结果:

0                中华 女子 学院 : 本科 层次 仅 1 专业 招 男生
1    卡佩罗 : 告诉 你 德国 脚 生猛 的 原因   不 希望 英德 战 踢 点球
2                   《 赤壁 OL 》 攻城战 诸侯 战 硝烟 又 起
3           上海 2010 上半年 四六级 考试 报名 48 日前 完成
4           李永波 称 李宗伟 难 阻林丹 取胜   透露 谢杏芳 有望 出战

去除停用词

本次使用的停用词表是哈工大停用词表,点我下载

# 加载停用词
def get_custom_stopwords(stop_words_file):
    with open(stop_words_file, encoding="gbk") as f:
        stopwords = f.read()
    stopwords_list = stopwords.split('\n')
    custom_stopwords_list = [i for i in stopwords_list]
    return custom_stopwords_list
stop_words_file = "stopwords.txt"
stopwords = get_custom_stopwords(stop_words_file)

TF-IDF算法提取文本特征

具体TfidfVectorizer的配置参数可以去参考[官方文档](sklearn.feature_extraction.text.TfidfVectorizer — scikit-learn 1.2.2 documentation),或者其他的博客。

from sklearn.feature_extraction.text import TfidfVectorizer
# 使用TF-IDF将文本处理成向量格式
tfidf_vectorizer  = TfidfVectorizer(max_df=0.8,
                                    min_df=3,
                                    token_pattern=u'(?u)\\b[^\\d\\W]\\w+\\b',
                                    stop_words=frozenset(stopwords),
                                    # max_features=1000) # 最大提取特征,默认就是没有限制
train_weight = tfidf_vectorizer.fit_transform(train_text["分词结果"])
test_weight = tfidf_vectorizer.transform(test_text["分词结果"])
print("train:\n", f"数据集大小:{train_weight.toarray().shape[0]} 提取特征数量:{train_weight.toarray().shape[1]}")
print("test:\n", f"数据集大小:{test_weight.toarray().shape[0]} 提取特征数量:{test_weight.toarray().shape[1]}")

输出结果:

train:
 数据集大小:72000 提取特征数量:20677
test:
 数据集大小:4000 提取特征数量:20677

KNN分类器的设计

KNN分类器的K值(n_neighbors参数)取3,距离计算方式(metric参数)选择余弦距离,其他的参数默认就行。

from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, recall_score, f1_score, precision_score
import pickle
save_model = False
k = 3
knn = KNeighborsClassifier(n_neighbors=k, metric="cosine")
knn.fit(train_weight, train_text[1])
test_pred = knn.predict(test_weight)
# 计算准确率、召回率、精确率和F1值
accuracy = accuracy_score(test_pred, test_text[1])
recall = recall_score(test_pred, test_text[1], average='macro')
precision = precision_score(test_pred, test_text[1], average='macro')
f1 = f1_score(test_pred, test_text[1], average='macro')
# 输出训练日志
with open("output_logs/knn_cls.txt", "a+") as log_txt:
    log_txt.write(f"k = {k}\n")
    log_txt.write(f"accuracy = {accuracy}\n")
    log_txt.write(f"recall = {recall}\n")
    log_txt.write(f"precision = {precision}\n")
    log_txt.write(f"f1 = {f1}\n")
    log_txt.close()
    # 保存训练模型
if save_model:
    with open(f"output_models/knn_{k}.pkl", "wb") as f:
        pickle.dump(knn, f)
    print("Save model sucess!")

结果日志输出:

k = 3
accuracy = 0.8945
recall = 0.9015750424563225
precision = 0.8945
f1 = 0.8939859931730288

现在的模型分类效果可以在调调参数,比如把k值调大一点等。

完整代码下载

CSDN下载(只需1积分)

蓝奏云下载

# encoding=utf-8 from sklearn.feature_extraction.text import TfidfVectorizer, TfidfTransformer corpus = [ 'This This is the first document.', 'This This is the second second document.', K-近邻算法,简称KNN(k-Nearest Neighbor),是一个相当简单的分类/预测算法。其主要思想就是,选取与待分类/预测数据的最相似的K个训练数据,通过对这K个数据的结果或者分类标号取平均、取众数等方法得到待分类/预测数据的结果或者分类标号。 关于KNN,笔者在浅入浅出:K近邻算
2.1 代码 from sklearn.datasets import fetch_20newsgroups from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.naive_bayes import MultinomialNB def bayesian_demo(): 1. 首先对文本进行分词,去除停用词等预处理操作; 2. 采用TF-IDF算法计算文本中每个词的权重,TF-IDF的公式为:TF-IDF(w,d)=TF(w,d)×IDF(w),其中TF(w,d)表示词w在文档d中的出现次数,IDF(w)表示词w的逆文档频率,其公式为:IDF(w)=log(N/n),其中N表示总文档数,n表示包含词w的文档数; 3. 将每个文本表示成一个向量,向量的每个维度对应一个词,其值为该词的TF-IDF权重; 4. 对所有文本向量进行归一化处理,使其模长为1; 5. 选取一个合适的K值,对于未分类文本,计算其与所有已分类文本向量的距离,并选取距离最近的K个已分类文本向量; 6. 根据K个最近邻文本分类标签,采取多数表决的方式确定未分类文本分类标签。 需要注意的是,TF-IDF+KNN算法对于文本分类的效果受到许多因素的影响,如文本处理、特征选择、K值的选择等。在实际应用中,需要根据具体情况进行优化和调参。