You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用Gensim快速加载指定词表的GloVe预训练词向量?

快速从GloVe文件提取指定词表的词向量

你的需求太常见了——面对动辄几十G的GloVe预训练文件,只需要小部分词的向量时,完全没必要硬啃整个文件。下面给你几个高效的实现方案,总有一款适合你:

方案1:优化你的逐行遍历代码(最易实现,速度飙升)

你原来的代码慢核心原因是列表的inremove操作都是O(n)复杂度,把词表转成集合就能把查找速度直接降到O(1),同时优化循环逻辑提前退出,效率提升非常明显:

import pandas as pd

def read_word_embedding_vector(target_words):
    # 把目标词表转成集合,大幅提升查找速度
    target_set = set(target_words)
    vectors = []
    
    # 用with语句自动管理文件,避免资源泄漏
    with open('glove.twitter.27B/glove.twitter.27B.200d.txt', 'r', encoding='utf-8') as f:
        for line in f:
            parts = line.strip().split()
            word = parts[0]
            if word in target_set:
                # 把词和向量转换为合适格式
                vectors.append([word] + [float(x) for x in parts[1:]])
                # 找到目标词就从集合移除,避免重复匹配(GloVe中每个词仅出现一次)
                target_set.remove(word)
                # 所有目标词都找到后直接终止循环,节省不必要的遍历
                if not target_set:
                    break
    
    # 转换为DataFrame返回,保持和你原代码一致的输出格式
    return pd.DataFrame(vectors).set_index(0).astype('float')

这个优化后的版本,处理几百个目标词的话,速度至少是你原代码的几十倍。

方案2:用Gensim实现按需加载(完美匹配你想要的load_word2vec_format风格)

Gensim本身没有直接支持加载指定词表的API,但我们可以通过「格式转换+手动构建KeyedVectors」的方式实现,得到的对象和原生load_word2vec_format加载的完全一样:

第一步:把GloVe转成Word2Vec格式(只需执行一次)

GloVe和Word2Vec的格式只差开头的「词数+维度」行,用Gensim自带工具就能快速转换:

from gensim.scripts.glove2word2vec import glove2word2vec

# 转换GloVe格式为Word2Vec格式
glove_input_file = 'glove.twitter.27B/glove.twitter.27B.200d.txt'
word2vec_output_file = 'glove.twitter.27B.200d.word2vec.txt'
glove2word2vec(glove_input_file, word2vec_output_file)

第二步:按需加载指定词的向量

转换完成后,我们创建一个空的KeyedVectors对象,只加载我们需要的词:

from gensim.models import KeyedVectors

def load_target_vectors(target_words, word2vec_path):
    # 初始化KeyedVectors,维度要和你的GloVe文件一致(这里是200)
    kv = KeyedVectors(vector_size=200)
    target_set = set(target_words)
    
    with open(word2vec_path, 'r', encoding='utf-8') as f:
        # 跳过第一行的词数+维度信息
        next(f)
        for line in f:
            parts = line.strip().split()
            word = parts[0]
            if word in target_set:
                vec = [float(x) for x in parts[1:]]
                kv.add_vector(word, vec)
                target_set.remove(word)
                # 目标词全部找到就提前退出
                if not target_set:
                    break
    return kv

这样得到的kv对象,完全支持Gensim的所有操作,比如kv['like']获取向量、kv.most_similar('Python')找相似词,完美符合你想要的使用体验。

方案3:内存映射加速读取(针对超大规模GloVe文件)

如果你的GloVe文件特别大(比如10G以上),可以用mmap把文件直接映射到内存,减少磁盘IO开销,进一步提升速度:

import mmap
import pandas as pd

def read_glove_with_mmap(target_words):
    target_set = set(target_words)
    vectors = []
    
    with open('glove.twitter.27B/glove.twitter.27B.200d.txt', 'r', encoding='utf-8') as f:
        # 内存映射文件,把文件内容直接加载到内存缓冲区
        with mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ) as mm:
            # 按行遍历内存映射的内容
            for line in iter(mm.readline, b''):
                line = line.decode('utf-8').strip()
                parts = line.split()
                word = parts[0]
                if word in target_set:
                    vectors.append([word] + [float(x) for x in parts[1:]])
                    target_set.remove(word)
                    if not target_set:
                        break
    return pd.DataFrame(vectors).set_index(0).astype('float')

总结

  • 不想折腾额外工具?方案1直接优化你的代码,几分钟就能搞定,速度提升显著
  • 想和Gensim生态无缝对接?方案2能让你得到和原生API一样的使用体验
  • 处理超大规模文件?试试方案3的内存映射方式

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

火山引擎 最新活动