如何在Spacy中将Lexeme转换为Token以过滤词性获取同义词?
解决spaCy中Lexeme转Token并过滤词性的问题
我来帮你搞定这个问题——你遇到的核心问题有两个:一是错误地尝试直接累加Token对象导致报错,二是用了空白的English()模型无法正确获取词性标注。下面是具体的修复方案和优化后的代码:
首先解释你的错误:token += doc[counter]这行代码完全行不通,因为spaCy的Token对象是不可变的单个词元,不能用+=来拼接。而且你用的English()是空白模型,没有加载任何词性标注的权重,就算解析了字符串也拿不到正确的pos_属性。
正确的Lexeme转Token方法
其实不需要把多个候选词拼成字符串再批量解析,更高效的方式是针对每个Lexeme,直接用训练好的模型处理它的字符串形式,这样就能得到带有完整词性信息的Token。因为每个Lexeme代表的是一个词的基础形态,用模型处理它的orth_(即对应的字符串)就能得到对应的Token。
优化后的完整代码
下面是修改后的代码,实现了只保留动词类的同义词候选:
from numpy import dot from numpy.linalg import norm import spacy # 加载带词向量和词性标注的模型(必须用训练好的模型,不能用空白的English()) nlp = spacy.load('en_core_web_md') my_word = 'look' # 获取目标词的Lexeme target_lexeme = nlp.vocab[my_word] # 余弦相似度函数(增加分母非零判断,避免报错) cosine = lambda v1, v2: dot(v1, v2) / (norm(v1) * norm(v2)) if (norm(v1) * norm(v2)) != 0 else 0 # 筛选候选Lexeme:有向量、小写形式、不是目标词本身 candidates = [w for w in nlp.vocab if w.has_vector and w.orth_.islower() and w.lower_ != my_word.lower()] # 按相似度从高到低排序 candidates.sort(key=lambda w: cosine(w.vector, target_lexeme.vector), reverse=True) # 转换为Token并过滤动词,取前10个符合条件的结果 filtered_synonyms = [] for lexeme in candidates: # 将Lexeme的字符串形式传入模型,得到对应的Token token = nlp(lexeme.orth_)[0] # 过滤词性为动词的词(VERB是spaCy的标准词性标签) if token.pos_ == "VERB": filtered_synonyms.append((token.text, cosine(lexeme.vector, target_lexeme.vector))) # 收集够10个结果就停止遍历 if len(filtered_synonyms) >= 10: break # 输出最终结果 print(f"与'{my_word}'最相似的动词同义词:") for word, score in filtered_synonyms: print(f"{word} - 相似度: {score:.4f}")
关键说明
- 模型选择:必须使用
en_core_web_md或en_core_web_lg这类预训练模型,它们包含词性标注器和词向量,而English()是空白模型,没有这些核心功能。 - Lexeme转Token:通过
nlp(lexeme.orth_)[0]直接将Lexeme对应的字符串转换为Token,这样就能获取pos_属性进行词性过滤。 - 错误修复:去掉了错误的Token累加逻辑,改为逐个处理候选Lexeme,筛选符合词性要求的结果。
- 鲁棒性优化:给余弦相似度函数加了分母不为0的判断,避免出现除以0的运行时错误。
额外优化建议
如果需要处理大量候选词,你可以提前将常用词的Lexeme和对应Token缓存起来,避免重复调用nlp()解析,提升运行效率。另外,如果你想更精准地筛选同义词,还可以结合token.lemma_(词元的原型)来过滤掉形态不同但语义相同的词。
内容的提问来源于stack exchange,提问作者jax
相关产品推荐
相关产品推荐

