如何在短句的大型数据集中有效地使用 spacy?
How to use spacy in large dataset with short sentences efficiently?
我选择 spacy 来处理各种文本,因为与 nltk 相比,它的词形还原性能更好。但是当我处理数百万短文本时,它总是消耗掉我所有的内存(32G)并崩溃。没有它,只需几分钟,就会消耗不到 10G 内存。
这个方法的使用有问题吗?有没有更好的解决方案来提高性能?谢谢!
def tokenizer(text):
try:
tokens = [ word for sent in sent_tokenize(text) for word in word_tokenize(sent)]
tokens = list(filter(lambda t: t.lower() not in stop_words, tokens))
tokens = list(filter(lambda t: t not in punctuation, tokens))
tokens = list(filter(lambda t: len(t) > 4, tokens))
filtered_tokens = []
for token in tokens:
if re.search('[a-zA-Z]', token):
filtered_tokens.append(token)
spacy_parsed = nlp(' '.join(filtered_tokens))
filtered_tokens = [token.lemma_ for token in spacy_parsed]
return filtered_tokens
except Exception as e:
raise e
Dask 并行计算
ddata = dd.from_pandas(res, npartitions=50)
def dask_tokenizer(df):
df['text_token'] = df['text'].map(tokenizer)
return df
%time res_final = ddata.map_partitions(dask_tokenizer).compute(get=get)
关于 spaCy 的信息
spaCy version 2.0.5
Location /opt/conda/lib/python3.6/site-packages/spacy
Platform Linux-4.4.0-103-generic-x86_64-with-debian-stretch-sid
Python version 3.6.3
Models en, en_default
您应该在 解析后过滤掉标记 。这样,经过训练的模型将提供更好的标记(除非它是在以类似方式过滤的文本上训练的,这是不太可能的)。
此外,之后的过滤使得使用 nlp.pipe
成为可能,这被认为是快速的。请参阅 http://spacy.io/usage/spacy-101#lightning-tour-multi-threaded 中的 nlp.pipe
示例。
您可以在 spacy 中使用多线程来创建快速标记化和数据摄取管道。
使用 nlp.pipe
方法重写您的代码块和功能看起来像这样:
import spacy
nlp = spacy.load('en')
docs = df['text'].tolist()
def token_filter(token):
return not (token.is_punct | token.is_space | token.is_stop | len(token.text) <= 4)
filtered_tokens = []
for doc in nlp.pipe(docs):
tokens = [token.lemma_ for token in doc if token_filter(token)]
filtered_tokens.append(tokens)
这种方式将所有过滤都放入 token_filter
函数中,该函数接受一个 spacy 标记和 returns True
只有当它不是标点符号时,space、一个停用词和 4 个或更少的字符。然后,在传递每个文档中的每个标记时使用此函数,只有当它满足所有这些条件时,它才会 return 引理。然后,filtered_tokens
是您的标记化文档列表。
自定义此管道的一些有用参考资料是:
本回答基于pmbaumgartner的回答;谢谢 pmbaumgartner。我刚刚添加了 postags 来过滤词汇(某些文本分析需要):
allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV'] # or any other types
def token_filter(token):
return (token.pos_ in allowed_postags) & (not (token.is_punct | token.is_space |
token.is_stop | len(token.text) <= 2))
我选择 spacy 来处理各种文本,因为与 nltk 相比,它的词形还原性能更好。但是当我处理数百万短文本时,它总是消耗掉我所有的内存(32G)并崩溃。没有它,只需几分钟,就会消耗不到 10G 内存。
这个方法的使用有问题吗?有没有更好的解决方案来提高性能?谢谢!
def tokenizer(text):
try:
tokens = [ word for sent in sent_tokenize(text) for word in word_tokenize(sent)]
tokens = list(filter(lambda t: t.lower() not in stop_words, tokens))
tokens = list(filter(lambda t: t not in punctuation, tokens))
tokens = list(filter(lambda t: len(t) > 4, tokens))
filtered_tokens = []
for token in tokens:
if re.search('[a-zA-Z]', token):
filtered_tokens.append(token)
spacy_parsed = nlp(' '.join(filtered_tokens))
filtered_tokens = [token.lemma_ for token in spacy_parsed]
return filtered_tokens
except Exception as e:
raise e
Dask 并行计算
ddata = dd.from_pandas(res, npartitions=50)
def dask_tokenizer(df):
df['text_token'] = df['text'].map(tokenizer)
return df
%time res_final = ddata.map_partitions(dask_tokenizer).compute(get=get)
关于 spaCy 的信息
spaCy version 2.0.5
Location /opt/conda/lib/python3.6/site-packages/spacy
Platform Linux-4.4.0-103-generic-x86_64-with-debian-stretch-sid
Python version 3.6.3
Models en, en_default
您应该在 解析后过滤掉标记 。这样,经过训练的模型将提供更好的标记(除非它是在以类似方式过滤的文本上训练的,这是不太可能的)。
此外,之后的过滤使得使用 nlp.pipe
成为可能,这被认为是快速的。请参阅 http://spacy.io/usage/spacy-101#lightning-tour-multi-threaded 中的 nlp.pipe
示例。
您可以在 spacy 中使用多线程来创建快速标记化和数据摄取管道。
使用 nlp.pipe
方法重写您的代码块和功能看起来像这样:
import spacy
nlp = spacy.load('en')
docs = df['text'].tolist()
def token_filter(token):
return not (token.is_punct | token.is_space | token.is_stop | len(token.text) <= 4)
filtered_tokens = []
for doc in nlp.pipe(docs):
tokens = [token.lemma_ for token in doc if token_filter(token)]
filtered_tokens.append(tokens)
这种方式将所有过滤都放入 token_filter
函数中,该函数接受一个 spacy 标记和 returns True
只有当它不是标点符号时,space、一个停用词和 4 个或更少的字符。然后,在传递每个文档中的每个标记时使用此函数,只有当它满足所有这些条件时,它才会 return 引理。然后,filtered_tokens
是您的标记化文档列表。
自定义此管道的一些有用参考资料是:
本回答基于pmbaumgartner的回答;谢谢 pmbaumgartner。我刚刚添加了 postags 来过滤词汇(某些文本分析需要):
allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV'] # or any other types
def token_filter(token):
return (token.pos_ in allowed_postags) & (not (token.is_punct | token.is_space |
token.is_stop | len(token.text) <= 2))