如何优化基于sklearn CountVectorizer的词汇覆盖率计算方法?
优化CountVectorizer词汇覆盖率计算的方案
问题背景
已基于语料库训练好sklearn的CountVectorizer对象,对新文档向量化时向量仅包含词汇表中的词。希望为向量添加词汇覆盖率特征(即文档中属于词汇表的词占比),现有实现代码如下:
from sklearn.feature_extraction.text import CountVectorizer corpus = [ "good morning sunshine", "hello world", "hello sunshine", ] vectorizer = CountVectorizer() vectorizer.fit_transform(corpus) def get_vocab_coverage(vectorizer, sent): preprocessor = vectorizer.build_preprocessor() tokenizer = vectorizer.build_tokenizer() processed = preprocessor(sent) tokenized_license = tokenizer(processed) count = sum(w in vectorizer.vocabulary_ for w in tokenized_license) return count / len(tokenized_license) get_vocab_coverage(vectorizer, "hello world") # => 1.0 get_vocab_coverage(vectorizer, "hello to you") # => 0.333
该代码存在不够Python化、直接依赖sklearn内部变量、扩展性不足的问题,以下是优化方案:
一、Python化且低耦合的实现
核心思路是复用CountVectorizer的官方API,避免直接操作内部属性,同时简化文本处理流程:
from sklearn.feature_extraction.text import CountVectorizer import numpy as np corpus = [ "good morning sunshine", "hello world", "hello sunshine", ] vectorizer = CountVectorizer() vectorizer.fit_transform(corpus) def get_vocab_coverage(vectorizer, sent): # 调用analyzer获取完整处理后的分词结果(含预处理、分词、停用词过滤等) processed_words = vectorizer.build_analyzer()(sent) total_words = len(processed_words) if total_words == 0: return 0.0 # 用transform获取匹配词汇的总数量,避免遍历判断 matched_count = vectorizer.transform([sent]).sum() return matched_count / total_words # 测试用例 print(get_vocab_coverage(vectorizer, "hello world")) # 输出 1.0 print(get_vocab_coverage(vectorizer, "hello to you")) # 输出 0.333...
优化点说明
- 用
build_analyzer()替代单独调用预处理和分词函数,复用CountVectorizer的完整文本处理逻辑,更符合官方设计 - 通过
transform结果求和获取匹配词汇数,解耦对内部vocabulary_属性的依赖 - 增加空文本判断,避免除以0的运行时异常
二、扩展性优化:支持批量处理与Pipeline集成
如果需要批量处理文档,或要将覆盖率特征与词向量结合,可以封装成sklearn兼容的Transformer:
from sklearn.base import BaseEstimator, TransformerMixin class VocabCoverageTransformer(BaseEstimator, TransformerMixin): def __init__(self, vectorizer): self.vectorizer = vectorizer def fit(self, X, y=None): # 无需额外拟合,直接返回自身 return self def transform(self, X): coverage_list = [] for doc in X: processed = self.vectorizer.build_analyzer()(doc) total = len(processed) if total == 0: coverage_list.append(0.0) continue matched = self.vectorizer.transform([doc]).sum() coverage_list.append(matched / total) # 转换为二维数组,符合sklearn特征矩阵格式 return np.array(coverage_list).reshape(-1, 1) # 批量测试 docs = ["hello world", "hello to you", "goodbye moon"] coverage_transformer = VocabCoverageTransformer(vectorizer) print(coverage_transformer.transform(docs)) # 输出: # [[1. ] # [0.33333333] # [0. ]]
这个Transformer可直接集成到sklearn Pipeline中,与CountVectorizer的输出拼接,形成包含词向量和覆盖率的完整特征集。
三、是否有现成方法?
sklearn官方未提供直接计算词汇覆盖率的API,但通过组合build_analyzer()、transform()等现有方法,即可高效实现需求,无需额外依赖第三方库。
内容的提问来源于stack exchange,提问作者Gino
相关产品推荐
相关产品推荐

