如何优化NLP场景下NLTK停用词移除与词形还原的计算速度
预处理速度优化方案
原代码的性能瓶颈主要来自四个重复开销点,针对性修改后无需更换核心依赖即可把27000条数据的总预处理耗时压到10秒以内,配合多进程加速可降至3-5秒,和模型评估速度基本持平。
核心性能瓶颈说明
- 重复加载停用词表:
remove_stopwords函数每次调用都重新读取stopwords.words("english"),没有复用你已经初始化好的stop全局集合,反复的IO和对象构建占用了一半以上的耗时 - 单次POS标注效率极低:
get_wordnet_pos每次仅对单个单词做词性标注,nltk的pos_tag批量处理整句的效率是单次单词语料的上百倍 - 正则表达式未预编译:
punct_strip函数每次调用都重新编译正则规则,重复计算开销大 - 多次串行apply:停用词移除和词形还原分两次做
apply,多走了一遍逐行串行调度开销,还多次重复做字符串的split/join操作
优化后代码
import pandas as pd import re import nltk from nltk.corpus import stopwords, wordnet from nltk.stem import WordNetLemmatizer from nltk.tag import pos_tag # 全局对象仅初始化加载一次 nltk.download("all") stop = set(stopwords.words('english')) lemmatizer = WordNetLemmatizer() # 预编译正则规则 punct_re = re.compile(r'[^\w\s]') # 词性映射表提前构建,避免每次函数调用重复生成 tag_dict = {"J": wordnet.ADJ, "N": wordnet.NOUN, "V": wordnet.VERB, "R": wordnet.ADV} # 合并全部预处理逻辑,单次遍历完成所有操作 def text_preprocess(entry): # 1. 批量清洗标点 clean_text = punct_re.sub(' ', entry) # 2. 整句仅做一次POS标注,大幅降低调度开销 word_pos_pairs = pos_tag(clean_text.split()) res_words = [] for word, tag in word_pos_pairs: # 同步完成停用词过滤+词形还原,仅遍历单词一次;转小写匹配避免大小写漏匹配的Bug if word.lower() not in stop: wordnet_pos = tag_dict.get(tag[0].upper(), wordnet.NOUN) res_words.append(lemmatizer.lemmatize(word, wordnet_pos)) return " ".join(res_words) # 单次apply完成全部预处理,避免多次串行调用 df["Description_processed"] = df["Description"].apply(text_preprocess)
进一步加速方案
如果需要更快的处理速度,安装swifter库后将最后一行替换为以下代码,swifter会自动识别函数逻辑,无法向量化的场景会自动开启多进程利用CPU多核计算,27000条数据的处理耗时可进一步压缩到3-5秒:
import swifter df["Description_processed"] = df["Description"].swifter.apply(text_preprocess)
内容的提问来源于stack exchange,提问作者SteP
相关产品推荐
相关产品推荐

