大型数据集的Python内存错误

时间:2013-05-21 19:36:55

标签: python memory memory-management python-2.7 machine-learning

我想生成一个“包词”矩阵,其中包含文档中包含相应计数的文档。为了做到这一点,我运行下面的代码来初始化单词矩阵包。不幸的是,在我阅读文档的行中的x个文档之后,我收到了内存错误。有没有更好的方法来做到这一点,以便我可以避免内存错误?请注意,我想处理大量的文件~2000.000只有8 Gb的RAM。

def __init__(self, paths, words_count, normalize_matrix = False ,trainingset_size = None, validation_set_words_list = None):
    '''
    Open all documents from the given path.
    Initialize the variables needed in order
    to construct the word matrix.

    Parameters
    ----------
    paths: paths to the documents.
    words_count: number of words in the bag of words.
    trainingset_size: the proportion of the data that should be set to the training set.
    validation_set_words_list: the attributes for validation.
    '''

    print '################ Data Processing Started ################'

    self.max_words_matrix = words_count

    print '________________ Reading Docs From File System ________________'
    timer = time()
    for folder in paths:
        self.class_names.append(folder.split('/')[len(folder.split('/'))-1])
        print '____ dataprocessing for category '+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()
                # Append a filtered version of the document to the document list.
                self.docs_list.append(self.__filter__(d))
                # Append the name of the document to the list containing document names.
                self.docs_names.append(doc)
                # Increase the class indices counter.
                self.class_indices.append(len(self.class_names)-1)

            print 'Processed '+str(count)+' of '+str(length)+' in category '+folder
            count += 1

1 个答案:

答案 0 :(得分:4)

你要求的是不可能的。此外,Python不会自动获得您期望从BoW获得的空间优势。另外,我认为你首先做的关键是错误的。我们采取相反的顺序。


无论你在这条线上做什么:

self.docs_list.append(self.__filter__(d))

......可能是错的。

您要为每个文档存储的所有内容都是计数向量。为了获得该计数向量,您需要附加所有单词的单个dict。除非__filter__正在修改隐藏的字典,并返回一个向量,否则它不会做正确的事情。


BoW模型节省的主要空间来自于不必为每个文档存储字符串键的副本,以及能够存储简单的int数组而不是花式哈希表。但是整数对象几乎和(短)字符串对象一样大,并且没有办法预测或保证何时获得新的整数或字符串以及对现有的整数或字符串的额外引用。所以,真的,你获得的唯一好处是1/hash_fullness;如果您想要任何其他优势,您需要array.arraynumpy.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] += 1
self.doc_vectors.append(a)

但是这个仍然是不够的。除非您拥有1K个唯一单词的顺序,否则您无法将所有这些计数都记在内存中。

例如,如果你有5000个唯一的单词,你就有2M个数组,每个数组都有5000个2字节数,所以最紧凑的表示形式需要20GB。

由于大多数文档都没有大多数单词,因此使用稀疏数组(或单个2D稀疏数组)可以获得一些好处,但是只能获得很多好处。并且,即使事情恰好以这样的方式排序,你得到绝对完美的RLE压缩,如果每个文档的平均单词数量大约为1K,那么你仍然会耗尽内存。


因此,您只需无法将所有文档向量存储在内存中。

如果你可以迭代地处理它们而不是一次性处理它们,那就是明显的答案。

如果没有,您将不得不将它们分页到磁盘(无论是显式的,还是使用PyTables或数据库或其他东西)。