目前,我正在尝试与gensim一起使用dask进行NLP文档计算,并且在将我的语料库转换为“ TaggedDocument”时遇到了问题。
因为我尝试了许多不同的方法来解决这个问题,所以我将列出自己的尝试。
每次处理此问题的尝试都会遇到些微的麻烦。
df.info()
<class 'dask.dataframe.core.DataFrame'>
Columns: 5 entries, claim_no to litigation
dtypes: object(2), int64(3)
claim_no claim_txt I CL ICC lit
0 8697278-17 battery comprising interior battery active ele... 106 2 0
>>tagged_document[0]
>>TaggedDocument(words=['battery', 'comprising', 'interior', 'battery', 'active', 'elements', 'battery', 'cell', 'casing', 'said', 'cell', 'casing', 'comprising', 'first', 'casing', 'element', 'first', 'contact', 'surface', 'second', 'casing', 'element', 'second', 'contact', 'surface', 'wherein', 'assembled', 'position', 'first', 'second', 'contact', 'surfaces', 'contact', 'first', 'second', 'casing', 'elements', 'encase', 'active', 'materials', 'battery', 'cell', 'interior', 'space', 'wherein', 'least', 'one', 'gas', 'tight', 'seal', 'layer', 'arranged', 'first', 'second', 'contact', 'surfaces', 'seal', 'interior', 'space', 'characterized', 'one', 'first', 'second', 'contact', 'surfaces', 'comprises', 'electrically', 'insulating', 'void', 'volume', 'layer', 'first', 'second', 'contact', 'surfaces', 'comprises', 'formable', 'material', 'layer', 'fills', 'voids', 'surface', 'void', 'volume', 'layer', 'hermetically', 'assembled', 'position', 'form', 'seal', 'layer'], tags=['8697278-17'])
>>len(tagged_document) == len(df['claim_txt'])
def read_corpus_tag_sub(df,corp='claim_txt',tags=['claim_no']):
for i, line in enumerate(df[corp]):
yield gensim.models.doc2vec.TaggedDocument(gensim.utils.simple_preprocess(line), (list(df.loc[i,tags].values)))
tagged_document = df.map_partitions(read_corpus_tag_sub,meta=TaggedDocument)
tagged_document = tagged_document.compute()
TypeError:无法序列化类型生成器的对象。
我仍然无法使用发电机来解决这个问题。解决这个问题的方法非常棒!因为这对于普通的熊猫来说效果很好。
def read_corpus_tag_sub(df,corp='claim_txt',tags=['claim_no']):
for i, line in enumerate(df[corp]):
return gensim.models.doc2vec.TaggedDocument(gensim.utils.simple_preprocess(line), (list(df.loc[i,tags].values)))
tagged_document = df.map_partitions(read_corpus_tag_sub,meta=TaggedDocument)
tagged_document = tagged_document.compute()
该函数有点笨,因为该函数不会迭代(我知道),但是会提供所需的格式,但只会返回每个分区的第一行。
def read_corpus_tag_sub(df,corp='claim_txt',tags=['claim_no']):
tagged_list = []
for i, line in enumerate(df[corp]):
tagged = gensim.models.doc2vec.TaggedDocument(gensim.utils.simple_preprocess(line), (list(df.loc[i,tags].values)))
tagged_list.append(tagged)
return tagged_list
正如我所知道的,在循环外重构返回值时,此函数挂起将在dask客户端中建立内存,并且我的CPU利用率达到100%,但未计算任何任务。请记住,我以相同的方式调用该函数。
def tag_corp(corp,tag):
return gensim.models.doc2vec.TaggedDocument(gensim.utils.simple_preprocess(corp), ([tag]))
tagged_document = [tag_corp(x,y) for x,y in list(zip(df_smple['claim_txt'],df_smple['claim_no']))]
List comp我还没有时间测试这个解决方案
tagged_document = list(read_corpus_tag_sub(df))
此解决方案将持续几个小时。但是,完成后,我没有足够的内存来处理这个事情。
我现在感觉超级迷路了。这是我看过的线程列表。我承认自己真的很陌生,我花了这么多时间,感觉好像在做一个傻瓜。
答案 0 :(得分:1)
我不熟悉Dask API /限制,但通常:
如果您可以将数据迭代为(单词,标签)元组–甚至忽略Doc2Vec
/ TaggedDocument
步骤–那么Dask端将已处理,并转换这些元组TaggedDocument
实例应该不重要
通常,对于大型数据集,您不想(并且可能没有足够的RAM来)将完整数据集实例化为内存中的list
–因此,涉及{{1 }}或list()
可能在某种程度上可以正常工作,但是耗尽了本地内存(导致严重的交换)和/或只是没有达到数据的结尾。
大型数据集的首选方法是创建一个可迭代的对象,该对象每次被要求对数据进行迭代(因为.append()
训练将需要多次通过)可以依次提供每个项目–但切勿将整个数据集读入内存中的对象。
关于此模式的一个不错的博客文章是:Data streaming in Python: generators, iterators, iterables
鉴于您显示的代码,我怀疑适合您的方法可能是:
Doc2Vec
答案 1 :(得分:1)
对,所以您很接近这段代码
def read_corpus_tag_sub(df,corp='claim_txt',tags=['claim_no']):
for i, line in enumerate(df[corp]):
yield gensim.models.doc2vec.TaggedDocument(gensim.utils.simple_preprocess(line), (list(df.loc[i,tags].values)))
tagged_document = df.map_partitions(read_corpus_tag_sub,meta=TaggedDocument)
但是正如您所见,生成发电机对Dask并不是很有帮助。相反,您可以让函数返回一个序列
def myfunc(df, *args, **kwargs):
output = []
for i, line in enumerate(df["my_series"])
result = ...
output.append([])
return pd.Series(output)
或者,您可能只使用df.apply
方法,该方法采用了将单行转换为单行的函数。
您可能还想切换到Dask Bag,它比Pandas / Dask DataFrame更自然地处理列表和生成器之类的东西。