我想生成一个包含文档及其对应词频的“词袋”矩阵。为了实现这一点,我运行了下面的代码来初始化词袋矩阵。不幸的是,在读取文档的那一行处理了x数量的文档后,我收到了内存错误。有什么更好的方法可以避免这种内存错误吗?请注意,我需要处理大约200万个文档,而我的内存只有8GB。
def __init__(self, paths, words_count, normalize_matrix = False ,trainingset_size = None, validation_set_words_list = None): ''' 打开给定路径中的所有文档。 初始化构建词矩阵所需的变量。 参数 ---------- paths: 文档的路径。 words_count: 词袋中的词数。 trainingset_size: 数据中应设置为训练集的比例。 validation_set_words_list: 用于验证的属性。 ''' print '################ 数据处理开始 ################' self.max_words_matrix = words_count print '________________ 从文件系统读取文档 ________________' timer = time() for folder in paths: self.class_names.append(folder.split('/')[len(folder.split('/'))-1]) print '____ 类别 '+folder+' 的数据处理' if trainingset_size == None: docs = os.listdir(folder) elif not trainingset_size == None and validation_set_words_list == None: docs = os.listdir(folder)[:int(len(os.listdir(folder))*trainingset_size-1)] else: docs = os.listdir(folder)[int(len(os.listdir(folder))*trainingset_size+1):] count = 1 length = len(docs) for doc in docs: if doc.endswith('.txt'): d = open(folder+'/'+doc).read() # 将文档的过滤版本添加到文档列表中。 self.docs_list.append(self.__filter__(d)) # 将文档名称添加到包含文档名称的列表中。 self.docs_names.append(doc) # 增加类别索引计数器。 self.class_indices.append(len(self.class_names)-1) print '已处理 '+str(count)+' 个,共 '+str(length)+' 个,类别 '+folder count += 1
回答:
你所要求的做不到。此外,Python不会自动获得你期望的词袋模型的空间优势。而且,我认为你从一开始就做错了关键部分。我们按相反的顺序来讨论这些问题。
你在这行做的任何事情:
self.docs_list.append(self.__filter__(d))
… 很可能是错误的。
你想要为每个文档存储的只是一个计数向量。为了得到这个计数向量,你需要向一个包含所有已见单词的单一字典中添加内容。除非__filter__
是在修改一个隐藏的字典并返回一个向量,否则它没有做正确的事情。
词袋模型的主要空间节省来自于不需要为每个文档存储字符串键的副本,以及能够存储一个简单的整数数组而不是一个复杂的哈希表。但是,一个整数对象几乎和一个(短)字符串对象一样大,而且没有办法预测或保证何时会得到新的整数或字符串与现有对象的额外引用。因此,实际上,你唯一获得的优势是1/hash_fullness
;如果你想要其他任何优势,你需要像array.array
或numpy.ndarray
这样的东西。
例如:
a = np.zeros(len(self.word_dict), dtype='i2')for word in split_into_words(d): try: idx = self.word_dict[word] except KeyError: idx = len(self.word_dict) self.word_dict[word] = idx np.resize(a, idx+1) a[idx] = 1 else: a[idx] += 1self.doc_vectors.append(a)
但这仍然不够。除非你有大约1000个独特的词,否则你无法将所有这些计数装入内存中。
例如,如果你有5000个独特的词,你就有200万个数组,每个数组有5000个2字节的计数,因此最紧凑的表示将需要20GB。
由于大多数文档不会包含大多数词,你可以通过使用稀疏数组(或单个2D稀疏数组)获得一些好处,但好处是有限的。而且,即使事情的顺序恰好使得你获得了绝对完美的RLE压缩,如果每个文档的平均独特词数大约是1000,你仍然会耗尽内存。
因此,你根本无法将所有文档向量存储在内存中。
如果你可以迭代处理它们而不是一次性处理所有,这是显而易见的答案。
如果不能,你将不得不将它们分页进出磁盘(无论是显式地,还是通过使用PyTables或数据库或其他东西)。