python - 多个大型数组的内存问题

标签 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 数组中的每个单独索引(即每个 3D 数组/患者中的相同索引)对所有 1000 名患者进行求和,然后我最终得到一个很大的值列表。

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 左右(在患者范围内)时,我的内存就会被使用,然后就会关闭。 显然,我尝试将要加载的内容保存在磁盘上(这就是我加载这么多文件的原因),但这对我没有多大帮助。我想也许我可以一次进入一个数组并进入 log_likely 函数,但最终,在求和之前,我可能只会有一个同样大的数组,另外,计算可能会如果我不能使用 numpy sum 功能等,速度会慢很多。

那么有什么方法可以优化/改进这一点,或者是唯一的方法,但需要更多的内存?

最佳答案

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

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)

关于python - 多个大型数组的内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51813567/

相关文章:

python - 延迟调用函数

python - 从另一个类调用列表实例

python - 在 Python 中从一对或名称映射到一个值

csv - Clojure - 解析小型 CSV 文件的内存使用情况

python - 在具有不同大小和相似匹配的字符串中查找完全匹配

Python:子进程调用无法识别 * 通配符?

arrays - 将数组的数组作为参数传递给函数

php - 合并关联数组时计算空白

无法仅释放一个动态分配的元素

c - 在 chars.exe : 0xC0000005: Access violation reading location 0x00000004 中的 0x011414CE 抛出异常