使用 TFIDF+分类器 范式进行企业级文本分类(二)

news2025/4/15 4:39:37

1.开场白

上一期讲了 TF-IDF 的底层原理,简单讲了一下它可以将文本转为向量形式,并搭配相应分类器做文本分类,且即便如今的企业实践中也十分常见。详情请见我的上一篇文章 从One-Hot到TF-IDF(点我跳转)

光说不练假把式,在这篇文章中,你更加深刻了解TF-IDF是如何做文本分类的。具体有:

  1. 使用sklearn库进行TFIDF向量化
  2. 使用不同的分类器(SVM, 随机森林, XGBoost)做文本分类
  3. 搭配不同分类器的效果如何?

在开始之前推荐一个Github的开源项目。里面有很多开源数据集,很适合新手去探索 --> NLP民工乐园(本篇文章的数据集也是取自这里)

2.原理

1.TFIDF

TFIDF的原理虽然之前已经介绍了,但是这里还是简单讲一下好了。

TF-IDF(Term Frequency-Inverse Document Frequency)是一种用于信息检索和文本挖掘的加权技术,用于评估一个词在文档中的重要程度。它由两部分组成:

1. 词频(Term Frequency, TF)
衡量一个词在当前文档中出现的频率:

T F ( t , d ) = f t , d ∑ t ′ ∈ d f t ′ , d TF(t, d) = \frac{f_{t,d}}{\sum_{t' \in d} f_{t',d}} TF(t,d)=tdft,dft,d

其中:

  • f t , d f_{t,d} ft,d:词 t t t 在文档 d d d 中的出现次数
  • ∑ t ′ ∈ d f t ′ , d \sum_{t' \in d} f_{t',d} tdft,d:文档 d d d 中所有词的出现次数总和

2. 逆文档频率(Inverse Document Frequency, IDF)
衡量一个词的普遍重要性(在多少文档中出现):

I D F ( t , D ) = log ⁡ ( N ∣ { d ∈ D : t ∈ d } ∣ ) IDF(t, D) = \log \left( \frac{N}{|\{d \in D : t \in d\}|} \right) IDF(t,D)=log({dD:td}N)

其中:

  • N N N:语料库中文档的总数
  • ∣ { d ∈ D : t ∈ d } ∣ |\{d \in D : t \in d\}| {dD:td}:包含词 t t t 的文档数量

3. TF-IDF 最终公式
将TF和IDF相乘得到最终权重:

T F - I D F ( t , d , D ) = T F ( t , d ) × I D F ( t , D ) TF\text{-}IDF(t, d, D) = TF(t, d) \times IDF(t, D) TF-IDF(t,d,D)=TF(t,d)×IDF(t,D)

4. 变体说明
实际应用中可能存在不同变体,例如:

  • TF变体:对数缩放 T F = log ⁡ ( 1 + f t , d ) TF = \log(1 + f_{t,d}) TF=log(1+ft,d)
  • IDF变体:避免除零 I D F = log ⁡ ( N 1 + n t ) + 1 IDF = \log(\frac{N}{1 + n_t}) + 1 IDF=log(1+ntN)+1
  • 归一化:对文档向量进行L2归一化

2.SVM

全名支持向量机,简称SVM,在2000年前后的CPU时代,它也曾是顶流。

具体原理见我的另一篇文章,这是一篇背书于《统计学习方法》的、用严谨的数学进行SVM推导的文章 --> 支持向量机

之所以他曾是顶流,主要因为它具备如下优势

  1. SVM不存在现代深度学习反向传播的过拟合
  2. 小样本数据集上表现良好
  3. CPU环境下就能训练、推理,边缘设备(普通电脑)上也能跑起来
  4. 数学背景好,理论严谨

但是现在又被“淘汰”了,原因有:

  1. 大数据时代,SVM拓展性不足,数据量庞大的情况下训练很慢,相反深度学习可以利用GPU的并行,加速推理
  2. 泛化能力有限,SVM需要手动特征,而深度学习可以端到端自动学习特征
  3. 非线性场景能力有限,即便有核技巧处理非线性场景,但是函数选择和调参比较麻烦。
  4. 深度学习可以叠的很深,可以学习到数据中更加抽象、深层的信息,但SVM与之相比是浅层模型,学习到的信息有限。

关于支持向量机的作者 Vapnik,他还和现任人工智能的三驾马车 LeCun 有一段有趣的轶事,他们两个同为贝尔实验室的同事,因为学术之争处处不合。后来他们两位之间的争论某种意义上来说也代表了传统机器学习和深度学习之间的对碰。具体请见我的另一篇文章 自然语言处理发展史(点我跳转)

