简介这是一份基于Python的sklearn库实现的文本分类代码资源使用决策树和随机森林两种算法完成模型训练与评估适合毕业设计、课程设计或想快速搭建文本分类系统的开发者参考。资源围绕文本分类完整流程展开包含原始数据与训练数据Excel表格、标签向量npy文件、训练好的模型文件.m以及两套Jupyter Notebook代码分别对应算法实现和模型预测环节还附有需求示意图便于理解项目结构与运行逻辑。整个压缩包共9个文件大小仅1.78MB轻量且目录清晰下载后可直接打开Notebook逐步运行也可对比决策树与随机森林在相同数据上的分类效果。已有8209人学习下载对于希望跳过枯燥原理、直接获得可运行可视化样板的同学这份资源能帮助节省从数据预处理到模型部署的大量时间尤其适合作为课程报告或毕设演示的起点。1. 文本分类的整体思路与方案选型1.1 为什么选决策树和随机森林做文本分类拿到一个文本分类任务很多人第一反应是上深度学习模型或者直接套一个朴素贝叶斯。但从实际工程和教学角度看决策树和随机森林在文本分类场景里有自己的独特优势尤其是当你的数据量不大、需要快速验证思路、或者要给别人讲清楚模型到底学到了什么的时候。决策树最大的特点是可解释性极强。它会把文本属于哪个类别这个判断过程拆成一条条规则比如包含退款且包含物流的词频超过某阈值则判定为售后投诉。这种规则天然接近人类理解问题的方式调试起来非常直观。随机森林则是集成学习的经典代表把多棵决策树的结果做投票显著降低单棵树的过拟合风险在文本分类这种高维稀疏特征场景下表现往往比单棵决策树稳定得多。选择这两个模型还有一个现实原因sklearn里它们都有开箱即用的实现代码量小参数对新手友好不需要像支持向量机那样操心核函数选择也不像朴素贝叶斯那样对特征分布有较强的假设。文本分类本质上是一个词频权重驱动的任务决策树和随机森林对这种特征有天然的容忍度即使不去做复杂的数据清洗也能得到一个可用的基线模型。1.2 从原始文本到特征矩阵中文文本的预处理链路做文本分类第一步不是选模型而是把文本变成模型能吃的东西。计算机不认识汉字它只认识数字。所以我们必须把一段话拆成模型可理解的数值特征这个过程通常分三步中文分词、去除停用词、向量化。中文分词是最特殊的一步。英文单词之间有空格中文没有所以必须借助分词工具。我用的是jieba这是目前用的最多的中文分词库支持精确模式、全模式和搜索引擎模式默认的精确模式就能满足大多数分类任务。分词之后文本就变成了一个词列表比如这家店的服务态度非常好切分成[这家, 店, 的, 服务态度, 非常, 好]。接下来要去停用词。所谓停用词就是的、了、是、在这类出现频率极高但对分类几乎没有贡献的虚词。如果不把它们滤掉它们会占据大量特征维度反而稀释真正有区分度的关键词权重。停用词表可以自己维护也可以直接下载网上现成的中文停用词库一般覆盖几百个常见词就够了。最后一步是向量化。文本分类里最常用的就是TfidfVectorizer它能把分词后的文本转换成TF-IDF特征矩阵。TF-IDF的核心思想是一个词在当前文档里出现频率高TF高但在整个语料库中出现频率低IDF高说明这个词对这篇文章有很好的标识度值得给高权重。换成大白话就是退款在一条售后投诉里反复出现但在正常交易评价里很少出现那它就是一个高信号词。这个特征矩阵就是后面决策树和随机森林的输入。import jieba from sklearn.feature_extraction.text import TfidfVectorizer def tokenize(text): return .join(jieba.cut(text))2. 核心实现代码逐段拆解2.1 数据集准备与文本清洗先做一个能跑通的最小闭环。我用的是一份公开的新闻文本分类数据集包含体育、财经、科技、娱乐、汽车五个类别每个类别大概几百条样本。真实场景里你可能只有自己的业务数据比如客服工单、用户评论、邮件内容结构和字段不一样但处理思路完全一致。文本清洗这一步直接决定模型的上限。我见过太多人把原始文本直接丢进模型试了半天效果差结果发现是数据里充满了HTML标签、URL、无意义的符号。我的清洗流程是这样的先统一转成字符串去掉HTML标签过滤URL和邮箱移除所有非中文字符和数字最后压缩多余空格。注意每一步都要谨慎不要过度清洗比如iPhone 15这种词里的数字和英文如果被去掉就丢失了关键信息。我的经验是清洗规则要按你的业务数据来定制做一个基本的清洗函数即可。import re def clean_text(text): text re.sub(r.*?, , str(text)) # 去HTML标签 text re.sub(rhttp\S|www\.\S, , text) # 去URL text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9], , text) # 只保留中文、英文、数字 text re.sub(r\s, , text).strip() # 压缩空格 return text清洗完之后把原始文本和标签整理成一个DataFrame列名分别叫text和label这是后面所有流程的数据基础。标签这一步我建议直接用数值编码比如体育0财经1科技2娱乐3汽车4sklearn的LabelEncoder可以帮你自动完成这个映射。2.2 特征工程TF-IDF向量化特征工程是文本分类的灵魂。TfidfVectorizer有几个关键参数你调好了模型效果立刻上一个台阶调不好则很容易被无意义的高频词带偏。第一个参数是max_features控制特征维度上限。如果原始语料分词后有几万个词不限制维度矩阵会非常大训练也慢。我通常限制在5000到10000之间这个范围对中小规模数据集足够用还能有效抑制低频噪声词。第二个参数是ngram_range它控制特征粒度。ngram_range(1, 1)只使用单个词ngram_range(1, 2)会同时使用单词和相邻两词的组合这样能捕捉非常 满意这种短语级别的语义对分类效果有提升。代价是特征维度增加所以设置max_features时要把这个因素考虑进去。第三个参数是min_df和max_df分别过滤掉在过少和过多文档中出现的词。min_df2表示一个词至少要在2个文档里出现才保留能去掉只出现在某一条样本里的极端稀疏词max_df0.8表示在超过80%文档里都出现的词会被移除因为它们对分类没有区分力。vectorizer TfidfVectorizer( tokenizertokenize, max_features8000, ngram_range(1, 2), min_df2, max_df0.8, sublinear_tfTrue ) X vectorizer.fit_transform(df[text_clean]) y df[label]这段代码里有个细节容易被忽略tokenizer参数传入的是jieba分词函数。sklearn默认的tokenizer是按空格切分的所以要在分词函数里用空格把词连接起来这样sklearn就能正确处理。sublinear_tfTrue表示对词频做对数变换能弱化高频词的绝对数量优势是文本分类里一个常开的小开关。2.3 决策树分类器构建决策树的代码非常简洁但参数直接影响模型复杂度。最核心的参数是max_depth和min_samples_split。max_depth控制树的深度太浅则欠拟合太深则过拟合。min_samples_split控制一个节点继续分裂所需的最少样本数调大它可以让树停止细分起到正则化作用。我第一版跑的时候直接把max_depth设置为None也就是不限深度树完全生长。结果训练集准确率达到了100%测试集却掉到75%左右这是典型的过拟合。后来我把max_depth调成10加上min_samples_split5测试集准确率反而提升到82%。这个经验在文本分类里尤其重要因为TF-IDF特征维度高树特别容易记住训练集中的噪声。from sklearn.tree import DecisionTreeClassifier dt_model DecisionTreeClassifier( max_depth10, min_samples_split5, min_samples_leaf2, criteriongini, random_state42 ) dt_model.fit(X_train, y_train)criterion参数默认是gini也可以换成entropy。两者在大多数场景下效果差异极小选gini就好计算开销略小。random_state42是我固定随机种子的习惯保证每次运行结果一致方便对比调优。2.4 随机森林分类器构建随机森林是决策树的集成。核心思想是训练多棵互相独立的树每棵树只看一部分样本和一部分特征最后用投票决定结果。这种随机性带来了两个收益一是大幅降低方差防止过拟合二是让模型对个别异常样本不敏感。我建议从n_estimators100起步也就是100棵树。这个值不是越大越好超过200以后效果提升趋缓训练时间却线性增加。max_features这个参数在随机森林里很关键它控制每棵树分裂时最多考虑多少个特征文本分类场景下我一般设为sqrt也就是特征数的平方根这样能强制每棵树关注不同的特征子集增加多样性。from sklearn.ensemble import RandomForestClassifier rf_model RandomForestClassifier( n_estimators100, max_depth12, max_featuressqrt, min_samples_split5, min_samples_leaf2, n_jobs-1, random_state42 ) rf_model.fit(X_train, y_train)n_jobs-1表示使用所有CPU核心随机森林每棵树是独立训练的天然支持并行这一步能省不少时间。3. 训练、评估与调优实战3.1 划分训练集测试集模型训练前必须把数据分成训练集和测试集否则无法评估模型的真实泛化能力。我用的是train_test_split按照7:3的比例划分。这里有两个要点stratify参数要按标签比例分层采样保证训练集和测试集里每个类别的比例一致random_state固定种子保证可复现。from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, stratifyy, random_state42 )分层采样这一步容易被忽略但实际影响很大。如果原始数据里科技类占比60%不设置stratify随机划分可能导致测试集里科技类占比变成70%评估结果就会偏离真实情况。3.2 模型评估指标怎么看文本分类常见的评估指标有准确率、精确率、召回率和F1值。准确率是预测对的比例在类别均衡时最直观但遇到类别不均衡比如95%的样本都是科技类模型全预测成科技类准确率也有95%这时候就必须看精确率和召回率。精确率回答的问题是预测为A类的样本里有多少确实是A类召回率回答的是真正的A类样本里有多少被找出来了。F1值是两者的调和平均兼顾精确和召回。我用classification_report一次性输出所有指标。from sklearn.metrics import classification_report y_pred rf_model.predict(X_test) print(classification_report(y_test, y_pred, target_names[体育, 财经, 科技, 娱乐, 汽车]))顺便说一个实用技巧如果业务更看重召回比如客服工单分类你希望舆情投诉一条都不要漏那就调低判定阈值或者用predict_proba加上自定义阈值如果更看重精确率希望预测为A类的都足够可靠那模型调整方向正好相反。3.3 参数调优的实操经验调参最有性价比的方法是网格搜索sklearn的GridSearchCV可以自动遍历参数组合并用交叉验证打分。但网格搜索是穷举式的如果你给每个参数列了10个候选值组合数量会爆炸。我的做法是分两阶段调参。第一阶段先粗调关键参数。决策树和随机森林优先调max_depth和n_estimators固定其他参数不变分别跑一组候选值画出准确率变化曲线找出趋势区间。第二阶段再在这个区间里做细粒度搜索同时加入min_samples_split、min_samples_leaf等参数。from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [100, 150, 200], max_depth: [10, 12, 15], min_samples_split: [3, 5, 8] } grid_search GridSearchCV( RandomForestClassifier(random_state42), param_grid, cv5, scoringf1_macro, n_jobs-1 ) grid_search.fit(X_train, y_train) print(grid_search.best_params_)这里要注意scoring参数。我用的是f1_macro它会对每个类别算F1后取平均对类别不均衡比准确率更可靠。cv5表示5折交叉验证即把训练集再分成5份轮流用4份训练、1份验证最后取平均值作为该组参数的得分。这个过程比较耗时但结果可信度高。还有一个高频坑网格搜索结果很好但实际测试集表现一般这多半是交叉验证和测试集的数据分布差异造成的。我的经验是网格搜索得到的参数只是一个起点最后一定要结合实际业务数据和少量人工标注做二次验证。4. 常见问题与排查技巧实录4.1 中文编码问题中文文本处理最常见的问题就是编码。读取CSV文件时如果不指定编码很容易出现乱码或者报错。建议统一使用UTF-8编码读文件时显式加一行encodingutf-8。老旧的CSV文件可能是GBK编码那就要用encodinggbk。如果读出来是乱码不要盲目用整表清洗先单独打印前几行看看到底是哪里出了问题。另一个编码问题是路径。在Windows环境下Python处理包含中文的路径偶尔会有问题我通常会在代码开头加一行让系统识别中文路径。分词和建模本身对编码其实不敏感只要读进来的时候是正确的字符串后面基本不会再出乱码。4.2 内存与性能问题文本分类的数据量一大TF-IDF矩阵可能占用几个GB内存。特征维度几万、样本量几十万的时候直接训练随机森林能跑到内存爆炸。我的解决思路是控制特征数量优先max_features先设5000以下看准确率变化再决定是否提升。另外要注意TfidfVectorizer输出的是稀疏矩阵中间过程不要转成稠密数组否则几百MB的矩阵可能直接膨胀成十几GB。还有一点如果你多次运行代码务必确认旧变量没有被反复引用Python的垃圾回收有时不会立刻释放大对象我习惯在循环训练多个模型时手动删掉大矩阵。4.3 准确率上不去怎么办准确率低的排查路线是有优先级的。第一步看数据先随机抽查几十条训练样本看看标签是不是标错了、清洗后文本是不是丢了关键内容。第二步看特征把vectorizer训练后的特征名称打出来用argsort找到权重最高的几十个词看看它们是否符合业务直觉。第三步才是调模型参数。我在一次客服工单分类任务里准确率死活卡在70%左右查了特征之后发现分词结果里退货退款被人为拆分成了退货和退款相当于同一个语义被拆成了两个特征每个特征的数据稀疏度都变大了。后来在分词前加入自定义词典把退货退款、七天无理由这类业务词当成整体准确率立刻提升到了85%。这个经验说明文本分类的特征工程优先级永远高于模型调参。4.4 决策树过拟合与随机森林的差异单棵决策树在文本分类上几乎必然过拟合这是由算法特性决定的。它可以把训练集分割到每个叶子节点都只包含一个样本测试集自然就崩了。随机森林通过样本抽样和特征抽样缓解了这个问题但仍然需要限制树深。我的直观经验是如果随机森林比单棵决策树准确率高不了多少大概率是你没有给随机森林足够的随机性。检查一下max_features是不是设成了None那样等于每棵树都考虑全部特征多棵树之间的相关性很高集成效果就会大打折扣。另外样本量太小时随机森林优势不明显几千条样本效果可能和单棵决策树差不多这时不如先做特征工程或者换更简单的模型。最后分享一个小技巧调参时不要只看测试集指标。把训练集和测试集上的指标同时打出来训练集98%测试集80%说明过拟合两者都在85%左右说明模型容量适中两个都低说明特征没有表现力。这个对比能帮你快速定位瓶颈在哪个环节比盲目堆参数有效得多。本文还有配套的精品资源点击获取