使用sklearn的TfidfVectorizer按评分阈值提取n-grams的相关问题
问题1:是否可以修改n-grams的评分规则,使其支持基于频率之外的指标筛选特征?
sklearn原生的TfidfVectorizer没有直接提供自定义n-gram打分的参数,但可以通过以下两种方案实现需求:
- 方案1:预生成合法n-gram词汇表
先用gensim叠层训练Phrases模型得到2/3/4元组,按PMI/NPMI阈值筛选出符合要求的n-gram列表,再将该列表传入TfidfVectorizer的vocabulary参数,vectorizer只会提取列表内的特征,完全跳过默认的频率筛选逻辑,天然兼容sklearn流水线。 - 方案2:重写vectorizer逻辑
继承TfidfVectorizer类,重写build_analyzer方法,在生成n-gram的步骤后插入自定义打分(如自行实现PMI计算)和过滤逻辑,低于阈值的n-gram直接丢弃,全程在sklearn体系内完成,无需额外依赖。
问题2:是否有方法避免同一个词语序列被拆分为多个不同的n-grams特征重复计数?
可以通过最长匹配优先的规则实现,两种落地方式都兼容sklearn流水线:
- 方案1:预处理阶段文本替换
先基于你筛选好的合法n-gram列表,对每一条输入文本做最长匹配:优先匹配长度最长的n-gram,匹配到之后将对应文本段用下划线连接为单个词(如new york city替换为new_york_city),同时标记该段文本不再参与更短的n-gram匹配。处理完成后将TfidfVectorizer的ngram_range设置为(1,1)即可,完全避免重复计数。 - 方案2:特征矩阵后处理
得到tfidf特征矩阵后,对每个文本的非零特征按n-gram长度倒序排序,保留最长的重叠匹配项,将其余更短的重叠特征的得分置0即可,该方案实现成本更低,无需修改特征提取逻辑。
补充:gensim嵌入sklearn流水线的实现方法
你可以自定义符合sklearn规范的Transformer类,就能直接把gensim的n-gram提取逻辑嵌入流水线,示例代码如下:
from sklearn.base import BaseEstimator, TransformerMixin from gensim.models import Phrases class GensimPhraseTransformer(BaseEstimator, TransformerMixin): def __init__(self, min_count=2, threshold=10, max_n=4): self.min_count = min_count self.threshold = threshold self.max_n = max_n self.phrase_models = [] def fit(self, X, y=None): # 按n从2到max_n叠层训练Phrases模型 tokenized_docs = [doc.split() for doc in X] current_docs = tokenized_docs for n in range(2, self.max_n+1): model = Phrases(current_docs, min_count=self.min_count, threshold=self.threshold) self.phrase_models.append(model) current_docs = model[current_docs] return self def transform(self, X, y=None): tokenized_docs = [doc.split() for doc in X] for model in self.phrase_models: tokenized_docs = model[tokenized_docs] # 把处理好的token拼接回文本,供后续TfidfVectorizer使用 return [" ".join(tokens) for tokens in tokenized_docs]
之后就可以直接把这个类放到sklearn的Pipeline中,和TfidfVectorizer串联使用,训练、预测流程都完全符合sklearn的规范。
内容的提问来源于stack exchange,提问作者Jaccar
相关产品推荐
相关产品推荐

