我想在Spacy中使用经过预训练的word2vec模型,通过以下方式对标题进行编码:(1)将单词映射到其矢量嵌入,以及(2)执行单词嵌入的均值。
为此,我使用以下代码:
import spacy
nlp = spacy.load('myspacy.bioword2vec.model')
sentence = "I love Stack Overflow butitsalsodistractive"
avg_vector = nlp(sentence).vector
其中nlp(sentence).vector
(1)用空格分割将我的句子标记化,(2)根据提供的字典对每个单词进行向量化,(3)对句子中的单词向量求平均以提供单个输出向量。那又快又酷。
但是,在此过程中,语音(OOV)术语被映射到n维0向量,这会影响所得平均值。相反,我希望在执行平均值时忽略OOV项。在我的示例中,“ butitsalsodistractive ”是字典中不存在的唯一术语,因此我想使用nlp("I love Stack Overflow butitsalsodistractive").vector = nlp("I love Stack Overflow").vector
。
我已经可以通过后处理步骤做到这一点(请参见下面的代码),但是对于我的目的而言,这变得太慢了,因此我想知道是否有一种方法可以告诉nlp
管道事先忽略OOV术语?因此,在调用nlp(sentence).vector
时,在计算均值时不包括OOV项向量
import numpy as np
avg_vector = np.asarray([word.vector for word in nlp(sentence) if word.has_vector]).mean(axis=0)
尝试的方法
在两种情况下,documents
都是一个包含200个字符串元素(每个单词≈400个单词)的列表。
import spacy
import time
nlp = spacy.load('myspacy.bioword2vec.model')
times = []
for i in range(0, 100):
init = time.time()
documents_vec = [document.vector for document in list(nlp.pipe(documents))]
fin = time.time()
times.append(fin-init)
print("Mean time after 100 rounds:", sum(times)/len(times), "s")
# Mean time after 100 rounds: 2.0850741124153136 s
r_vec = np.random.rand(200) # Random vector for empty text
# Define function to obtain average vector given a document
def get_vector(text):
vectors = np.asarray([word.vector for word in nlp(text) if word.has_vector])
if vectors.size == 0:
# Case in which none of the words in text were in vocabulary
avg_vector = r_vec
else:
avg_vector = vectors.mean(axis=0)
return avg_vector
times = []
for i in range(0, 100):
init = time.time()
documents_vec = [get_vector(document) for document in documents]
fin = time.time()
times.append(fin-init)
print("Mean time after 100 rounds:", sum(times)/len(times), "s")
# Mean time after 100 rounds: 2.4214172649383543 s
在此示例中,矢量化200个文档的平均时差时间为0.34s。但是,当处理200M文档时,这变得很关键。我知道第二种方法需要一个额外的'if'条件来处理充满OOV术语的文档,这可能会稍微增加计算时间。另外,在第一种情况下,我可以使用nlp.pipe(documents)
一次性处理所有文档,我认为必须优化该过程。
我总是可以寻找额外的计算资源来应用第二段代码,但是我想知道是否有任何方法可以使用nlp.pipe(documents)
来忽略输出中的OOV术语。任何建议都将非常受欢迎。
答案 0 :(得分:1)
请参见Spacy的作者this post,其中说:
该Doc对象具有不可变的文本,但是使用所需令牌子集创建一个新的Doc对象应该非常容易并且非常有效。
尝试以下示例:
import spacy
nlp = spacy.load('en_core_web_md')
import numpy as np
sentence = "I love Stack Overflow butitsalsodistractive"
print(sentence)
tokens = nlp(sentence)
print([t.text for t in tokens])
cleanText = " ".join([token.text for token in tokens if token.has_vector])
print(clean)
tokensClean = nlp(cleanText)
print([t.text for t in tokensClean])
np.array_equal(tokens.vector, tokensClean.vector)
#False
如果您想加快速度,请在不使用时禁用流水线组件(例如NER,依赖项解析等)。