2

我有一个长度为 1e8 的一维时间序列(100,000,000 个元素)。是我在 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

4

3 回答 3

5

我刚刚生成了 100,000,000 个随机浮点数并进行了与您描述的相同的索引。整个内存使用量远低于 1 GB。您的代码还做了哪些您没有告诉我们的事情?尝试通过出色的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 的浮点数不会占用那么多内存。

于 2013-02-04T14:26:46.707 回答
4

您的数据和修改@mbatchkarov 代码的结果:

$ 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。

于 2013-02-04T15:36:05.907 回答
3

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

以@mbatchkarov 为例,您可以将“data[numpy.absolute(data-dc) < 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”指令复制了您的内存布局。解决此问题的方法是就地执行减法,即将“t1 = data - dc”替换为“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”现在几乎不会增加内存。

于 2013-02-05T08:46:48.343 回答