最有效的方法是基于另一个提取一个数组的部分

时间:2013-02-22 02:28:08

标签: python numpy indexing

我有一个约1.5亿分的时间序列。我需要放大300万点。也就是说,我需要在这个1.5亿点时间序列中提取围绕这300万个感兴趣区域的100个时间点

尝试:

 def get_waveforms(data,spiketimes,lookback=100,lookahead=100):
      answer = zeros((len(spiketimes),(lookback+lookahead)))
      duration = len(data)
      for i in xrange(len(spiketimes)):
          if(spiketimes[i] - lookback) > 0 and spiketimes[i] + lookahead) < duration:
               answer[i,:] = data[(spiketimes[i]-lookback):(spiketimes[i]+lookahead)]
      return answer

这会占用我Mac上的所有可用内存。如果我尝试传递len(array) > 100000的数组,它会爆炸。是否有更高效的内存或(希望)更优雅的方法来基于另一个阵列拉出一个阵列的部分?

相关 This答案是相关的。但是,我不确定如何应用它并避免循环。我是否有效地使用布尔矩阵的列来反复索引时间序列向量?

1 个答案:

答案 0 :(得分:1)

您正在分配200 * len(spiketimes)个浮点数组,因此对于您的100,000个项spiketimes应该只有160 MB左右,这看起来并不多。另一方面,如果你去1,000,000 spiketimes,1.6 GB单阵列可能是某些系统的延伸。如果你有记忆,你可以用这样的东西来矢量化提取:

def get_waveforms(data, spiketimes, lookback=100, lookahead=100) :
    offsets = np.arange(-lookback, lookahead)
    indices = spiketimes + offsets[:, None]
    ret = np.take(data, indices, mode='clip')
    ret[:, spiketimes < lookback] = 0
    ret[:, spiketimes + lookahead >= len(data)] = 0
    return ret

spiketimes太靠近data边缘的处理模仿了你的函数中的循环。

当您拥有如此多的数据时,明智之举就是将视图带入其中。这很难进行矢量化(或者至少我没有想过如何),但由于你没有复制任何数据,所以python循环不会慢得多:

def get_waveforms_views(data, spiketimes, lookback=100, lookahead=100) :
    ret = []
    for j in spiketimes :
        if j < lookback or j + lookahead >= len(data) :
            ret.append(None)
        else :
            ret.append(data[j - lookback:j + lookahead])
    return ret

使用以下测试数据:

data_points, num_spikes = 1000000, 10000

data = np.random.rand(data_points)
spiketimes = np.random.randint(data_points, size=(num_spikes))

我得到了这些时间:

In [2]: %timeit get_waveforms(data, spiketimes)
1 loops, best of 3: 320 ms per loop

In [3]: %timeit get_waveforms_views(data, spiketimes)
1 loops, best of 3: 313 ms per loop