3.XGBoost

XGBoost 是梯度提升树GBDT的改良版,他们都是树模型的一种。

什么?你问我什么是树模型?好吧,这里我来解答一下,其实树模型是决策树类模型的简称,业内常常管决策树类的模型叫输模型。

至于决策树模型,可以见我另一篇文章 决策树(点我跳转)

跳转文章讲了决策树模型的基本原理,从纯数学的角度出发,带你理解决策树模型。

有了决策树的基础,理解GBDT和XGBoost就不是问题了。

那么让我们先了解GBDT,再看一看他是如何从GBDT过渡到XGBoost的吧

1.GBDT(梯度提升树)

GBDT(Gradient Boosting Decision Tree)的核心思想是通过加法模型(Additive Model)将多个弱分类器(通常是决策树)的预测结果逐步累加,从而逼近真实值
具体来说, 每一轮迭代都会训练一个新的弱分类器,使其拟合当前模型的负梯度(即残差的近似),而非直接拟合残差本身。
这里的“残差”可以理解为当前模型的预测值与真实值之间的误差方向,而GBDT通过梯度下降的策略逐步减少这一误差。

如图,Y = Y1 + Y2 + Y3
在这里插入图片描述

举一个非常简单的例子,比如我今年30岁了,但计算机或者模型GBDT并不知道我今年多少岁,那GBDT咋办呢?

它会在第一个弱分类器(或第一棵树中)随便用一个年龄比如20岁来拟合,然后发现误差有10岁;
接下来在第二棵树中,用6岁去拟合剩下的损失,发现差距还有4岁;
接着在第三棵树中用3岁拟合剩下的差距,发现差距只有1岁了;
最后在第四课树中用1岁拟合剩下的残差,完美。
最终,四棵树的结论加起来,就是真实年龄30岁。

实际工程中,gbdt是计算负梯度,用负梯度近似残差.

那么为什么用负梯度近似残差呢?

回归任务下,GBDT 在每一轮的迭代时对每个样本都会有一个预测值,此时的损失函数为均方差损失函数,
在这里插入图片描述

那此时的负梯度是这样计算的
在这里插入图片描述

所以,当损失函数选用均方损失函数时,每一次拟合的值就是(真实值 - 当前模型预测的值),即残差。
此时的变量是 y i y^i yi,即“当前预测模型的值”,也就是对它求负梯度。

2.XGBoost(极度梯度提升)

核心思想如图
在这里插入图片描述
在这里插入图片描述

(作者陈天奇大佬的原图)
可以看到,男孩的计算得分是两个树的相加 2+0.9=2.9

这不和GBDT一样么!

确实,如果不考虑工程实现、解决问题上的一些差异,xgboost与gbdt比较大的不同就是目标函数的定义

xgboost的目标函数如下图所示:
在这里插入图片描述
在这里插入图片描述

XGBoost的核心算法思想不难,基本就是:

  1. 不断地添加树,不断地进行特征分裂来生长一棵树,每次添加一个树,其实是学习一个新函数f(x),去拟合上次预测的残差。
  2. 当我们训练完成得到k棵树,我们要预测一个样本的分数,其实就是根据这个样本的特征,在每棵树中会落到对应的一个叶子节点,每个叶子节点就对应一个分数
  3. 最后只需要将每棵树对应的分数加起来就是该样本的预测值。

为什么XGBoost要用泰勒展开,优势在哪里?

XGBoost使用了一阶和二阶偏导, 二阶导数有利于梯度下降的更快更准. 使用泰勒展开取得函数做自变量的二阶导数形式, 可以在不选定损失函数具体形式的情况下, 仅仅依靠输入数据的值就可以进行叶子分裂优化计算, 本质上也就把损失函数的选取和模型算法优化/参数选择分开了. 这种去耦合增加了XGBoost的适用性, 使得它按需选取损失函数, 可以用于分类, 也可以用于回归。

3.数据集

该篇文章数据集地址 酒店评论 (也出自开头推荐的那个Github开源项目里)

该数据集是一个酒店评价数据集,有两个字段:

  • review为用户评论
  • label为情感的正负类标签,其中1为正面情绪,0为负面情绪

数据集预览
在这里插入图片描述

4.技术实践

1.sklearn中的使用TFIDF

前提:安装sklearn

pip install scikit-learn

