文本分类中的词袋特征矩阵为什么是稀疏矩阵——以 python-machine-learning-book 情感分析实战为例【免费下载链接】python-machine-learning-bookThe Python Machine Learning (1st edition) book code repository and info resource项目地址: https://gitcode.com/gh_mirrors/py/python-machine-learning-book词袋bag-of-words模型把每篇文档表示为一个维度等于词表大小的计数向量绝大多数维度取值都是 0因此拼接起来的特征矩阵在真实数据集上几乎总是稀疏的。本文基于本项目 faq/bag-of-words-sparsity.md 的原始论述结合第 8 章情感分析code/ch08/ch08.ipynb与第 9 章电影评论分类器code/ch09/ch09.ipynb的源码讲清稀疏性的定义、触发条件、一个完整的稠密/稀疏判定示例以及稀疏表示在 scikit-learn 管线中的实际意义与工程处理方式。读完你将能判断自己的词袋特征矩阵是否稀疏、为什么必须保留稀疏存储并理解CountVectorizer、TfidfVectorizer、HashingVectorizer与SGDClassifier协同工作的底层原理。结论先行是的绝大多数情况下词袋特征矩阵是稀疏的回到 FAQ 提出的问题——用于文本分类的词袋特征表示可以被视为稀疏矩阵吗原始文档给出的回答是这取决于你的词表vocabulary和数据集但通常情况下毫无疑问是的要理解这句话先明确稀疏的严格定义如果矩阵中大部分元素为零就称它为稀疏矩阵。在词袋模型中每篇文档被表示为一个词计数向量向量的每个位置对应词表中的一个词取值可以是二进制计数binary count该词是否出现出现为 1否则为 0绝对计数absolute count即词频 term frequency或归一化后的计数。向量长度等于词表大小。只要大部分文档的特征向量是稀疏的由这些向量堆叠而成的词袋特征矩阵就极大概率也是稀疏的。什么时候词袋向量会变稠密——稀疏性的三个决定因素FAQ 指出向量何时稀疏取决于三个因素词表大小vocabulary size词表越大每个文档向量中非零元素占比就越低矩阵越稀疏文档长度document length文档越短一篇文档能覆盖的词就越少向量越稀疏文档多样性/相似度variety of documents语料中文档越相似、用词越集中词表就越小矩阵越接近稠密。原文对此有一个精确的边界判断训练集中文档越短、彼此越相似最终越可能得到稠密矩阵——但在真实应用中这依然几乎不可能发生。原因很直观即便语料高度同质词表通常也远大于单篇文档的词汇量于是每篇文档的向量中仍然充斥着大量零元素。一个完整的判定示例3 篇文档的稠密与稀疏边界FAQ 给出了一个平凡但极具说服力的示例设我们有 3 篇文档Doc1Hello, World, the sun is shiningDoc2Hello world, the weather is niceDoc3Hello world, the wind is cold使用 1-gram一元词元且不做停用词移除得到词表Vocabulary: [hello, world, the, wind, weather, sun, is, shining, nice, cold]对应的二进制特征向量为Doc1[1, 1, 1, 0, 0, 0, 1, 1, 0, 0]Doc2[1, 1, 1, 0, 0, 1, 0, 1, 1, 0]Doc3[1, 1, 1, 1, 0, 0, 1, 0, 0, 1]拼成稠密矩阵后[[1, 1, 1, 0, 0, 0, 1, 1, 0, 0] [1, 1, 1, 0, 0, 1, 0, 1, 1, 0] [1, 1, 1, 1, 0, 0, 1, 0, 0, 1]]统计一下矩阵共 3 × 10 30 个元素其中17 个 1、13 个 0。由于非零元素占比过半按定义这不算稀疏矩阵。但 FAQ 随即点出要害我们也能猜到这种场景在真实应用中几乎不可能出现——这正是该示例的价值它用一个人为构造的极端反例反衬出真实文本数据的稀疏程度。真实数据下的稀疏规模从源码看词袋矩阵的实际形状把示例放大到本项目实际使用的数据规模稀疏性立刻变得压倒性。第 8、9 章使用的 IMDb 电影评论数据集见 code/datasets/movie/README.md包含 50,000 条评论前 25,000 条为训练集、后 25,000 条为测试集。在 code/optional-py-scripts/ch08.py 中可以看到基础建模流程count CountVectorizer() docs np.array([The sun is shining, The weather is sweet, The sun is shining and the weather is sweet]) bag count.fit_transform(docs) print(Vocabulary, count.vocabulary_) print(bag.toarray(), bag.toarray())注意fit_transform返回的bag在 scikit-learn 中本身就是 scipy 稀疏矩阵CSR 格式只有显式调用.toarray()才会转成稠密 numpy 数组。在 5 万条评论上CountVectorizer构造的词表通常达到数万甚至数十万量级而一条电影评论平均只有一两百个词元——这意味着每条特征向量的非零占比通常在千分之一以下稀疏性比 FAQ 示例中那个 17/30 的稠密矩阵高出几个数量级。这正是真实数据几乎必然稀疏的量化证据。从源码结构还可以推断如果在此规模上调用.toarray()把矩阵稠密化5 万行 × 数万列以 float64 存储将轻松消耗数 GB 内存而 CSR 稀疏格式只保存非零元素及其行列索引内存占用往往缩小一到两个数量级。这正是 scikit-learn 所有文本向量化器默认返回稀疏矩阵的根本原因。工程视角稀疏矩阵如何贯穿情感分析全流程稀疏表示不是孤立概念它贯穿了本项目第 8、9 章的完整文本分类管线可以从三处源码得到印证。1. 词频加权TfidfTransformer与TfidfVectorizer第 8 章在词袋计数之上进一步做 TF-IDF 加权见 code/optional-py-scripts/ch08.pytfidf TfidfTransformer(use_idfTrue, norml2, smooth_idfTrue) print(tfidf.fit_transform(count.fit_transform(docs)).toarray())fit_transform同样保持稀疏输出.toarray()仅用于打印查看。TF-IDF 在稀疏矩阵上可以高效实现idf 权重只需对每个词统计文档频率一次稀疏矩阵的列统计而 l2 归一化逐行进行都不需要物化稠密矩阵。2. 在线学习与哈希向量化HashingVectorizerSGDClassifier第 9 章把模型嵌入 Flask Web 应用code/ch09/README.md其中 code/ch09/movieclassifier/vectorizer.py 使用哈希技巧vect HashingVectorizer(decode_errorignore, n_features2**21, preprocessorNone, tokenizertokenizer)n_features2**21约 210 万维是稀疏性最直接的体现即使词表映射到 210 万维的哈希空间每条评论向量仍只有几十到几百个非零项。该向量化器配合SGDClassifier(losslog)的partial_fit实现真正的 out-of-core 在线学习见 code/optional-py-scripts/ch08.pyclf SGDClassifier(losslog, random_state1, n_iter1) for _ in range(45): X_train, y_train get_minibatch(doc_stream, size1000) if not X_train: break X_train vect.transform(X_train) clf.partial_fit(X_train, y_train, classesclasses)vect.transform(X_train)输出的就是稀疏矩阵SGDClassifier等线性模型内部按稀疏数据结构计算梯度与预测从而在不把全部数据载入内存的前提下处理 5 万条评论。预测阶段code/ch09/movieclassifier/app.py同样是X vect.transform([document])后直接喂给模型——单条输入的稀疏向量在高维空间中只有极少数非零项计算开销极小。3. 稀疏性带来的实际工程收益综合上述源码可以把词袋矩阵的稀疏性总结为三项工程收益内存可承受CSR/稀疏矩阵只存非零项5 万文档 × 210 万维的特征空间才能常驻内存计算可加速SGDClassifier.partial_fit与TfidfTransformer的矩阵运算按稀疏结构迭代复杂度与文档总词数非零项总数成正比而非矩阵整体规模流式处理成为可能HashingVectorizer不依赖全局词表统计可以随stream_docs逐批变换文本这正是 out-of-core 在线学习code/ch08/ch08.ipynb 中Working with bigger data一节的主题能够成立的前提。总结如何判断你的词袋矩阵是否稀疏将 FAQ 的论述整理成可直接套用的判定流程算非零占比统计特征矩阵中非零元素数量与总元素数量之比若远低于 0.5即为稀疏矩阵预估词表规模词表越大、文档越短、语料差异越大稀疏性越强仅当词表极小且文档高度同质时如 FAQ 的 3 篇示例才可能出现稠密边界情形检查存储格式在 scikit-learn 中CountVectorizer、TfidfVectorizer、HashingVectorizer的fit_transform/transform默认返回稀疏矩阵务必保持稀疏传递到下游模型避免无谓的.toarray()稠密化。真实世界的文本分类任务如本项目第 8、9 章的 IMDb 情感分析几乎不可能落入稠密区间——词表大小、文档长度与语料多样性的自然组合保证了词袋特征矩阵从定义上就是稀疏矩阵而这一性质正是高维文本特征能够被高效训练与部署的根本原因。【免费下载链接】python-machine-learning-bookThe Python Machine Learning (1st edition) book code repository and info resource项目地址: https://gitcode.com/gh_mirrors/py/python-machine-learning-book创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
