多个大型阵列的内存问题

时间:2018-08-12 23:06:28

标签: python arrays memory

我正在尝试对超过1000个(100, 100, 1000)数组进行一些计算。但是我可以想象,在内存用完之前,不需要花费超过150-200个数组,并且所有操作都会失败(至少在我当前的代码中)。

这是我目前拥有的:

import numpy as np

toxicity_data_path = open("data/toxicity.txt", "r")
toxicity_data = np.array(toxicity_data_path.read().split("\n"), dtype=int)

patients = range(1, 1000, 1)

上面只是每个阵列的1和0(表示是否有毒性)的列表(在这种情况下,一个阵列是一名患者的数据)。因此,在这种情况下,大约有1000名患者。

然后我从上面的代码中创建了两个列表,所以我有一个列表中有毒性的患者,而另一个列表中没有毒性的患者。

patients_no_tox = [i for i, e in enumerate(toxicity_data.astype(np.str)) if e in set("0")]
patients_with_tox = [i for i, e in enumerate(toxicity_data.astype(np.str)) if e in set("1")]

然后我编写此函数,该函数为每个患者获取一个已经保存到磁盘的数组((100, 100, 1000)),然后在每个数组上删除一些索引(也从保存的文件中加载),以后无法使用,或者只需要删除即可。因此,这样做至关重要。结果是所有患者及其3D数据阵列的最终列表。当列表理解中使用该函数时,这里就是开始消耗内存的地方。

def log_likely_list(patient, remove_index_list):
    array_data = np.load("data/{}/array.npy".format(patient)).ravel()
    return np.delete(array_data, remove_index_list)


remove_index_list = np.load("data/remove_index_list.npy")
final_list = [log_likely_list(patient, remove_index_list) for patient in patients]

下一步是创建两个计算所需的列表。我列出了所有患者的最终名单,并分别删除了有毒性或无毒性的患者。

patients_no_tox_list = np.column_stack(np.delete(final_list, patients_with_tox, 0))
patients_with_tox_list = np.column_stack(np.delete(final_list, patients_no_tox, 0))

难题的最后一部分是在以下方程式中使用这两个列表,在该方程式中,我将非毒素列表放入方程的右侧,而在左边放置了毒素。然后针对所有患者的3D数组中的每个索引,对所有1000位患者进行汇总,即每个3D数组/患者中的索引相同,然后得出的值几乎都是很大的。

log_likely = np.sum(np.log(patients_with_tox_list), axis=1) +
             np.sum(np.log(1 - patients_no_tox_list), axis=1)

如上所述,我的问题是,当我达到150-200(在patients范围内)时,我的内存被使用,并且它关闭了。 我显然试图将内容保存在磁盘上以进行加载(这就是为什么我要加载这么多文件的原因),但这并没有太大帮助。我在想也许我可以一次进入一个数组,然后进入log_likely函数,但是最后,在求和之前,我可能只拥有一个同样大的数组,而且,计算量可能很多如果我不能使用numpy sum等功能,速度会变慢。

那么我有什么办法可以对此进行优化/改进,还是唯一的办法来获得更多的RAM?

1 个答案:

答案 0 :(得分:1)

每次使用列表推导时,都会在内存中创建数据的新副本。所以这行:

final_list = [log_likely_list(patient, remove_index_list) for patient in patients]

包含所有1000位患者的完整数据!

更好的选择是利用生成器表达式,该表达式一次处理一项。要生成一个生成器,请用括号而不是括号将for...in...:表达式括起来。看起来可能像这样:

with_tox_data = (log_likely_list(patient, remove_index_list) for patient in patients_with_tox)
with_tox_log = (np.log(data, axis=1) for data in with_tox_data)

no_tox_data = (log_likely_list(patient, remove_index_list) for patient in patients_no_tox)
no_tox_log = (np.log(1 - data, axis=1) for data in no_tox_data)

final_data = itertools.chain(with_tox_log, no_tox_log)

请注意,实际上尚未执行任何计算:在您迭代生成器之前,生成器不会执行任何操作。在这种情况下,is to use reduce:

汇总所有结果的最快方法
log_likely = functools.reduce(np.add, final_data)