【发布时间】:2015-09-30 08:05:06
【问题描述】:
我需要使用 numpy 对一个非常大的基因组数据集进行排序。我有一个包含 26 亿个浮点数的数组,维度 = (868940742, 3),一旦加载并坐在那里,它会在我的机器上占用大约 20GB 的内存。我有一台 2015 年初的 13' MacBook Pro,配备 16GB 内存、500GB 固态硬盘和 3.1 GHz 英特尔 i7 处理器。只是将数组加载到虚拟内存中,但不会导致我的机器受到影响,或者我必须停止我正在做的所有其他事情。
我从 22 个较小的 (N, 2) 子数组逐步构建这个非常大的数组。
函数FUN_1 使用我称之为sub_arr 的22 个子数组中的每一个生成2 个新的(N, 1) 数组。
FUN_1 的第一个输出是通过在数组 b = array([X, F(X)]) 上插入来自 sub_arr[:,0] 的值生成的,第二个输出是通过使用数组 r = array([X, BIN(X)]) 将 sub_arr[:, 0] 放入 bin 中生成的。我将这些输出分别称为b_arr 和rate_arr。该函数返回一个由(N, 1) 数组组成的三元组:
import numpy as np
def FUN_1(sub_arr):
"""interpolate b values and rates based on position in sub_arr"""
b = np.load(bfile)
r = np.load(rfile)
b_arr = np.interp(sub_arr[:,0], b[:,0], b[:,1])
rate_arr = np.searchsorted(r[:,0], sub_arr[:,0]) # HUGE efficiency gain over np.digitize...
return r[rate_r, 1], b_arr, sub_arr[:,1]
我在 for 循环中调用该函数 22 次,并用值填充一个预分配的零数组 full_arr = numpy.zeros([868940742, 3]):
full_arr[:,0], full_arr[:,1], full_arr[:,2] = FUN_1
在这一步节省内存方面,我认为这是我能做的最好的,但我愿意接受建议。无论哪种方式,我都没有遇到问题,而且只需要大约 2 分钟。
这里是排序例程(有两个连续的排序)
for idx in range(2):
sort_idx = numpy.argsort(full_arr[:,idx])
full_arr = full_arr[sort_idx]
# ...
# <additional processing, return small (1000, 3) array of stats>
现在这种方法一直在工作,尽管速度很慢(大约需要 10 分钟)。然而,我最近开始在FUN_1 中使用更大、更精细的[X, F(X)] 值的分辨率表作为上述插值步骤,返回b_arr,现在SORT 真的变慢了,尽管其他一切都保持不变。
有趣的是,我什至没有在排序滞后的那一步对插值进行排序。以下是不同插值文件的一些 sn-ps - 在每种情况下,较小的文件大约小 30%,并且在第二列中的值更加统一;较慢的具有更高的分辨率和更多的独特值,因此插值的结果可能更独特,但我不确定这是否应该有任何效果......?
更大、更慢的文件:
17399307 99.4
17493652 98.8
17570460 98.2
17575180 97.6
17577127 97
17578255 96.4
17580576 95.8
17583028 95.2
17583699 94.6
17584172 94
更小、更统一的常规文件:
1 24
1001 24
2001 24
3001 24
4001 24
5001 24
6001 24
7001 24
我不确定是什么导致了这个问题,我会对任何关于在这种内存限制情况下排序的建议或一般输入感兴趣!
【问题讨论】:
-
为什么不在构建大数组时对其进行排序 - 例如在小数组的插值或合并期间?您可以使用就地合并排序,因为它使用 O(1) 内存。
-
不明白你的整个问题,但如果你需要对大于内存的数据集进行排序,你可以看看merge sort。他们在过去将其用于sort large data sets on tapes,当时主内存只有几千字节。
-
@StoyanDekov 嘿,感谢您的意见。我不确定我是否理解它是如何工作的,但也许你可以提示我。假设我沿着第 1 列对
sub_arr1进行排序,然后出现sub_arr2,它的第 1 列值将所有排序的sub_arr1一分为二,你是说通过合并排序我可以将这些列插入到正确索引处的增长数组中,然后移动到下一个sub_arrN? -
@BasSwinckels 也感谢您,Bas,我将对此进行调查。在我发现 NumPy 对大数据的处理效率之前,我实际上曾试图想出一些方法来按顺序对我的数据进行排序,方法是像你的链接文章描述的那样将其分解,尽管我并没有完全理解周围 ;-)。这里困扰我的问题是大小没有改变,只是其中一个数据列的组成,并且以某种方式使我的程序中断,所以我试图弄清楚为什么会这样......干杯!
-
@YXD 嘿,不知道你的意思是什么......你的意思是为我的数据集建立一个数据库并创建“键”或某种索引系统来返回排序的数据?我认为我写的问题很糟糕,TBH 我的主要问题是试图弄清楚为什么相同大小的数组更难根据其内容进行排序,尽管直观上它是有道理的,因为可能需要进行更多的比较......但我不太明白这些东西是如何在内部或任何东西上表示的,我还是个菜鸟;-)
标签: python performance sorting numpy memory