返回

Scikit-learn TfidfVectorizer 自定义词汇避坑指南

python

Scikit-learn TfidfVectorizer 自定义词汇问题剖析

当使用 scikit-learn 的 TfidfVectorizer 进行文本向量化时,自定义词汇能够精确控制模型所使用的特征,这种方法在特定场景下尤为有用。然而,不恰当的用法也会导致意料之外的结果。本文探讨自定义词汇在 TfidfVectorizer 中的使用误区,并提供有效的解决方案。

问题表现与根源分析

当向 TfidfVectorizer 传递自定义词汇表时,常见的问题包括:

  1. 稀疏矩阵特征不匹配 :大部分文档中仅出现少量几个(通常是相同)的特征,而非文档中存在的实际单词。
  2. 结果的词向量维度偏差 : 自定义词汇表长度与实际输出的维度不一致。
  3. 自定义词汇失效 : 使用自定义词汇后的结果与模型自行生成的词汇的结果截然不同,出现明显不合逻辑的结果。

问题的核心在于,TfidfVectorizer 预期接收的自定义词汇必须与原始数据中的词元 (token) 相匹配。如果词汇表中的词语经过预处理(如大小写转换、去标点等)而原始文本没有进行相同的处理,那么模型便无法正确识别它们。

解决方案与实践

以下是几种解决 TfidfVectorizer 自定义词汇问题的方法,每种方案都有对应的代码示例,务必根据实际场景选择。

方案一:确保自定义词汇与原始词元匹配

此方法的核心在于,保持文本预处理过程的一致性。如果你的原始数据已经经过某些处理(比如小写转换、删除特殊符号),你的自定义词汇也必须经过相同的处理,这样,才能使词汇与输入匹配。反之亦然。如果希望词汇以原本的格式进行匹配,则文本也不应预先处理。

  1. 分析预处理步骤 : 明确你的 TfidfVectorizer 默认的或你设定的 tokenizer, preprocessor参数所执行的文本处理,例如:小写转换 (lowercase = True), 是否保留特定格式符号等,stop_words, 以及其他相关的设置.

  2. 自定义词汇同步处理 : 在创建自定义词汇时,对词汇执行同样的预处理操作。

示例:

import re
from sklearn.feature_extraction.text import TfidfVectorizer

# 假设 raw_vocabulary 是原始词汇表
raw_vocabulary = ["This is A Sample Sentence.", "Another_sentence_WITH_specialChars!"]
dataset2 = ["this IS a sample sentence. and more","another sentence, With SPECIAL CHARS."]


def custom_preprocess(text):
    # 这是与TfidfVectorizer设置相匹配的自定义预处理方法示例。
    text = text.lower()
    text = re.sub(r'[^a-z\s]', '', text)
    return text


processed_vocabulary = [custom_preprocess(word) for word in raw_vocabulary]
# 或者构建成字典,使用索引对应
processed_vocabulary_dict = {custom_preprocess(word): i for i,word in enumerate(raw_vocabulary)}


vectorizer = TfidfVectorizer(vocabulary=processed_vocabulary, lowercase=True, preprocessor=custom_preprocess )
# 或者指定参数preprocessor,使用自定义预处理方法。也可以不用预处理直接传入tokenizer方法,例如 nltk,spaCy.


X = vectorizer.fit_transform(dataset2)
print(X)

print(vectorizer.get_feature_names_out()) # 特征名称应该会变成预处理过后的形式。

# 当使用字典形式时
vectorizer = TfidfVectorizer(vocabulary=processed_vocabulary_dict,lowercase=True, preprocessor=custom_preprocess )
X = vectorizer.fit_transform(dataset2)
print(X)
print(vectorizer.get_feature_names_out())

操作步骤:

  1. 提取预处理步骤。根据你使用的TfidfVectorizer配置。
  2. 实现匹配的处理方法(上述的custom_preprocess),确保它与你的TfidfVectorizer的预处理方式保持一致。
  3. 使用预处理过的词汇表初始化你的TfidfVectorizer.

方案二:自定义分词器(Tokenizer)

除了对整个文本进行预处理外,有时更精确的分词逻辑也很重要。这时可以创建自定义分词器来处理你的词汇表与输入。
分词器负责把一段文本切分成词语(或词元)。TfidfVectorizer默认的分词方式通常为以空格进行分割,可以使用特定的词语,或者NLTK, spaCy中的tokenizer.
以下展示如何自定义分词器。

import re
from sklearn.feature_extraction.text import TfidfVectorizer

dataset2 = ["this IS a sample sentence. and more","another sentence, With SPECIAL CHARS."]

def custom_tokenizer(text):
    #这里你可以根据你的词语格式自定义任何复杂的分词方法
    return re.findall(r'\b\w+\b', text.lower())  # 最简单地使用\b\w+\b捕获小写的单词,以单词边界做分隔。
    

raw_vocabulary = ["This is A Sample Sentence.", "Another_sentence_WITH_specialChars!","Sample","chars"]
processed_vocabulary_list = [ word.lower()  for word in raw_vocabulary if word.lower() ] 

# 创建自定义的Tokenizer
vectorizer = TfidfVectorizer(vocabulary = processed_vocabulary_list,tokenizer = custom_tokenizer)

X = vectorizer.fit_transform(dataset2)
print(X)

print(vectorizer.get_feature_names_out())

操作步骤:

  1. 创建一个分词方法(上述代码的custom_tokenizer), 该方法应当将原始数据分割成词元(tokens)返回。确保此分词方法正确反映你的原始数据。
  2. 实例化TfidfVectorizer, 使用tokenizer = custom_tokenizer方法, 使用已预处理(如果有)过的vocabulary

额外安全建议

  • 词汇表校验 : 在应用 TfidfVectorizer之前,输出一部分经过预处理的词汇,以及文本中进行token化后的片段,检验它们是否一致。
  • 控制输出 : 对于维度过高导致的不合理输出, 可以使用PCA,或者其他的降维方法,减少维度,增强模型性能。
  • 异常排查 : 如果输出存在大量重复的相同特征,检查词汇表的预处理,以及分词器逻辑。

总之,确保自定义词汇表与输入文本的词元匹配是成功使用 TfidfVectorizer的关键。选择正确的预处理方法,或者自定义tokenizer,并验证结果是至关重要的步骤。 通过以上方法可以有效规避大部分相关问题。