我正在处理大量需要注释并保存到磁盘的短文本。理想情况下,我想将它们保存/加载为 spaCyDoc对象。显然,我不想多次保存Language或Vocab对象(但很高兴为一组Docs保存/加载一次 )。
该Doc对象有一个to_disk方法和一个to_bytes方法,但我并不清楚如何将一堆文档保存到同一个文件中。有没有首选的方法来做到这一点?我正在寻找尽可能节省空间的东西。
目前我正在这样做,我对此不太满意:
def serialize_docs(docs):
"""
Writes spaCy Doc objects to a newline-delimited string that can be used to load them later,
given the same Vocab object that was used to create them.
"""
return '\n'.join([codecs.encode(doc.to_bytes(), 'hex') for doc in docs])
def write_docs(filename, docs):
"""
Writes spaCy Doc objects to a file.
"""
serialized_docs = seralize_docs(docs)
with open(filename, 'w') as f:
f.write(serialized_docs)
Run Code Online (Sandbox Code Playgroud)
从 Spacy 2.2 开始,正确的答案是使用DocBin。
正如Spacy 文档现在所说,
如果您正在处理大量数据,您可能需要在机器之间传递分析,要么使用 Dask 或 Spark 之类的东西,要么甚至只是将工作保存到磁盘。通常,为此使用 Doc.to_array 功能就足够了,只需序列化 numpy 数组 - 但有时您需要一种更通用的方法来保存和恢复 Doc 对象。
DocBin 类可以轻松地将一组 Doc 对象序列化和反序列化在一起,并且比在每个单独的 Doc 对象上调用 Doc.to_bytes 更有效。您还可以控制保存哪些数据,并且可以将托盘合并在一起以便于进行映射/简化式处理。
例子
import spacy
from spacy.tokens import DocBin
doc_bin = DocBin(attrs=["LEMMA", "ENT_IOB", "ENT_TYPE"], store_user_data=True)
texts = ["Some text", "Lots of texts...", "..."]
nlp = spacy.load("en_core_web_sm")
for doc in nlp.pipe(texts):
doc_bin.add(doc)
bytes_data = doc_bin.to_bytes()
# Deserialize later, e.g. in a new process
nlp = spacy.blank("en")
doc_bin = DocBin().from_bytes(bytes_data)
docs = list(doc_bin.get_docs(nlp.vocab))
Run Code Online (Sandbox Code Playgroud)
由于您使用相同的 nlp 对象,因此 Vocab 可以在所有不同的 doc 对象中使用,因此只需序列化一次。
我的序列化方法是:
要取回您的文档对象:
以下代码应该可以工作:
import spacy
import glob
import os
nlp = spacy.load('en_core_web_sm')
texts = ["Hello friend", "how is your day?", "I wish you all the best"]
docs = [nlp(text) for text in texts]
''' Serialization '''
# Serialize vocab
nlp.vocab.to_disk('vocab/vocab.txt')
# Serialize docs
for i, doc in enumerate(docs):
doc.to_disk('docs/{}.txt'.format(i))
''' Deserialization '''
docs = []
# deserialize vocab - common for all docs
nlp_vocab = spacy.vocab.Vocab().from_disk('vocab/vocab.txt')
# deserialize docs
path = os.path.join('docs', '*.txt')
files = glob.iglob(path)
for file in files:
docs.append(spacy.tokens.Doc(nlp_vocab).from_disk(file))
Run Code Online (Sandbox Code Playgroud)
我认为这是尽可能有效的空间利用。
希望能帮助到你!