我有这段代码
N=10^4;
for i = 1:N
[E,X,T] = fffun(); % Stochastic simulation. Returns every time three different vectors (whose length is 10^3).
X_(i,:)=X;
T_(i,:)=T;
GRID=[GRID T];
end
GRID=unique(GRID);
% Second part
for i=1:N
for j=1:(kmax)
f=find(GRID==T_(i,j) | GRID==T_(i,j+1));
s=f(1);
e=f(2)-1;
counter(X_(i,j), s:e)=counter(X_(i,j), s:e)+1;
end
end
该代码对随机过程进行N次不同的模拟(由10 ^ 3个事件组成,这些事件在离散时刻(T向量)发生,具体取决于特定的模拟。现在,我想知道(第二部分)与时间有关的函数,在特定状态下有多少个模拟(X的取值范围是1到10),我的想法是:创建一个网格矢量,其中包含所有模拟中发生的所有时刻。发生某事的时间步长,并递增与该特定时间段相对应的所有计数器的增量。
但是,第二部分非常繁重(我的意思是在标准四核CPU上要花费几天的时间)。而且不应该。是否有任何想法(也许是关于更有效地比较向量的想法)来减少CPU时间?
这是一个独立的“ second_part”
N=5000;
counter=zeros(11,length(GRID));
for i=1:N
disp(['Counting sim #' num2str(i)]);
for j=1:(kmax)
f=find(GRID==T_(i,j) | GRID==T_(i,j+1),2);
s=f(1);
e=f(2)-1;
counter(X_(i,j), s:e)=counter(X_(i,j), s:e)+1;
end
end
counter=counter/N;
stop=find(GRID==Tmin);
stop=stop-1;
plot(counter(:,(stop-500):stop)')
以及相关的伪数据(filedropper.com/data_38)。在实际情况下,矩阵有2x行和10x列。
这是我的理解:
T_
是来自N个模拟的时间步长矩阵。
X_
是T_
这些仿真中的仿真状态矩阵。
因此,如果您这样做:
[ut,~,ic]= unique(T_(:));
您将获得ic
,它是中所有唯一元素的索引向量T_
。然后,您可以编写:
counter = accumarray([ic X_(:)],1);
并得到counter
没有。行数作为您唯一的时间步长,没有。列中的唯一状态X_
(均为且必须为整数)。现在您可以说,对于每个时间步ut(k)
,仿真处于状态的时间m
为counter(k,m)
。
在您的数据,唯一的组合m
和k
具有大于1的值是(1,1)
。
编辑:
从下面的评论中,我了解到您记录了所有状态更改以及发生状态更改的时间步长。然后,每次模拟更改状态时,您都希望从所有模拟中收集所有状态,并计算每种类型有多少个状态。
这里的主要问题是您的时间是连续的,因此基本上每个元素T_
都是唯一的,并且您有超过一百万个时间步长要循环。完全矢量化此过程将需要大约80GB的内存,这可能会卡住您的计算机。
因此,我在时间步长中寻求矢量化和循环的结合。我们首先找到所有唯一的时间间隔,然后预先分配counter
:
ut = unique(T_(:));
stt = 11; % no. of states
counter = zeros(stt,numel(ut));r = 1:size(T_,1);
r = 1:size(T_,1); % we will need that also later
然后,我们遍历中的所有元素ut
,并且每次T_
都以矢量化的方式在所有模拟中寻找相关的时间步长。最后我们histcounts
用来计算所有状态:
for k = 1:numel(ut)
temp = T_<=ut(k); % mark all time steps before ut(k)
s = cumsum(temp,2); % count the columns
col_ind = s(:,end); % fins the column index for each simulation
% convert the coulmns to linear indices:
linind = sub2ind(size(T_),r,col_ind.');
% count the states:
counter(:,k) = histcounts(X_(linind),1:stt+1);
end
在我的计算机上进行1000次仿真大约需要4秒钟,因此整个过程增加了一个多小时的时间。不太快...
您还可以尝试以下一项或两项调整,以进一步压缩运行时间:
正如您在这里所读到的,accumarray
似乎在较小的数组中工作得更快histcouns
。所以可能要切换到它。
另外,直接计算线性索引比更快sub2ind
,因此您可能需要尝试一下。
在上面的循环中实现这些建议,我们得到:
R = size(T_,1);
r = (1:R).';
for k = 1:K
temp = T_<=ut(k); % mark all time steps before ut(k)
s = cumsum(temp,2); % count the columns
col_ind = s(:,end); % fins the column index for each simulation
% convert the coulmns to linear indices:
linind = R*(col_ind-1)+r;
% count the states:
counter(:,k) = accumarray(X_(linind),1,[stt 1]);
end
在我的计算机上,切换到accumarray
或删除sub2ind
的效果有所改善,但是并不一致(timeit
用于测试中的100或1K元素ut
),因此您最好自己进行测试。但是,这仍然很长。
您可能要考虑的一件事是尝试离散化您的时间步长,因此循环使用的独特元素要少得多。在您的数据中,大约有8%的时间间隔小于1。如果您可以假设该时间间隔短到可以视为一个时间步长,则可以四舍五入T_
并获得约12.5K个唯一元素,这大约需要一个分钟即可结束。您可以以0.1个间隔(小于时间间隔的1%)执行相同操作,并获得122K元素进行循环,这大约需要8个小时...
当然,以上所有时序都是使用相同算法的粗略估计。如果你不选择圆的时间可能有更好的方法来解决这个问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句