内存映射数组操作的正确方式
我对这个操作有点困惑,具体情况是这样的。我之前在普通的Numpy数组上做过这个,但在一个内存映射(memmap)上,我想了解它是怎么运作的。
arr2 = np.argsort(np.argsort(arr1,axis=0),axis=0) / float(len(arr1)) * 100
#This is basically to calculate Percentile rank of each value wrt the entire column
这是我在普通Numpy数组上使用的代码。
现在,假设arr1是一个20GB的内存映射数组,我有几个问题:
1:
arr2 = np.argsort(np.argsort(arr1,axis=0),axis=0) / float(len(arr1)) * 100
arr2应该是一个普通的Numpy数组,对吧?那么执行这个操作会在内存上造成很大的压力,对吧?
考虑到我现在已经创建了一个大小合适的内存映射数组arr2
(里面全是零)。
2:
arr2 = np.argsort(np.argsort(arr1,axis=0),axis=0) / float(len(arr1)) * 100
与
arr2[:] = np.argsort(np.argsort(arr1,axis=0),axis=0) / float(len(arr1)) * 100
有什么区别呢?
3.
如果我单独计算np.argsort
作为一个临时的内存映射数组,然后再计算np.argsort(np.argsort)
作为另一个临时的内存映射数组,这样做会不会更节省内存?因为对于一个20GB的数组,argsort数组本身也会非常大!
我觉得这些问题能帮助我更好地理解Python中内存映射数组的内部工作原理!
谢谢...
1 个回答
我先来回答第2部分,然后再说第1和第3部分。
首先,arr = <something>
是简单的变量赋值,而 arr[:] = <something>
是在给数组的内容赋值。在下面的代码中,执行 arr[:] = x
后,arr
仍然是一个内存映射数组,而执行 arr = x
后,arr
就变成了一个ndarray(即普通数组)。
>>> arr = np.memmap('mm', dtype='float32', mode='w+', shape=(1,10000000))
>>> type(arr)
<class 'numpy.core.memmap.memmap'>
>>> x = np.ones((1,10000000))
>>> type(x)
<class 'numpy.ndarray'>
>>> arr[:] = x
>>> type(arr)
<class 'numpy.core.memmap.memmap'>
>>> arr = x
>>> type(arr)
<class 'numpy.ndarray'>
对于 np.argsort
,它返回一个和输入参数类型相同的数组。所以在这个特定的情况下,我认为 arr = np.argsort(x)
和 arr[:] = np.argsort(x)
之间应该没有区别。在你的代码中,arr2
将会是一个内存映射数组。但实际上是有区别的。
>>> arr = np.memmap('mm', dtype='float32', mode='w+', shape=(1,10000000))
>>> x = np.ones((1,10000000))
>>> arr[:] = x
>>> type(np.argsort(x))
<class 'numpy.ndarray'>
>>> type(np.argsort(arr))
<class 'numpy.core.memmap.memmap'>
好,现在来说说有什么不同。使用 arr[:] = np.argsort(arr)
,如果我们查看内存映射文件的变化,会发现每次对 arr
的修改都会导致文件的md5校验和发生变化。
>>> import os
>>> import numpy as np
>>> arr = np.memmap('mm', dtype='float32', mode='w+', shape=(1,10000000))
>>> arr[:] = np.zeros((1,10000000))
>>> os.system("md5sum mm")
48e9a108a3ec623652e7988af2f88867 mm
0
>>> arr += 1.1
>>> os.system("md5sum mm")
b8efebf72a02f9c0b93c0bbcafaf8cb1 mm
0
>>> arr[:] = np.argsort(arr)
>>> os.system("md5sum mm")
c3607e7de30240f3e0385b59491ac2ce mm
0
>>> arr += 1.3
>>> os.system("md5sum mm")
1e6af2af114c70790224abe0e0e5f3f0 mm
0
我们看到 arr
仍然保留着它的 _mmap
属性。
>>> arr._mmap
<mmap.mmap object at 0x7f8e0f086198>
而使用 arr = np.argsort(x)
时,我们会发现md5校验和不再变化。尽管 arr
的类型是内存映射数组,但它实际上是一个新对象,似乎内存映射的特性消失了。
>>> import os
>>> import numpy as np
>>> arr = np.memmap('mm', dtype='float32', mode='w+', shape=(1,10000000))
>>> arr[:] = np.zeros((1,10000000))
>>> os.system("md5sum mm")
48e9a108a3ec623652e7988af2f88867 mm
0
>>> arr += 1.1
>>> os.system("md5sum mm")
b8efebf72a02f9c0b93c0bbcafaf8cb1 mm
0
>>> arr = np.argsort(arr)
>>> os.system("md5sum mm")
b8efebf72a02f9c0b93c0bbcafaf8cb1 mm
0
>>> arr += 1.3
>>> os.system("md5sum mm")
b8efebf72a02f9c0b93c0bbcafaf8cb1 mm
0
>>> type(arr)
<class 'numpy.core.memmap.memmap'>
现在 _mmap
属性变成了 None。
>>> arr._mmap
>>> type(arr._mmap)
<class 'NoneType'>
接下来是第3部分。进行复杂操作时,似乎很容易失去对内存映射对象的引用。我目前的理解是,你需要将操作拆分开,并使用 arr[:] = <>
来处理中间结果。
使用的是numpy 1.8.1 和 Python 3.4.1