You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 18:50:26