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

如何在scikit-learn的TfidfVectorizer中添加同义词识别?

嘿,这个需求我太熟了!分两种场景给你解决方案,刚好覆盖你举的house/houses这类词形变化,以及更广义的同义词映射:

方案1:用词形还原搞定单复数/时态这类词形变化

你举的house和houses其实属于词形变化,用「词形还原(Lemmatization)」就能轻松把它们统一成同一个词。推荐用NLTK的WordNetLemmatizer,它能根据词性精准还原单词,比简单的词干提取(Stemming)效果更自然。

具体步骤:

  • 自定义一个分词器,先做基础分词,再对每个token做词形还原
  • 把这个分词器传给TfidfVectorizer的tokenizer参数

代码示例:

from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.stem import WordNetLemmatizer
import nltk

# 第一次运行需要下载NLTK的必要数据
nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger')

lemmatizer = WordNetLemmatizer()

def lemmatize_token(token):
    # 获取词性标签,让还原更准确(比如区分名词house和动词house)
    pos_tag = nltk.pos_tag([token])[0][1][0].lower()
    # 只保留名词/动词/形容词/副词的标签,其他默认按名词处理
    pos = pos_tag if pos_tag in ['n', 'v', 'a', 'r'] else 'n'
    return lemmatizer.lemmatize(token, pos=pos)

def custom_tokenizer(text):
    # 先用Tfidf默认的分词器拆分文本
    base_tokens = TfidfVectorizer().build_tokenizer()(text)
    # 对每个token做词形还原
    return [lemmatize_token(token) for token in base_tokens]

# 实例化TfidfVectorizer,使用自定义分词器
tfidf = TfidfVectorizer(tokenizer=custom_tokenizer)

# 测试一下效果
corpus = ["I own a house", "They bought three houses", "She is housing a friend"]
X = tfidf.fit_transform(corpus)
print(tfidf.get_feature_names_out())
# 输出会包含house(houses被还原成house,housing作为动词也会被还原成house)
方案2:自定义同义词映射处理广义同义词

如果除了词形变化,你还需要把真正的同义词(比如house和home、apartment)统一成同一个术语,那就需要做一个同义词映射字典,在分词后替换对应的词。

可以把同义词映射和词形还原结合起来,效果更好:

from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.stem import WordNetLemmatizer
import nltk
import re

nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger')

# 定义你的同义词映射:键是要替换的词,值是统一的目标词
synonym_map = {
    "home": "house",
    "apartment": "house",
    "bungalow": "house"
}

lemmatizer = WordNetLemmatizer()

def lemmatize_token(token):
    pos_tag = nltk.pos_tag([token])[0][1][0].lower()
    pos = pos_tag if pos_tag in ['n', 'v', 'a', 'r'] else 'n'
    return lemmatizer.lemmatize(token, pos=pos)

def custom_tokenizer(text):
    base_tokens = TfidfVectorizer().build_tokenizer()(text)
    # 先做词形还原,再替换同义词
    lemmatized_tokens = [lemmatize_token(token) for token in base_tokens]
    # 替换同义词:如果token在映射里就替换,否则保留原词
    final_tokens = [synonym_map.get(token.lower(), token) for token in lemmatized_tokens]
    return final_tokens

# 如果你想在文本层面替换(避免分词后漏处理),可以用preprocessor
def custom_preprocessor(text):
    text = text.lower()
    for syn, target in synonym_map.items():
        # 用正则匹配整个单词,避免替换到单词的一部分(比如把"household"误改)
        text = re.sub(r'\b' + re.escape(syn) + r'\b', target, text)
    return text

# 实例化时同时传入preprocessor和tokenizer
tfidf = TfidfVectorizer(preprocessor=custom_preprocessor, tokenizer=custom_tokenizer)

# 测试效果
corpus = ["I live in a house", "My home is cozy", "He rents an apartment"]
X = tfidf.fit_transform(corpus)
print(tfidf.get_feature_names_out())
# 输出只会有house,因为home、apartment都被统一成house了
额外注意事项
  • 停用词处理:如果用了自定义分词器,记得手动过滤停用词。可以通过TfidfVectorizer(stop_words='english').get_stop_words()获取默认停用词列表,在分词时过滤。
  • 大小写问题:建议在预处理阶段把文本转成小写,避免House和house被当成两个不同的词。
  • 正则替换的准确性:用\b匹配单词边界,防止替换到单词的子串(比如把houses替换成house时,不会影响household)。

内容的提问来源于stack exchange,提问作者Federico Caccia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:33:26