spaCy 和 scikit-learn 向量化器
Posted
技术标签:
【中文标题】spaCy 和 scikit-learn 向量化器【英文标题】:spaCy and scikit-learn vectorizer 【发布时间】:2017-12-25 01:33:19 【问题描述】:我根据他们的example 使用 spaCy 为 scikit-learn 编写了一个引理分词器,它可以独立运行:
import spacy
from sklearn.feature_extraction.text import TfidfVectorizer
class LemmaTokenizer(object):
def __init__(self):
self.spacynlp = spacy.load('en')
def __call__(self, doc):
nlpdoc = self.spacynlp(doc)
nlpdoc = [token.lemma_ for token in nlpdoc if (len(token.lemma_) > 1) or (token.lemma_.isalnum()) ]
return nlpdoc
vect = TfidfVectorizer(tokenizer=LemmaTokenizer())
vect.fit(['Apples and oranges are tasty.'])
print(vect.vocabulary_)
### prints 'apple': 1, 'and': 0, 'tasty': 4, 'be': 2, 'orange': 3
但是,在GridSearchCV
中使用它会出错,下面是一个自包含的示例:
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
from sklearn.multiclass import OneVsRestClassifier
from sklearn.pipeline import Pipeline
from sklearn.grid_search import GridSearchCV
wordvect = TfidfVectorizer(analyzer='word', strip_accents='ascii', tokenizer=LemmaTokenizer())
classifier = OneVsRestClassifier(SVC(kernel='linear'))
pipeline = Pipeline([('vect', wordvect), ('classifier', classifier)])
parameters = 'vect__min_df': [1, 2], 'vect__max_df': [0.7, 0.8], 'classifier__estimator__C': [0.1, 1, 10]
gs_clf = GridSearchCV(pipeline, parameters, n_jobs=7, verbose=1)
from sklearn.datasets import fetch_20newsgroups
categories = ['comp.graphics', 'rec.sport.baseball']
newsgroups = fetch_20newsgroups(remove=('headers', 'footers', 'quotes'), shuffle=True, categories=categories)
X = newsgroups.data
y = newsgroups.target
gs_clf = gs_clf.fit(X, y)
### AttributeError: 'spacy.tokenizer.Tokenizer' object has no attribute '_prefix_re'
当我在分词器的构造函数之外加载 spacy 时没有出现错误,然后 GridSearchCV
运行:
spacynlp = spacy.load('en')
class LemmaTokenizer(object):
def __call__(self, doc):
nlpdoc = spacynlp(doc)
nlpdoc = [token.lemma_ for token in nlpdoc if (len(token.lemma_) > 1) or (token.lemma_.isalnum()) ]
return nlpdoc
但这意味着GridSearchCV
中的每个n_jobs
都将访问和调用同一个 spacynlp 对象,它在这些作业之间共享,这就留下了问题:
-
来自
spacy.load('en')
的 spacynlp 对象是否可以安全地用于 GridSearchCV 中的多个作业?
这是在 scikit-learn 的标记器中实现对 spacy 的调用的正确方法吗?
【问题讨论】:
【参考方案1】:为网格中的每个参数设置运行 Spacy 是在浪费时间。内存开销也很大。您应该通过 Spacy 运行一次所有数据并将其保存到磁盘,然后使用简化的矢量化器来读取预先确定的数据。查看TfidfVectorizer
的tokenizer
、analyser
和preprocessor
参数。有很多关于堆栈溢出的示例展示了如何构建自定义矢量化器。
【讨论】:
这些都是好点,而这很可能是该做的。但是,我最终希望将具有不同选项(例如 POS)的 spaCy 标记化作为超参数网格搜索的一部分,因此我提出了问题。 你也可以这样做。将您的数据存储为这样的字典列表:["token": "cats", "lemma": "cat", ...]
。这基本上就是 Spacy 句子的内容,转换为 JSON。编写一个管道步骤,将其作为输入,并有一个参数来输出一个标记或一个引理,然后你就有了——标记化是网格搜索的一部分。
“你在浪费时间”,“有很多例子”。这个答案并没有那么有用。
欢迎提出改进建议。编辑按钮在帖子底部
“有很多关于堆栈溢出的示例展示了如何构建自定义矢量化器”,至少链接到这些示例中的一个会很有帮助【参考方案2】:
基于 mbatchkarov 的帖子的 cmets,我尝试通过 Spacy 运行我在 pandas 系列中的所有文档进行标记化和词形还原,并首先将其保存到磁盘。
然后,我加载了词形化的spacy Doc
对象,为每个文档提取一个标记列表,并将其作为输入提供给由简化的TfidfVectorizer
和DecisionTreeClassifier
组成的管道。
我用GridSearchCV
运行pipeline
并提取最佳估计器和相应的参数。
看一个例子:
from sklearn import tree
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
import spacy
from spacy.tokens import DocBin
nlp = spacy.load("de_core_news_sm") # define your language model
# adjust attributes to your liking:
doc_bin = DocBin(attrs=["LEMMA", "ENT_IOB", "ENT_TYPE"], store_user_data=True)
for doc in nlp.pipe(df['articleDocument'].str.lower()):
doc_bin.add(doc)
# either save DocBin to a bytes object, or...
#bytes_data = doc_bin.to_bytes()
# save DocBin to a file on disc
file_name_spacy = 'output/preprocessed_documents.spacy'
doc_bin.to_disk(file_name_spacy)
#Load DocBin at later time or on different system from disc or bytes object
#doc_bin = DocBin().from_bytes(bytes_data)
doc_bin = DocBin().from_disk(file_name_spacy)
docs = list(doc_bin.get_docs(nlp.vocab))
print(len(docs))
tokenized_lemmatized_texts = [[token.lemma_ for token in doc
if not token.is_stop and not token.is_punct and not token.is_space and not token.like_url and not token.like_email]
for doc in docs]
# classifier to use
clf = tree.DecisionTreeClassifier()
# just some random target response
y = np.random.randint(2, size=len(docs))
vectorizer = TfidfVectorizer(ngram_range=(1, 1), lowercase=False, tokenizer=lambda x: x, max_features=3000)
pipeline = Pipeline([('vect', vectorizer), ('dectree', clf)])
parameters = 'dectree__max_depth':[4, 10]
gs_clf = GridSearchCV(pipeline, parameters, n_jobs=-1, verbose=1, cv=5)
gs_clf.fit(tokenized_lemmatized_texts, y)
print(gs_clf.best_estimator_.get_params()['dectree'])
一些更有用的资源:
model and language selection spacy DocBin class spacy Multiprocessing nlp pipe spacy Serializing Doc objects efficiently spacy Token class spacy GridSearchCV scikit-learn Pipeline scikit-learn【讨论】:
以上是关于spaCy 和 scikit-learn 向量化器的主要内容,如果未能解决你的问题,请参考以下文章