如何用Gensim快速加载指定词表的GloVe预训练词向量?
快速从GloVe文件提取指定词表的词向量
你的需求太常见了——面对动辄几十G的GloVe预训练文件,只需要小部分词的向量时,完全没必要硬啃整个文件。下面给你几个高效的实现方案,总有一款适合你:
方案1:优化你的逐行遍历代码(最易实现,速度飙升)
你原来的代码慢核心原因是列表的in和remove操作都是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




