Skip to main content
 首页 » 编程设计

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

2025年05月04日6www_RR

我有一个包含大约 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答案是相关的。但是,我不确定如何应用它并避免循环。我是否会有效地用 bool 矩阵的列一遍又一遍地为时间序列向量编制索引?

请您参考如下方法:

您正在分配一个 200 * len(spiketimes) float 数组,因此对于您的 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 

太靠近data 边缘的spiketimes 的处理模仿了带有循环的函数中的情况。

当您拥有如此多的数据时,明智的做法是对数据进行观察。这更难矢量化(或者至少我还没有想出如何),但由于您没有复制任何数据,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