序列化 spaCy Docs 集合的推荐方法是什么?

Bil*_*ill 5 python spacy

我正在处理大量需要注释并保存到磁盘的短文本。理想情况下,我想将它们保存/加载为 spaCyDoc对象。显然,我不想多次保存LanguageVocab对象(但很高兴为一组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)

Sam*_* H. 5

从 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)


gda*_*ras 4

由于您使用相同的 nlp 对象,因此 Vocab 可以在所有不同的 doc 对象中使用,因此只需序列化一次。

我的序列化方法是:

  • 序列化共享 Vocab
  • 使用 to_disk 方法将每个 doc 对象序列化到 docs 文件夹中的不同文件中

要取回您的文档对象:

  • 反序列化共享 Vocab
  • 反序列化 docs 文件夹中的每个 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)

我认为这是尽可能有效的空间利用。

希望能帮助到你!