【问题标题】:Vectorized approach to compute PSTH (peristimulus time histogram) in MATLAB在 MATLAB 中计算 PSTH(周刺激时间直方图)的矢量化方法
【发布时间】:2016-08-14 11:29:00
【问题描述】:

我有一个尖峰时间向量(来自神经元的动作电位)和一个刺激事件时间戳向量。我想创建一个 PSTH 来查看刺激是否会影响神经元的尖峰率。我可以通过循环遍历每个刺激事件来做到这一点(参见下面的简单示例),但是对于有超过 30,000 个刺激事件并且正在记录许多神经元的长时间实验来说,这非常慢。

没有for循环怎么办?

慢路示例:

% set variables
spikeTimes = [0.9 1.1 1.2 2.5 2.8 3.1];
stimTimes = [1 2 3 4 5];        
preStimTime = 0.2;
postStimTime = 0.3;
for iStim = 1:length(stimTimes)
    % find spikes within time window
    inds = find((spikeTimes > (stimTimes(iStim) - preStimTime)) & (spikeTimes < (stimTimes(iStim) + postStimTime)));
    % align spike times to stimulus onset
    stimONtimes = spikeTimes(inds) - stimTimes(iStim);
    % store times in array for plotting
    PSTH_array(iStim,1:length(stimONtimes)) = stimONtimes;
end

【问题讨论】:

  • 您可能需要告诉我们 PSTH 的作用。在正常的直方图中,您只需要每个箱的计数,但在您的情况下,您似乎将各个值放入每个箱中。这是你想要的吗?
  • @beaker 我没有将值放入示例代码中的 bin 中,我只是存储每个刺激呈现的定义时间窗口中发生的尖峰时间。这就是我要优化的。然后可以使用该数组制作直方图并定义任意大小的时间箱。
  • 啊,我明白了。这是一种耻辱,因为它会更容易进行总和或计数或其他任何事情。 (或者,至少,我可以找到一种更直接的方法。)尽管如此,还是很受欢迎的。
  • @beaker 你会如何使用 sum 或 count 呢?我肯定想知道怎么问有多少尖峰时间在0.8和1.3之间,有多少尖峰时间在1.8和2.3之间,没有循环。输出应该是 3 和 0,并且应该以某种方式存储。如果您对应用程序感兴趣,这里是 PSTH 的参考en.wikipedia.org/wiki/Peristimulus_time_histogram
  • 好吧,你可以试试 histogramdiscretize 并通过 bin 边缘,但我不确定当 bin 重叠时它们会做什么。

标签: matlab vectorization neuroscience


【解决方案1】:

最好的方法可能是只使用现有的直方图函数。它们的速度非常快,应该可以为您提供所需的所有信息。当然,这是假设箱不重叠。鉴于您的示例数据:

spikeTimes = [0.9 1.1 1.2 2.5 2.8 3.1];
stimTimes = [1 2 3 4 5];        
preStimTime = 0.2;
postStimTime = 0.3;

你可以像这样构造垃圾箱:

bins = sort([stimTimes - preStimTime, stimTimes + postStimTime])

bins = [stimTimes - preStimTime; stimTimes + postStimTime];
bins = bins(:).'

bins =
   0.80000   1.30000   1.80000   2.30000   2.80000   3.30000   3.80000   4.30000   4.80000   5.30000

然后您可以使用histcountsdiscretizehistc,具体取决于您想要的结果以及您拥有的 MATLAB 版本。我将使用histc(因为我没有那么多花哨的东西),但所有三个函数的输入都是相同的。 histcounts 有一个额外的输出(edges,对我们没用),discretize 少一个输出(实际计数)。

[N, IDX] = histc(spikeTimes, bins)

N =    
   3   0   0   1   2   0   0   0   0   0

IDX =    
   1   1   1   4   5   5

由于垃圾箱包括(T(i) + postStimTime)(T(i+1) - preStimTime) 之间的时间,我们需要采取其他所有垃圾箱:

N = N(1:2:end)

N =
   3   0   2   0   0

同样,我们只对奇数时隙中发生的尖峰感兴趣,我们需要调整索引以匹配新的IDX

v = mod(IDX, 2)

v =
   1   1   1   0   1   1

IDX = ((IDX+1)/2).*v

IDX =
   1   1   1   0   3   3

结果与我们最初得到的一致:bin 1 中有 3 个尖峰,bin 3 中有 2 个尖峰。

【讨论】:

  • 这将执行时间从 20 分钟到几个小时之间的任何时间更改为 3 秒。好棒的烧杯!
【解决方案2】:

这是一个解决方案,在所有尖峰上都有一个循环和两个假设:

  • 刺激时间间隔固定
  • 刺激间隔大于 PSTH 间隔

假设刺激时间是固定的:

delta_times = mean(diff(stimTimes));
assert(max(abs(diff(stimTimes)-delta_times))<1e-3);

现在我们将尖峰时间与第一次刺激之前的 preStimTime 对齐:

spikeTimes0 = spikeTimes - stimTimes(1) + preStimTime;

现在我们希望使用第二个假设计算每个尖峰的刺激因素:

assert((postStimTime-preStimTime)<dekta_times);
stimuli_index = floor(spikeTimes0 / delta_times); 

相对于该刺激进行计算:

spike_time_from_stimuli = spikeTimes0 - stimuli_index*delta_times;

现在让我们以 0.01 的精度构建 PSTH(与所有其他时间使用相同的单位):

dt = 0.01;
times_around_stimuli = preStimTime:dt:postStimTime;
n_time_bins = length(times_around_stimuli);
n_stimuli = length(stimTimes);
PSTH = zeros(n_stimuli, n_time_bins)
for i=1:length(spikeTimes)
     time_index = ceil(spike_time_from_stimuli(i) / dt);
     % Ignore time-bins far from the event
     if time_index > n_time_bins
           continue;
     end
     PSTH(stimuli_index(i),time_index) = PSTH(stimuli_index(i),time_index) + 1;
end

【讨论】:

  • 感谢您的回复。请您测试您提出的解决方案的完整版本,然后将其发送给我吗?您在此处粘贴的代码存在许多错误(例如,stimuli_before_index、n_time_bins 和 n_stimuli 均未定义)。
  • 我已经修复了我发现的问题,但是没有更完整的版本,我写它是为了你的答案,而不是复制粘贴它。您应该首先了解它,以便您可以自己解决任何此类问题!祝你好运。
  • 通过完整版,我的意思是您能够在您的计算机上成功运行某些东西并获得我想要的输出。当我尝试使用您的代码时,它不会毫无错误地执行。当您甚至不知道它有效时,我宁愿不调试您的代码......
猜你喜欢
  • 2011-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 2015-09-07
  • 2011-09-17
相关资源
最近更新 更多