【问题标题】:Most efficient way to extract parts of one array based on another基于另一个数组提取部分数组的最有效方法
【发布时间】:2013-02-22 02:28:08
【问题描述】:

我有一个大约 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) &gt; 100000 的数组,它就会爆炸。是否有更高效的内存或(希望)更优雅的方法来提取基于另一个数组的一部分?

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

【问题讨论】:

  • 您需要一次获得所有这些吗?之后你对每个波形做了什么?
  • 我要在波形矩阵上做 PCA(好吧,SVD)。在获取波形和执行此操作之间,我可以将波形零碎地保存到文件中(如果我知道如何做到这一点)。但是,我需要在某个时候访问所有波形。

标签: python numpy indexing


【解决方案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

【讨论】:

  • 我明白为什么你写的第一个函数更好——我不知道 take 函数。为什么第二个函数比我的更快或更高效?它们看起来非常相似。
  • @mac389 第一个函数是从你的大数组中取出 200 个项目的块,并将这些块复制到一个新的、更大的数组中。因此你的记忆问题。第二个没有进行任何复制:附加到列表的每个项目都不拥有它们的数据,它们只是显示大数组的一个小窗口。这更节省内存,并且如上所示,尽管有 for 循环,它的性能可能相当好。当然,修改视图中的项目会修改底层数组,以及重叠视图中的值,所以你需要知道你在做什么。
猜你喜欢
  • 2022-12-11
  • 1970-01-01
  • 2017-08-27
  • 1970-01-01
  • 2020-01-04
  • 1970-01-01
  • 2011-06-27
  • 1970-01-01
  • 2014-03-03
相关资源
最近更新 更多