评估文本分类器时,通常使用精确度、召回率和F1分数等指标。然而,仅通过将数据单次固定划分为训练集和测试集来评估模型可能产生误导。模型的性能可能仅仅因为测试集中恰好包含的特定文档而显得过于乐观或悲观。为了更可靠地估计分类器在未见数据上的表现,交叉验证提供了一种有效的解决方案。单一训练-测试划分的局限性当您只对数据集进行一次划分时,您的评估指标在很大程度上取决于该特定划分。如果您的测试集碰巧包含异常简单或困难的示例,您的性能估计将无法准确反映模型的真实泛化能力。此外,您用于训练的数据量少于可用数据,可能导致模型不够理想。交叉验证技术通过系统地使用数据的不同子集进行训练和验证来解决这些问题。K折交叉验证最常用的交叉验证策略是K折交叉验证。其工作原理如下:划分: 整个数据集被随机划分为$K$个大小相等(或近似相等)的子集,通常称为“折”。$K$的常见选择是5或10。迭代: 此过程重复$K$次。在每次迭代$i$中:第$i$折被作为验证集(或测试折)保留。其余的$K-1$折组合形成训练集。分类模型在训练集上进行训练。训练好的模型在验证集(第$i$折)上进行评估,并记录所需的评估指标(例如,准确率、F1分数)。聚合: 经过$K$次迭代后,您将获得$K$个不同的性能得分。整体交叉验证性能通常计算为这$K$个得分的平均值。这个平均值比单一训练-测试划分更能可靠地估计模型的性能。下图说明了K=5折的过程:digraph KFold { rankdir=LR; node [shape=rect, style=filled, color="#ced4da", fontname="sans-serif"]; edge [arrowhead=none, penwidth=2]; subgraph cluster_data { label = "数据集"; bgcolor="#e9ecef"; style=filled; D1 [label="折 1"]; D2 [label="折 2"]; D3 [label="折 3"]; D4 [label="折 4"]; D5 [label="折 5"]; } subgraph cluster_iter1 { label = "迭代 1"; bgcolor="#a5d8ff"; style=filled; T1 [label="训练 (F2, F3, F4, F5)", shape=box, style=filled, color="#74c0fc"]; V1 [label="验证 (F1)", shape=box, style=filled, color="#ffc9c9"]; T1 -> V1 [style=invis]; } subgraph cluster_iter2 { label = "迭代 2"; bgcolor="#a5d8ff"; style=filled; T2 [label="训练 (F1, F3, F4, F5)", shape=box, style=filled, color="#74c0fc"]; V2 [label="验证 (F2)", shape=box, style=filled, color="#ffc9c9"]; T2 -> V2 [style=invis]; } subgraph cluster_iter3 { label = "迭代 3"; bgcolor="#a5d8ff"; style=filled; T3 [label="训练 (F1, F2, F4, F5)", shape=box, style=filled, color="#74c0fc"]; V3 [label="验证 (F3)", shape=box, style=filled, color="#ffc9c9"]; T3 -> V3 [style=invis]; } subgraph cluster_iter4 { label = "迭代 4"; bgcolor="#a5d8ff"; style=filled; T4 [label="训练 (F1, F2, F3, F5)", shape=box, style=filled, color="#74c0fc"]; V4 [label="验证 (F4)", shape=box, style=filled, color="#ffc9c9"]; T4 -> V4 [style=invis]; } subgraph cluster_iter5 { label = "迭代 5"; bgcolor="#a5d8ff"; style=filled; T5 [label="训练 (F1, F2, F3, F4)", shape=box, style=filled, color="#74c0fc"]; V5 [label="验证 (F5)", shape=box, style=filled, color="#ffc9c9"]; T5 -> V5 [style=invis]; } {rank=same; D1 D2 D3 D4 D5} {D1, D2, D3, D4, D5} -> {T1, V1} [style=invis]; {D1, D2, D3, D4, D5} -> {T2, V2} [style=invis]; {D1, D2, D3, D4, D5} -> {T3, V3} [style=invis]; {D1, D2, D3, D4, D5} -> {T4, V4} [style=invis]; {D1, D2, D3, D4, D5} -> {T5, V5} [style=invis]; Result [label="平均性能得分", shape=ellipse, style=filled, color="#b2f2bb"]; {V1, V2, V3, V4, V5} -> Result [style=invis]; } K折交叉验证将数据分成K个折。每个折恰好用作验证集一次,而其余K-1个折用于训练。性能指标在所有K次迭代中取平均值。分层K折交叉验证在文本分类中,特别是在垃圾邮件检测或小众话题的情感分析等任务中,您可能会遇到不平衡数据集,其中某些类别的示例远少于其他类别。标准K折随机划分数据,这可能碰巧导致某些折中包含非常少甚至没有少数类别的实例。在这些折上进行训练或评估可能会导致不可靠的结果。分层K折是旨在处理此情况的一种变体。在创建折时,它确保每个折中各类别样本的比例与原始数据集中的比例大致相同。例如,如果您的数据集包含10%的垃圾邮件和90%的非垃圾邮件,分层K折的目标是让每个折反映这种10/90的划分。这对文本分类尤为重要,因为类别不平衡很常见。使用分层K折能让您更有信心,您的评估能反映模型处理所有类别(即使是稀有类别)的能力。在处理本章后面讨论的不平衡数据集策略时,这一点变得非常必要。文本数据实现时的考量在为文本分类流程实现交叉验证时,请注意以下几点:防止数据泄露: 验证折中的信息不“泄露”到该折的训练过程中,这一点非常重要。这最常发生在特征工程期间。例如,如果您正在使用TF-IDF,IDF成分应仅根据当前折的训练数据计算。如果在执行交叉验证之前对整个数据集计算TF-IDF并应用,会给模型提供关于验证集的隐式信息,导致过于乐观的得分。整个流程,包括文本预处理和特征提取(如TF-IDF向量化或N-gram生成),必须在交叉验证循环的每个折中独立应用。仅在每个折的训练部分上拟合您的向量器或其他特征转换器,然后使用它们来转换训练和验证部分。聚合结果: 您将获得$K$组性能指标(例如,$K$个F1分数,$K$个精确度分数)。通常,您报告这些指标的平均值,并且常常报告标准差。平均值提供了性能的中心估计,而标准差提供了关于模型在不同数据子集上性能变异性或稳定性的认识。计算成本: 交叉验证包括训练模型$K$次,而不是仅仅一次。这增加了计算时间,特别是对于大型数据集或复杂模型。然而,更可靠的性能估计的好处通常超过此成本,特别是在模型选择和超参数调整期间。通过采用K折或分层K折等交叉验证策略,您能获得对文本分类模型在新、未见文档上表现的更值得信赖的评估。这种评估是比较不同模型或有效调整参数的基础,我们接下来将讨论。