为什么这个Python逻辑索引占用了这么多内存

时间:2013-02-04 14:11:23

标签: python numpy python-2.7

我的1-D时间序列长1e8(100,000,000个元素)。 Here是我在Dropbox上使用的数据的链接。 (该文件为382 MB。)

更新

基于memory_profiling,错误发生在行

data[absolute(data-dc)< m*std(data)]=dc.

更具体地说,操作absolute(data-dc)占用了所有内存。 Data如上所述,dc是常量。也许这是一个微妙的语法错误?

我想从中删除异常值和工件,并用中位数替换这些值。我尝试使用以下功能执行此操作。

 from numpy import *

 from sys import argv

 from scipy.io import savemat
 from scipy.stats import scoreatpercentile

 def reject_outliers(data,dc,m=3):
      data[data==0] = dc
      data[bp.absolute(data-dc) < m*np.std(data)] = dc
      return data

 def butter_bandpass(lowcut,highcut,fs,order=8):
    nyq = 0.5*fs
    low = lowcut/nyq
    high = highcut/nyq

    b,a= butter(order, [low, high], btype='band')
    return b,a

 def butter_bandpass_filter(data,lowcut,highcut,fs,order=8):
    b,a = butter_bandpass(lowcut,highcut,fs,order=order)
    return lfilter(b,a,data) 

 OFFSET = 432
 filename = argv[1]
 outname = argv[2]  

 print 'Opening '+ filename
 with open(filename,'rb') as stream:
      stream.seek(OFFSET)
      data=fromfile(stream,dtype='int16')
 print 'Removing Artifacts, accounting for zero-filling'
 dc = median(data)
 data = reject_outliers(data,dc)

 threshold = scoreatpercentile(absolute(data),85)   
 print 'Filtering and Detrending'
 data = butter_bandpass_filter(data,300,7000,20000)
 savemat(outname+'.mat',mdict={'data':data})

在一个文件上调用此文件会占用4 GB的RAM和3 GB的虚拟内存。我确定这是这个函数的第二行,因为我逐步完成了我编写的脚本,它总是挂在这一部分上。我甚至可以看到(在OS X上的Finder中)第二个可用的硬盘空间直线下降。

时间序列不足以解释它。 reject-outliers的第二行有什么问题?

3 个答案:

答案 0 :(得分:5)

我刚刚生成100,000,000个随机浮点数并执行了您描述的相同索引。整个内存使用量远低于千兆字节。你没有告诉我们你的代码还做了什么?尝试通过优秀的memory_profiler运行您的代码。


编辑:添加了memory_profiler的代码和输出:

from numpy.random import uniform
import numpy

@profile
def go(m=3):
    data = uniform(size=100000000)
    dc = numpy.median(data)
    data[numpy.absolute(data-dc) < m*numpy.std(data)] = dc
    return data

if __name__ == '__main__':
    go()

输出:

Filename: example.py

Line #    Mem usage    Increment   Line Contents
================================================
     3                             @profile
     4     15.89 MB      0.00 MB   def go(m=3):
     5    778.84 MB    762.95 MB    data = uniform(size=100000000)
     6    778.91 MB      0.06 MB    dc = numpy.median(data)
     7    874.34 MB     95.44 MB    data[numpy.absolute(data-dc) < m*numpy.std(data)] = dc
     8    874.34 MB      0.00 MB    return data

正如您所看到的,100M浮动不会占用太多内存。

答案 1 :(得分:4)

您的数据和已修改@mbatchkarov's code的结果:

$ python mbatchkarov.py 
Filename: mbatchkarov.py

Line #    Mem usage    Increment   Line Contents
================================================
     5                             @profile
     6     15.74 MB      0.00 MB   def go(m=3):
     7     15.74 MB      0.00 MB       header_size = 432
     8     15.74 MB      0.00 MB       with open('ch008.ddt', 'rb') as file:
     9     15.75 MB      0.00 MB           file.seek(header_size)
    10    380.10 MB    364.36 MB           data = np.fromfile(file, dtype=np.int16) # 2 bytes per item                                                             
    11    380.20 MB      0.10 MB       dc = np.median(data)
    12                             
    13                                 # data[np.absolute(data - dc) < m*np.std(data)] = dc                                                                        
    14                                 # `data - dc` => temporary array 8 bytes per item                                                                           
    15    744.56 MB    364.36 MB       t = data.copy()
    16    744.66 MB      0.09 MB       t -= dc
    17    744.66 MB      0.00 MB       np.absolute(t, t)
    18    926.86 MB    182.20 MB       b = t < m*np.std(data) # boolean => 1 byte per item                                                                         
    19    926.87 MB      0.01 MB       data[b] = dc
    20    926.87 MB      0.00 MB       return data

data - dc需要几倍的内存:200M项目x每个项目8个字节,即data - dc导致由于广播而创建一个或两个临时双数组。为避免这种情况,请在其中制作显式副本和子结构:

t = data.copy() # 200M items x 2 bytes per item
t -= dc

似乎memory_profiler没有显示临时数组的内存。该程序的最大内存大约为3GB。

答案 2 :(得分:3)

Memory_profiler将执行给定行后的Python虚拟机的状态作为行的内存。因此,在一行中创建和销毁的数组不会出现在配置文件中。

以@ mbatchkarov为例,您可以将“data [numpy.absolute(data-dc)&lt; m * numpy.std(data)] = dc”这一行展开到较小的块中,以查看临时数组如何影响内存:

from numpy.random import uniform
import numpy

@profile
def go(m=3):
    data = uniform(size=100000000)
    dc = numpy.median(data)
    t1 = data-dc
    t2 = numpy.absolute(t1) < m*numpy.std(data)
    data[t2] = dc
    return data

if __name__ == '__main__':
    go()

给出了

$ python -m memory_profiler t1.py 
Filename: t1.py

Line #    Mem usage    Increment   Line Contents
================================================
     4                             @profile
     5     16.61 MB      0.00 MB   def go(m=3):
     6    779.56 MB    762.95 MB       data = uniform(size=100000000)
     7    779.62 MB      0.06 MB       dc = numpy.median(data)
     8   1542.57 MB    762.95 MB       t1 = data-dc
     9   1637.99 MB     95.42 MB       t2 = numpy.absolute(t1) < m*numpy.std(data)
    10   1638.00 MB      0.02 MB       data[t2] = dc
    11   1638.00 MB      0.00 MB       return data

很明显,“data-dc”指令会复制您的内存布局。解决这个问题的方法是在原地进行减法,即用“data - = dc”代替“t1 = data - dc”:

$ python -m memory_profiler t1.py 
Filename: t1.py

Line #    Mem usage    Increment   Line Contents
================================================
     4                             @profile
     5     16.61 MB      0.00 MB   def go(m=3):
     6    779.56 MB    762.95 MB       data = uniform(size=100000000)
     7    779.62 MB      0.06 MB       dc = numpy.median(data)
     8    779.63 MB      0.01 MB       data -= dc
     9    875.05 MB     95.42 MB       t2 = numpy.absolute(data) < m*numpy.std(data)
    10    875.07 MB      0.02 MB       data[t2] = dc
    11    875.07 MB      0.00 MB       return data

正如您所看到的,“data - = dc”现在几乎不会增加内存。