2012-08-03 92 views
0

数据是一个包含2500次测量时间序列的矩阵。我需要随时间对每个时间序列进行平均,丢弃峰值附近记录的数据点(在tspike-dt * 10 ... tspike + 10 * dt的时间间隔内)。针对每个神经元的尖峰时间数是可变的,并存储在具有2500个条目的字典中。我当前的代码遍历神经元和尖峰时间,并将屏蔽值设置为NaN。然后bottleneck.nanmean()被调用。然而,这个代码在当前版本中会变慢,我想知道更快的解决方案。谢谢!如何从时间点为numpy数组创建掩码?

import bottleneck 
import numpy as np 
from numpy.random import rand, randint 

t = 1 
dt = 1e-4 
N = 2500 
dtbin = 10*dt 

data = np.float32(ones((N, t/dt))) 
times = np.arange(0,t,dt) 
spiketimes = dict.fromkeys(np.arange(N)) 
for key in spiketimes: 
    spiketimes[key] = rand(randint(100)) 

means = np.empty(N) 

for i in range(N):   
    spike_times = spiketimes[i] 
    datarow = data[i] 
    if len(spike_times) > 0: 
    for spike_time in spike_times:       
     start=max(spike_time-dtbin,0) 
     end=min(spike_time+dtbin,t) 
     idx = np.all([times>=start,times<=end],0) 
     datarow[idx] = np.NaN 
    means[i] = bottleneck.nanmean(datarow) 

回答

0

绝大多数的在你的代码的处理时间来自这条线:

idx = np.all([times>=start,times<=end],0) 

这是因为每个秒杀,你是在对抗开始和结束时间比较每个值。既然你有统一的时间步骤,在这个例子中(我想这是真的在你的数据也一样),它是要快得多简单计算的起始和结束的索引:

# This replaces the last loop in your example: 
for i in range(N):   
    spike_times = spiketimes[i] 
    datarow = data[i] 
    if len(spike_times) > 0: 
     for spike_time in spike_times: 
      start=max(spike_time-dtbin,0) 
      end=min(spike_time+dtbin,t) 
      #idx = np.all([times>=start,times<=end],0) 
      #datarow[idx] = np.NaN 
      datarow[int(start/dt):int(end/dt)] = np.NaN 
    ## replaced this with equivalent for testing 
    means[i] = datarow[~np.isnan(datarow)].mean() 

这减少了运行时间对我来说从大约100秒到大约1.5秒。 您还可以通过将spike_times上的循环向量化来削减更多时间。这样做的效果将取决于您的数据的特征(应该对高峰值速率最有效):

kernel = np.ones(20, dtype=bool) 
for i in range(N):   
    spike_times = spiketimes[i] 
    datarow = data[i] 
    mask = np.zeros(len(datarow), dtype=bool) 
    indexes = (spike_times/dt).astype(int) 
    mask[indexes] = True 
    mask = np.convolve(mask, kernel)[10:-9] 

    means[i] = datarow[~mask].mean() 
+0

向量化内循环是我寻找的wthat。也感谢提示使用convolve为掩码创建间隔。在我的时间里,我从几分钟到一秒之内都有了加速 – 2012-08-10 09:26:01

0

而不是使用nanmean你可以只索引你需要的值,并使用mean的。

means[i] = data[ (times<start) | (times>end) ].mean() 

如果我误解,你需要你的索引,你可以尝试

means[i] = data[numpy.logical_not(np.all([times>=start,times<=end],0))].mean() 
你可能想不使用 if len(spike_times) > 0代码

也(我假设你删除尖峰时间在每次迭代或否则该语句将始终为真,并且您将有一个无限循环),只能使用for spike_time in spike_times

+0

采取措施应该已经优化。根据http://stackoverflow.com/questions/5480694/numpy-calculate-averages-with-nans-removed bottleneck.mean()是最快的方式来掩盖数组。我希望从没有迭代的spiketimes字典创建一个面具可以带来性能的改善 – 2012-08-03 20:32:12

+0

@maryamroayaee:我不认为你需要有'NaN'或使用掩码 - 你可以索引到你想要的值,并采取'平均值' - 这应该比将元素设置为NaN更快。 – jmetz 2012-08-03 20:36:29

+0

@maryamroayaee:我认为你的代码还有一个错误:因为当你在每次迭代中将元素设置为NaN时,元素不会恢复到它们的NaN之前的值,以便进行下一次迭代! – jmetz 2012-08-03 20:40:06