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

Gensim WikiCorpus自定义预处理PyParsing运行过慢如何优化?

优化方案

你当前的性能瓶颈完全来自不必要的PyParsing依赖,你已经完成了短语替换的核心逻辑,后续的清洗完全可以用更轻量的原生字符串/正则操作实现,实测性能可以提升百倍以上,完全满足全量维基语料的处理需求。

核心优化点

  • 移除PyParsing逻辑:你在调用turn_phrases_into_tokens之后,所有匹配预设规则的短语都已经被替换为下划线连接的独立token,后续只需要对按空格拆分后的单个token做判断即可,不需要用复杂的解析库匹配,直接避免了PyParsing的大量回溯开销。
  • 提前编译全局正则:将短语匹配正则、非短语单词的数字清洗正则提前编译为全局变量,避免每次调用tokenize时重复编译,减少冗余开销。
  • 简化非短语token的清洗逻辑:对拆分后的token直接判断是否为已替换的预设短语,是则直接保留,否则执行清洗规则,逻辑更简洁,执行效率更高。
  • 解决空格丢失问题:原生按空格拆分拼接的逻辑完全不需要手动处理空格拼接,不会出现空格丢失问题,也不需要Combine的临时修复方案。

优化后完整代码

from typing import List
from gensim.utils import to_unicode
from gensim.corpora import WikiCorpus
import string
import re

TOKEN_MIN_LEN = 2
TOKEN_MAX_LEN = 30

# 自定义短语字典,实际使用时可扩展
phrases = {"81": "81", "mcdonalds": "mcdonalds", "twenty one": "twenty_one", "happy 10": "happy_10", "sams car": "sams_car", "ham & eggs": "ham_&_eggs", "in n out": "in_n_out", "7 eleven": "7_eleven"}
# 提前编译短语匹配正则
phrase_regex = re.compile("|".join([r"\b{}\b".format(re.escape(phrase)) for phrase in phrases.keys()]))
# 提前编译数字清洗正则
num_regex = re.compile(r'\d+')
# 提前生成保留短语的集合,用于O(1)复杂度快速判断
phrase_values = set(phrases.values())

def pre_phrase_tokenize_processing(sentence):
    """
    辅助函数:在短语合并为下划线连接的单个token前清洗句子,作用于整句。
    移除连字符,以及除&之外的所有标点符号。
    """
    # 将所有连字符替换为空格,部分短语包含连字符,可后续合并为下划线连接的多词短语
    sentence = sentence.translate(str.maketrans('-', ' '))
    
    # 移除除&之外的所有标点符号,部分短语包含&符号
    remove_punct = string.punctuation.replace("&", "")
    sentence = sentence.translate(str.maketrans('', '', remove_punct))
    
    return sentence

def turn_phrases_into_tokens(sentence):
    """
    辅助函数:根据提供的短语字典,将句子中所有匹配的短语转换为下划线连接的单个token。
    """
    return phrase_regex.sub(lambda m: phrases[m.group(0)], sentence)

def tokenize(content: str, token_min_len=TOKEN_MIN_LEN, token_max_len=TOKEN_MAX_LEN, lower=True) -> List[str]:
    """重写wikicorpus.py中的原始tokenize方法
    对维基百科文本进行分词处理。
    """
    content = to_unicode(content, encoding='utf8', errors='ignore')
    if lower:
        content = content.lower()
    
    content = pre_phrase_tokenize_processing(content)
    content = turn_phrases_into_tokens(content)
    
    # 直接拆分token逐个处理,无额外解析开销
    res = []
    for token in content.split():
        # 如果是预设短语直接保留
        if token in phrase_values:
            if token_min_len <= len(token) <= token_max_len and not token.startswith('_'):
                res.append(token)
            continue
        # 非短语单词走清洗逻辑
        token = num_regex.sub('', token)
        token = token.translate(str.maketrans('', '', string.punctuation))
        if token and token_min_len <= len(token) <= token_max_len and not token.startswith('_'):
            res.append(token)
    return res

def make_corpus(in_f, out_f):
    """将维基百科xml dump文件转换为文本语料"""
    # 增加写入缓冲,减少IO开销
    with open(out_f, 'w', buffering=1024*1024, encoding='utf-8') as output:
        wiki = WikiCorpus(in_f, tokenizer_func=tokenize)
        i = 0
        for text in wiki.get_texts():
            output.write(' '.join(text) + '\n')
            i += 1
            if i % 1000 == 0:
                print(f'已处理{i}篇文章')
    print('处理完成!')

额外性能提升建议

  • 如果你的短语列表超过1000条,可以使用Aho-Corasick自动机算法做短语匹配,比正则的多模式匹配性能更高。
  • 可以使用多进程对处理逻辑做并行化,维基语料的单篇文章处理是独立的,多进程可以进一步提升处理速度。
  • 可以提前过滤掉维基语料中的重定向、消歧义页等非正文内容,减少不必要的处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 14:06:04