在 scikit-learn (sklearn) 中,TfidfVectorizer 是用于 TF-IDF文本特征提取的主要类。它属于 sklearn.feature_extraction.text 模块,主要用于将文本数据转换为数值特征矩阵

下面讲一下它的关键参数吧~

  1. stop_words{‘english’}, list, default=None
  2. ngram_range: tuple (min_n, max_n)` default=(1, 1)
    a. 要提取的不同n-gram的n值范围的下限和上限。将使用min_n<=n<=max_n的所有n值。
  3. max_dffloat or int, default=1.0:
    i. 在构建词汇表时,忽略文档频率严格高于给定阈值的术语(特定于语料库的停用词)。如果在[0.0,1.0]范围内,则该参数表示文档的比例,即整数绝对计数。如果词汇表不是None,则忽略此参数。
  4. min_df float or int, default=1
    i. 在构建词汇表时,忽略文档频率严格低于给定阈值的术语。这个值在文献中也被称为截止值。如果浮点数在[0.0,1.0]的范围内,则该参数表示文档的比例,即整数绝对计数。如果词汇表不是None,则忽略此参数。
  5. max_features int, default=None
    i. 如果不是None,则构建一个词汇表,只考虑语料库中按词频排序的顶级max_features。否则,将使用所有功能。
    如果词汇表不是None,则忽略此参数。
  6. smooth_idf bool, default=True
    i. 通过在文档频率上加1来平滑idf权重,就像看到一个额外的文档包含集合中的每个术语一样。
  7. sublinear_tf bool, default=False
    i. 应用亚线性tf缩放,即将 tf 替换为1 + log(tf)。
tfidf = TfidfVectorizer(
    max_features=5000, 
    stop_words=stopwords, 
    ngram_range=(1,2),
    min_df=3,           # 过滤低频词
    max_df=0.9,          # 过滤高频词
    # sublinear_tf=True, # 对数平滑,降低词频影响
)
X = tfidf.fit_transform(train_df['processed_text'])
  1. 总结
    a. 注意调整ngram_rangemax_features 。直接对效率和特征表示能力相关联。

2.XGBoost

前提:安装XGBoost

pip install xgboost

下面讲讲xgboost的使用吧

1. 通用参数
宏观函数控制 在 xgboost.config_context() 设置
a. verbosity: Valid values of 0 (silent), 1 (warning), 2 (info), and 3 (debug).

2. 一般参数:
a. booster [default= gbtree ]。使用哪种助推器。可以是gbtree、gblinear或dart;gbtree和dart使用基于树的模型,而gblinear使用线性函数。
b. device [default= cpu]
c. nthread [如果未设置,则默认为可用的最大线程数]

3. Booster 参数
a. eta [default=0.3, alias(别名): learning_rate]
b. gamma [default=0, alias: min_split_loss][0,∞]

  • 在树的叶子节点上进行进一步分区所需的最小损失减少。gamma越大,算法就越保守。请注意,没有进行分割的树可能仍然包含一个非零分数的终端节点。

c. max_depth [default=6][0,∞]

  • 树的最大深度。增加此值将使模型更加复杂,更有可能过度拟合。0表示深度没有限制。请注意,XGBoost在训练深层树时会大量消耗内存。精确树方法需要非零值。

d. min_child_weight [default=1][0,∞]

  • 孩子结点所需实例权重的最小总和。如果树分区步骤导致叶节点的实例权重之和小于min_child_weight,则构建过程将放弃进一步的分区。在线性回归任务中,这只对应于每个节点中需要的最小实例数。min_child_weight越大,算法就越保守。

e. subsample [default=1]

  • 训练实例的子样本比率。将其设置为0.5意味着XGBoost将在种植树木之前随机采样一半的训练数据。这将防止过拟合。子采样将在每次增强迭代中发生一次。

f. lambda [default=1, alias: reg_lambda]

  • 权重的L2正则化项。增加此值将使模型更加保守。range: [0, ∞]

g. alpha [default=0, alias: reg_alpha]

  • 权重上的L1正则化项。增加此值将使模型更加保守。range: [0, ∞]

h. tree_method string [default= auto] auto, exact, approx, hist

  • auto: 与hist-tree方法相同。
  • exact: 精确贪婪算法。枚举所有拆分的候选人。
  • approx:使用分位数草图和梯度直方图的近似贪婪算法。
  • hist: 更快的直方图优化近似贪婪算法。

i. scale_pos_weight [default=1]

  • 控制正负权重的平衡,对不平衡的类很有用。需要考虑的典型值:sum(负实例)/sum(正实例)。

4. 特定学习任务参数
指定学习任务和相应的学习目标。目标选项如下

  • objective [default=reg:squarederror]
    a. reg:squarederror: 平方误差:损失平方的回归
    b. reg:squaredlogerror: 平方对数误差:具有平方对数损失的回归。所有输入标签都必须大于-1
    c. reg:logistic: 逻辑回归,输出概率
    d. reg:pseudohubererror:伪Huber误差:使用伪Huber损失的回归,这是绝对损失的两次可微替代方案。
    e. reg:absoluteerror: 绝对误差:L1误差回归。当使用树模型时,在树构建后刷新叶值。如果在分布式训练中使用,叶值将作为所有工人的平均值计算,这并不能保证是最优的。
    f. reg:quantileerror:分位数损失,也称为弹球损失。
    g. binary:logistic: 二元逻辑回归:用于二元分类的逻辑回归,输出概率
    h. binary:logitraw: 二元分类的逻辑回归,逻辑转换前的输出分数
    i. binary:hinge:二元分类的铰链损失。这使得预测为0或1,而不是产生概率。
    j. multi:softmax: 设置XGBoost使用softmax目标进行多类分类,还需要设置num_class(类的数量)
    k. multi:softprob: 与softmax相同,但输出一个 ndatanclass 向量,该向量可以进一步整形为ndatanclass矩阵。结果包含每个数据点属于每个类的预测概率。
  • eval_metric [default according to objective] :验证数据的评估指标,将根据目标分配默认指标(回归的rmse,分类的logloss,排名的平均精度:映射等)
    a. rmse: 均方根误差
    b. mae: 平均绝对误差
    c. logloss: 负对数似然
    d. auc: ROC曲线下与坐标轴围成的面积。可用于分类和学习任务排名。
    • 用于二分类时,目标函数应为binary:logistic或类似的处理概率的函数。
    • 用于多分类时,目标函数应为multi:softprob而非multi:softmax,因为后者不输出概率。AUC通过1对其余类计算,参考类由类别比例加权。
    • 当输入数据集只包含负样本或正样本时,输出为NaN。具体行为取决于实现,例如scikit-learn会返回0.5。

5. XGBoost调优

1.控制过拟合

当你观察到训练精度很高,但测试精度很低时,很可能会遇到过拟合问题

在XGBoost中,通常有两种方法可以控制过拟合:

第一种方法是直接控制模型的复杂性
a. 包括 max_depth, min_child_weight and gamma.

第二种方法是增加随机性,使训练对噪声具有鲁棒性。
a. 包括 subsample and colsample_bytree
b. 您还可以减小步长 eta。执行此操作时,请记住增加num_round

2.处理不平衡数据集

数据集非常不平衡。这会影响XGBoost模型的训练,有两种方法可以改进它。

  • 如果你只关心预测的整体性能指标(AUC)
    • 通过 scale_pos_weight平衡正负权重
  • 如果你关心预测正确的概率
    • 将参数 max_delta_step设置为有限数(比如1)以帮助收敛

5.使用TFIDF做特征,用SVM或XGBoost做分类器,做酒店评价的情感分析

在这里插入图片描述

1.分词

ps:由于中文和英文不一样,英文会天然的使用空格进行分词,但是中文的一句话是连贯的。如:

英文:I want to go to Beijing.
中文:我想去北京。

如果把英语交给模型,模型收到的是 ["I", "want", "to", "go", "to", "Beijing", "."],总共6个词。
但是如果把中文交给模型,模型收到的是 我想去北京。,总共1个词。

故在NLP中,中文领域都是要分词的。

但是中文如果直接以“字”分词,效果可能很可能不好,因为中文是以词为单位的。如 北京 (一个词)和 (两个字)是两个完全不同的概念。

如果是传统的机器学习文本分类,如SVM和XGBoost通常是采用 Jieba 库来进行分词的。

关于这个库我以后会专门出一篇文章来讲。

总之,在这篇文章中先不考虑jieba的原理,你只需要知道他可以进行如下方式的分词即可。

text = "我要去北京。"
print(jieba.lcut(text))# 

# ['我要', '去', '北京', '。']

1.这里使用的是 lcut而不是cut,是因为方便打印展示,lcut会直接返回list(迭代器),而cut会返回一个生成器<generator object Tokenizer.cut at 0x164a07a00>.
2.其实业务中大多还是采用生成器cut的形式,因为生成器是惰性迭代计算的,内存效率高。


简单解释一下生成器和迭代器的区别。

生成器 vs 迭代器(列表)(以"我要去北京。"为例)

列表:像把所有分词结果装进盒子
lcut(“我要去北京。”) → 直接给你 [‘我要’, ‘去’, ‘北京’, ‘。’]
生成器:像现用现做的流水线
cut(“我要去北京。”) → 需要时才一个个生成:
‘我要’ → ‘去’ → ‘北京’ → ‘。’

区别:
列表:一次性全做好(占内存,但能反复用)
生成器:用的时候才做(省内存,但只能用一次)

(如果同学不理解生成器和列表的区别,可以评论或留言,我会迅速转门出一篇文章来阐述他俩的区别)


2.使用SVM做分类器

import time
import pandas as pd
import jieba
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
from sklearn.metrics import classification_report

# 记录总开始时间
total_start = time.time()

# 1. 数据加载
print("1. 正在加载数据...")
start = time.time()
data = pd.read_csv('/Users/zhangqingjie/Downloads/ChnSentiCorp_htl_all.csv')  # 替换为你的文件路径
print(f"数据加载完成,用时: {time.time() - start:.2f}秒")
print(f"数据样本数: {len(data)}")

# 2. 中文分词
print("\n2. 正在进行中文分词...")
start = time.time()

def chinese_tokenizer(text):
    return ' '.join(jieba.cut(text))

data['review'] = data['review'].fillna('')
data['tokenized_review'] = data['review'].apply(chinese_tokenizer)
print(f"分词完成,用时: {time.time() - start:.2f}秒")

# 3. 数据划分
print("\n3. 正在划分训练集和测试集...")
start = time.time()
X_train, X_test, y_train, y_test = train_test_split(
    data['tokenized_review'], 
    data['label'], 
    test_size=0.2, 
    random_state=42,
    shuffle=True
)
print(f"数据划分完成,用时: {time.time() - start:.2f}秒")
print(f"训练集大小: {len(X_train)}, 测试集大小: {len(X_test)}")

# 4. TF-IDF特征提取
print("\n4. 正在进行TF-IDF特征提取...")
start = time.time()
tfidf = TfidfVectorizer(max_features=5000)
X_train_tfidf = tfidf.fit_transform(X_train)
X_test_tfidf = tfidf.transform(X_test)
print(f"TF-IDF特征提取完成,用时: {time.time() - start:.2f}秒")
print(f"特征维度: {X_train_tfidf.shape[1]}")

# 5. SVM模型训练
print("\n5. 正在训练SVM模型...")
start = time.time()
svm_model = SVC(kernel='linear', random_state=42)
svm_model.fit(X_train_tfidf, y_train)
print(f"SVM模型训练完成,用时: {time.time() - start:.2f}秒")

# 6. 模型评估
print("\n6. 正在评估模型...")
start = time.time()
y_pred = svm_model.predict(X_test_tfidf)
print("分类报告:")
print(classification_report(y_test, y_pred))
print(f"模型评估完成,用时: {time.time() - start:.2f}秒")

# 总用时
print(f"\n总用时: {time.time() - total_start:.2f}秒")

最终效果

分类报告:
              precision    recall  f1-score   support

           0       0.84      0.76      0.80       505
           1       0.89      0.93      0.91      1049

    accuracy                           0.88      1554
   macro avg       0.87      0.85      0.86      1554
weighted avg       0.88      0.88      0.88      1554

3.使用XGBoost做分类器

import time
import pandas as pd
import jieba
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from xgboost import XGBClassifier
from sklearn.metrics import classification_report

# 记录总开始时间
total_start = time.time()

# 1. 数据加载
print("1. 正在加载数据...")
start = time.time()
data = pd.read_csv('/Users/zhangqingjie/Downloads/ChnSentiCorp_htl_all.csv')  # 替换为你的文件路径
print(f"数据加载完成,用时: {time.time() - start:.2f}秒")
print(f"数据样本数: {len(data)}")

# 2. 中文分词
print("\n2. 正在进行中文分词...")
start = time.time()

def chinese_tokenizer(text):
    return ' '.join(jieba.cut(text))

data['review'] = data['review'].fillna('')
data['tokenized_review'] = data['review'].apply(chinese_tokenizer)
print(f"分词完成,用时: {time.time() - start:.2f}秒")

# 3. 数据划分
print("\n3. 正在划分训练集和测试集...")
start = time.time()
X_train, X_test, y_train, y_test = train_test_split(
    data['tokenized_review'], 
    data['label'], 
    test_size=0.2, 
    random_state=42,
    shuffle=True
)
print(f"数据划分完成,用时: {time.time() - start:.2f}秒")
print(f"训练集大小: {len(X_train)}, 测试集大小: {len(X_test)}")

# 4. TF-IDF特征提取
print("\n4. 正在进行TF-IDF特征提取...")
start = time.time()
tfidf = TfidfVectorizer(max_features=5000)
X_train_tfidf = tfidf.fit_transform(X_train)
X_test_tfidf = tfidf.transform(X_test)
print(f"TF-IDF特征提取完成,用时: {time.time() - start:.2f}秒")
print(f"特征维度: {X_train_tfidf.shape[1]}")

# 5. XGBoost模型训练
print("\n5. 正在训练XGBoost模型...")
start = time.time()
xgb_model = XGBClassifier(
    n_estimators=100,
    max_depth=6,
    learning_rate=0.1,
    random_state=42,
    use_label_encoder=False,
    eval_metric='logloss'
)
xgb_model.fit(X_train_tfidf, y_train)
print(f"XGBoost模型训练完成,用时: {time.time() - start:.2f}秒")

# 6. 模型评估
print("\n6. 正在评估模型...")
start = time.time()
y_pred = xgb_model.predict(X_test_tfidf)
print("分类报告:")
print(classification_report(y_test, y_pred))
print(f"模型评估完成,用时: {time.time() - start:.2f}秒")

# 总用时
print(f"\n总用时: {time.time() - total_start:.2f}秒")

效果如下:

              precision    recall  f1-score   support

           0       0.82      0.65      0.73       505
           1       0.85      0.93      0.89      1049

    accuracy                           0.84      1554
   macro avg       0.84      0.79      0.81      1554
weighted avg       0.84      0.84      0.84      1554

4.效果对比

模型类别精确率召回率F1分数准确率
SVM00.840.760.800.88
10.890.930.91
XGBoost00.820.650.730.84
10.850.930.89

看起来SVM更胜一筹啊。

调调参,尝试抢救一下XGBoost

xgb_model = XGBClassifier(
    n_estimators=800,
    max_depth=8,
    subsample=0.8,        # 每棵树随机采样80%数据
    learning_rate=0.03,
    random_state=42,
    use_label_encoder=False, 
    objective='binary:logistic',
    eval_metric='logloss'
)

现在效果如下

分类报告:
              precision    recall  f1-score   support

           0       0.82      0.73      0.77       505
           1       0.88      0.92      0.90      1049

    accuracy                           0.86      1554
   macro avg       0.85      0.82      0.83      1554
weighted avg       0.86      0.86      0.86      1554

貌似还是差点意思。。。

6. 总结与收获

通过本篇文章的实践,我们系统地学习了如何使用TF-IDF结合不同分类器进行文本分类任务。以下是本次实践的核心收获:

5.1 关键技术掌握

  1. TF-IDF特征提取

    • 熟练使用sklearn的TfidfVectorizer进行文本向量化
    • 理解了max_featuresngram_range等关键参数对特征空间的影响
    • 掌握了中文分词处理技巧
  2. 分类器应用对比

    • 实现了SVM和XGBoost两种主流分类器
    • 观察到SVM在本任务中表现略优(88% vs 86%准确率)
    • 实践了XGBoost的参数调优过程
  3. 完整Pipeline构建

    • 从数据加载、预处理到模型训练评估的全流程实践
    • 掌握了文本分类任务的标准化开发流程

5.2 实践洞见

  1. SVM的优势显现

    • 在小规模文本数据上,SVM展现出更好的分类性能
    • 特别是对负类(差评)的识别更准确(F1 0.80 vs 0.77)
    • 验证了SVM在高维稀疏特征上的优势
  2. XGBoost的调参经验

    • 通过调整n_estimators、learning_rate等参数提升效果
    • 发现树模型需要更精细的参数调整才能达到理想效果
    • 证明了boosting算法在文本分类中的适用性
  3. 特征工程的关键性

    • TF-IDF作为基础特征提取方法仍然非常有效
    • 中文分词质量直接影响最终分类效果
    • 特征维度控制(max_features)对模型效率影响显著

思考题🤔

  1. 在本实验中,SVM在文本分类任务上表现略优于XGBoost(88% vs 86%准确率)。结合文章提到的原理,你认为可能是什么原因导致的?如果数据集规模扩大10倍,结果可能会发生怎样的变化?为什么?

  2. TF-IDF的ngram_range没有特别指定,其实内部是采用默认值的tfidf = TfidfVectorizer(max_features=5000, ngram_range=(1,1)),(即仅使用单词)。如果将其改为(1,2)(包含单词和双词组合),你认为会对分类效果产生什么影响?尝试修改代码并观察结果,验证你的猜想。

下期预告🚀
现在的NLP模型大多是预训练语言模型BERT类和GPT的衍生,你知道最初的预训练语言模型是什么样的么?

在 Transformer 和注意力机制崛起之前,Word2Vec 率先用『词向量』颠覆了传统 NLP——它让单词不再是孤立的符号,而是蕴含语义的数学向量。

下一期将深入拆解:
🔹 为什么Word2Vec是预训练模型的雏形
🔹 CBOW和Skip-Gram究竟有什么区别?
🔹 GloVe、FastText 等变体如何改进 Word2Vec?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2333990.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《车辆人机工程-汽车驾驶操纵实验》

汽车操纵装置有哪几种&#xff0c;各有什么特点 汽车操纵装置是驾驶员直接控制车辆行驶状态的关键部件&#xff0c;主要包括以下几种&#xff0c;其特点如下&#xff1a; 一、方向盘&#xff08;转向操纵装置&#xff09; 作用&#xff1a;控制车辆行驶方向&#xff0c;通过转…

python高级编程一(生成器与高级编程)

@TOC 生成器 生成器使用 通过列表⽣成式,我们可以直接创建⼀个列表。但是,受到内存限制,列表容量肯定是有限的。⽽且,创建⼀个包含100万个元素的列表,不仅占⽤很⼤的存储空间,如果我们仅仅需要访问前⾯⼏个元素,那后⾯绝⼤多数元素占 ⽤的空间都⽩⽩浪费了。所以,如果…

单片机Day05---动态数码管显示01234567

一、原理图 数组索引段码值二进制显示内容00x3f0011 1111010x060000 0110120x5b0101 1011230x4f0100 1111340x660110 0110450x6d0110 1101560x7d0111 1101670x070000 0111780x7f0111 1111890x6f0110 11119100x770111 0111A110x7c0111 1100B120x390011 1001C130x5e0101 1110D140…

muduo库源码分析: One Loop Per Thread

One Loop Per Thread的含义就是&#xff0c;一个EventLoop和一个线程唯一绑定&#xff0c;和这个EventLoop有关的&#xff0c;被这个EventLoop管辖的一切操作都必须在这个EventLoop绑定线程中执行 1.在MainEventLoop中&#xff0c;负责新连接建立的操作都要在MainEventLoop线程…

MCP结合高德地图完成配置

文章目录 1.MCP到底是什么2.cursor配置2.1配置之后的效果2.2如何进行正确的配置2.3高德地图获取key2.4选择匹配的模型 1.MCP到底是什么 作为学生&#xff0c;我们应该如何认识MCP&#xff1f;最近看到了好多跟MCP相关的文章&#xff0c;我觉得我们不应该盲目的追求热点的技术&…

重读《人件》Peopleware -(5)Ⅰ管理人力资源Ⅳ-质量—若时间允许

20世纪的心理学理论认为&#xff0c;人类的性格主要由少数几个基本本能所主导&#xff1a;生存、自尊、繁衍、领地等。这些本能直接嵌入大脑的“固件”中。我们可以在没有强烈情感的情况下理智地考虑这些本能&#xff08;就像你现在正在做的那样&#xff09;&#xff0c;但当我…

文献总结:AAAI2025-UniV2X-End-to-end autonomous driving through V2X cooperation

UniV2X 一、文章基本信息二、文章背景三、UniV2X框架1. 车路协同自动驾驶问题定义2. 稀疏-密集混合形态数据3. 交叉视图数据融合&#xff08;智能体融合&#xff09;4. 交叉视图数据融合&#xff08;车道融合&#xff09;5. 交叉视图数据融合&#xff08;占用融合&#xff09;6…

制造一只电子喵 (qwen2.5:0.5b 微调 LoRA 使用 llama-factory)

AI (神经网络模型) 可以认为是计算机的一种新的 “编程” 方式. 为了充分利用计算机, 只学习传统的编程 (编程语言/代码) 是不够的, 我们还要掌握 AI. 本文以 qwen2.5 和 llama-factory 举栗, 介绍语言模型 (LLM) 的微调 (LoRA SFT). 为了方便上手, 此处选择使用小模型 (qwen2…

Redis核心功能实现

前言 学习是个输入的过程&#xff0c;在进行输入之后再进行一些输出&#xff0c;比如写写文章&#xff0c;笔记&#xff0c;或者做一些技术串讲&#xff0c;虽然需要花费不少时间&#xff0c;但是好处很多&#xff0c;首先是能通过输出给自己的输入带来一些动力&#xff0c;然…

【连载3】基础智能体的进展与挑战综述

基础智能体的进展与挑战综述 从类脑智能到具备可进化性、协作性和安全性的系统 【翻译团队】刘军(liujunbupt.edu.cn) 钱雨欣玥 冯梓哲 李正博 李冠谕 朱宇晗 张霄天 孙大壮 黄若溪 2. 认知 人类认知是一种复杂的信息处理系统&#xff0c;它通过多个专门的神经回路协调运行…

MacOs java环境配置+maven环境配置踩坑实录

oracl官网下载jdk 1.8的安装包 注意可能需要注册&#xff01;&#xff01;&#xff01; 下载链接&#xff1a;下载地址点击 注意晚上就不要下载了 报错400 &#xff01;&#xff01;&#xff01; 1.点击安装嘛 2.配置环境变量 export JAVA_HOME/Library/Java/Java…

【Git】--- 企业级开发流程

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; Git 本篇博客我们讲解Git在企业开发中的整体流程&#xff0c;理解Git在实际企业开发中的高效设计。 &#x1f3e0; 企业级开发流程 一个软件从零开始到最…

蓝桥杯嵌入式历年省赛客观题

一.第十五届客观题 第十四届省赛 十三届 十二届

解决2080Ti使用节点ComfyUI-PuLID-Flux-Enhanced中遇到的问题

使用蓝大的工作流《一键同时换头、换脸、发型、发色之双pulid技巧》 刚开始遇到的是不支持bf16的错误 根据《bf16 is only supported on A100 GPUs #33》中提到&#xff0c;修改pulidflux.py中的dtype 为 dtype torch.float16 后&#xff0c;出现新的错误&#xff0c;这个…

LabVIEW驱动开发的解决思路

在科研项目中&#xff0c;常面临将其他语言开发的定制采集设备驱动转换为 LabVIEW 适用形式的难题。特别是当原驱动支持匮乏、开发人员技术支持不足时&#xff0c;如何抉择解决路径成为关键。以下提供具体解决思路&#xff0c;助力高效解决问题。 ​ 一、评估现有驱动死磕的可…

七、Qt框架编写的多线程应用程序

一、大纲 学习内容&#xff1a;使用两个线程&#xff0c;分别点击两个按钮&#xff0c;触发两个不同的效果 所需控件&#xff1a;两个button、三个label 涉及知识点&#xff1a;多线程、Qt的connect机制、定时器、互斥锁 需求&#xff1a; 1&#xff0c;多线程定时计数&#x…

MATLAB求和∑怎么用?

MATLAB求和∑怎么用&#xff1f; 一&#xff1a;题目&#xff1a;求下列方程的和 二、代码如下 1.syms函数 &#xff08;方法一) 代码如下&#xff08;示例&#xff09;&#xff1a; 1. syms x 2. symsum((x.^22*x).^3,1,100) 3. 2.直接用循环 (方法二) 代码如下&am…

项目二 使用miniedit创建拓扑

一、项目需求分析&#xff1a; 1. 在ubuntu的桌面环境中运行Mininet的图形化界面2. Mininet图形化界面中搭建拓扑并设置相关的设备和链路属性3. Floodlight中查看拓扑4. 完成Mininet的测试 二、项目实施步骤 1. 运行Mininet图形化界面 在“~/mininet/examples”目录下有一m…

Docker 镜像 的常用命令介绍

拉取镜像 $ docker pull imageName[:tag][:tag] tag 不写时&#xff0c;拉取的 是 latest 的镜像查看镜像 查看所有本地镜像 docker images or docker images -a查看完整的镜像的数字签名 docker images --digests查看完整的镜像ID docker images --no-trunc只查看所有的…

0x02.Redis 集群的实现原理是什么?

回答重点 Redis 集群&#xff08;Redis cluster&#xff09;是通过多个 Redis 实例组成的&#xff0c;每个主节点实例负责存储部分的数据&#xff0c;并且可以有一个或多个从节点作为备份。 具体是采用哈希槽&#xff08;Hash Slot&#xff09;机制来分配数据&#xff0c;将整…