迭代模拟的严重性能问题
Serious performance issue with iterating simulations
我最近在实现模拟算法时偶然发现了一个性能问题。我设法找到了瓶颈函数(信号,它是对 arrayfun
的内部调用,它减慢了一切):
function sim = simulate_frequency(the_f,k,n)
r = rand(1,n); %
x = arrayfun(@(x) find(x <= the_f,1,'first'),r);
sim = (histcounts(x,[1:k Inf]) ./ n).';
end
它正在代码的其他部分使用如下:
h0 = zeros(1,sims);
for i = 1:sims
p = simulate_frequency(the_f,k,n);
h0(i) = max(abs(p - the_p));
end
以下是一些可能的值:
% Test Case 1
sims = 10000;
the_f = [0.3010; 0.4771; 0.6021; 0.6990; 0.7782; 0.8451; 0.9031; 0.9542; 1.0000];
k = 9;
n = 95;
% Test Case 2
sims = 10000;
the_f = [0.0413; 0.0791; 0.1139; 0.1461; 0.1760; 0.2041; 0.2304; 0.2552; 0.2787; 0.3010; 0.3222; 0.3424; 0.3617; 0.3802; 0.3979; 0.4149; 0.4313; 0.4471; 0.4623; 0.4771; 0.4913; 0.5051; 0.5185; 0.5314; 0.5440; 0.5563; 0.5682; 0.5797; 0.5910; 0.6020; 0.6127; 0.6232; 0.6334; 0.6434; 0.6532; 0.6627; 0.6720; 0.6812; 0.6901; 0.6989; 0.7075; 0.7160; 0.7242; 0.7323; 0.7403; 0.7481; 0.7558; 0.7634; 0.7708; 0.7781; 0.7853; 0.7923; 0.7993; 0.8061; 0.8129; 0.8195; 0.8260; 0.8325; 0.8388; 0.8450; 0.8512; 0.8573; 0.8633; 0.8692; 0.8750; 0.8808; 0.8864; 0.8920; 0.8976; 0.9030; 0.9084; 0.9138; 0.9190; 0.9242; 0.9294; 0.9344; 0.9395; 0.9444; 0.9493; 0.9542; 0.9590; 0.9637; 0.9684; 0.9731; 0.9777; 0.9822; 0.9867; 0.9912; 0.9956; 1.000];
k = 90;
n = 95;
标量 sims
必须在 1000
1000000
范围内。累积频率向量 the_f
永远不会包含超过 100
个元素。标量 k
表示 the_f
中的元素数。最后,标量 n
表示经验样本向量中元素的数量,甚至可以非常大(据我所知,最多 10000
个元素)。
关于如何改进此过程的计算时间的任何线索?
在第二个测试用例中,这对我来说似乎稍微快一些,而不是第一个。对于更长的 the_f
和更大的 n
.
值,时间差异可能会更大
function sim = simulate_frequency(the_f,k,n)
r = rand(1,n); %
[row,col] = find(r <= the_f); % Implicit singleton expansion going on here!
[~,ind] = unique(col,'first');
x = row(ind);
sim = (histcounts(x,[1:k Inf]) ./ n).';
end
我在 r <= the_f
中使用隐式单例扩展,如果您使用的是旧版本的 MATLAB(但您知道操作),请使用 bsxfun
。
然后找到 returns 行和列到 r
大于 the_f
的所有位置。 unique
查找结果中每列第一个元素的索引。
来源:Andrei Bobrov over on MATLAB Answers
另一个选项(源自 this other answer)更短但也更晦涩 IMO:
mask = r <= the_f;
[x,~] = find(mask & (cumsum(mask,1)==1));
如果我想要性能,我会避免 arrayfun
。即使这个 for
循环更快:
function sim = simulate_frequency(the_f,k,n)
r = rand(1,n); %
for i = 1:numel(r)
x(i) = find(r(i)<the_f,1,'first');
end
sim = (histcounts(x,[1:k Inf]) ./ n).';
end
运行 10000 个 sims 与第一组样本数据给出以下时间。
您的 arrayfun
函数:
>Elapsed time is 2.848206 seconds.
for
循环函数:
>Elapsed time is 0.938479 seconds.
受 Cris Luengo 回答的启发,我建议如下:
function sim = simulate_frequency(the_f,k,n)
r = rand(1,n); %
x = sum(r > the_f)+1;
sim = (histcounts(x,[1:k Inf]) ./ n)';
end
时间:
>Elapsed time is 0.264146 seconds.
您可以使用 histcounts
并将 r
作为其输入:
r = rand(1,n);
sim = (histcounts(r,[-inf ;the_f]) ./ n).';
如果使用 histc
而不是 histcounts
,则整个模拟可以矢量化:
r = rand(n,sims);
p = histc(r, [-inf; the_f],1);
p = [p(1:end-2,:) ;sum(p(end-1:end,:))]./n;
h0 = max(abs(p-the_p(:))); %h0 = max(abs(bsxfun(@minus,p,the_p(:))));
我最近在实现模拟算法时偶然发现了一个性能问题。我设法找到了瓶颈函数(信号,它是对 arrayfun
的内部调用,它减慢了一切):
function sim = simulate_frequency(the_f,k,n)
r = rand(1,n); %
x = arrayfun(@(x) find(x <= the_f,1,'first'),r);
sim = (histcounts(x,[1:k Inf]) ./ n).';
end
它正在代码的其他部分使用如下:
h0 = zeros(1,sims);
for i = 1:sims
p = simulate_frequency(the_f,k,n);
h0(i) = max(abs(p - the_p));
end
以下是一些可能的值:
% Test Case 1
sims = 10000;
the_f = [0.3010; 0.4771; 0.6021; 0.6990; 0.7782; 0.8451; 0.9031; 0.9542; 1.0000];
k = 9;
n = 95;
% Test Case 2
sims = 10000;
the_f = [0.0413; 0.0791; 0.1139; 0.1461; 0.1760; 0.2041; 0.2304; 0.2552; 0.2787; 0.3010; 0.3222; 0.3424; 0.3617; 0.3802; 0.3979; 0.4149; 0.4313; 0.4471; 0.4623; 0.4771; 0.4913; 0.5051; 0.5185; 0.5314; 0.5440; 0.5563; 0.5682; 0.5797; 0.5910; 0.6020; 0.6127; 0.6232; 0.6334; 0.6434; 0.6532; 0.6627; 0.6720; 0.6812; 0.6901; 0.6989; 0.7075; 0.7160; 0.7242; 0.7323; 0.7403; 0.7481; 0.7558; 0.7634; 0.7708; 0.7781; 0.7853; 0.7923; 0.7993; 0.8061; 0.8129; 0.8195; 0.8260; 0.8325; 0.8388; 0.8450; 0.8512; 0.8573; 0.8633; 0.8692; 0.8750; 0.8808; 0.8864; 0.8920; 0.8976; 0.9030; 0.9084; 0.9138; 0.9190; 0.9242; 0.9294; 0.9344; 0.9395; 0.9444; 0.9493; 0.9542; 0.9590; 0.9637; 0.9684; 0.9731; 0.9777; 0.9822; 0.9867; 0.9912; 0.9956; 1.000];
k = 90;
n = 95;
标量 sims
必须在 1000
1000000
范围内。累积频率向量 the_f
永远不会包含超过 100
个元素。标量 k
表示 the_f
中的元素数。最后,标量 n
表示经验样本向量中元素的数量,甚至可以非常大(据我所知,最多 10000
个元素)。
关于如何改进此过程的计算时间的任何线索?
在第二个测试用例中,这对我来说似乎稍微快一些,而不是第一个。对于更长的 the_f
和更大的 n
.
function sim = simulate_frequency(the_f,k,n)
r = rand(1,n); %
[row,col] = find(r <= the_f); % Implicit singleton expansion going on here!
[~,ind] = unique(col,'first');
x = row(ind);
sim = (histcounts(x,[1:k Inf]) ./ n).';
end
我在 r <= the_f
中使用隐式单例扩展,如果您使用的是旧版本的 MATLAB(但您知道操作),请使用 bsxfun
。
然后找到 returns 行和列到 r
大于 the_f
的所有位置。 unique
查找结果中每列第一个元素的索引。
来源:Andrei Bobrov over on MATLAB Answers
另一个选项(源自 this other answer)更短但也更晦涩 IMO:
mask = r <= the_f;
[x,~] = find(mask & (cumsum(mask,1)==1));
如果我想要性能,我会避免 arrayfun
。即使这个 for
循环更快:
function sim = simulate_frequency(the_f,k,n)
r = rand(1,n); %
for i = 1:numel(r)
x(i) = find(r(i)<the_f,1,'first');
end
sim = (histcounts(x,[1:k Inf]) ./ n).';
end
运行 10000 个 sims 与第一组样本数据给出以下时间。
您的 arrayfun
函数:
>Elapsed time is 2.848206 seconds.
for
循环函数:
>Elapsed time is 0.938479 seconds.
受 Cris Luengo 回答的启发,我建议如下:
function sim = simulate_frequency(the_f,k,n)
r = rand(1,n); %
x = sum(r > the_f)+1;
sim = (histcounts(x,[1:k Inf]) ./ n)';
end
时间:
>Elapsed time is 0.264146 seconds.
您可以使用 histcounts
并将 r
作为其输入:
r = rand(1,n);
sim = (histcounts(r,[-inf ;the_f]) ./ n).';
如果使用 histc
而不是 histcounts
,则整个模拟可以矢量化:
r = rand(n,sims);
p = histc(r, [-inf; the_f],1);
p = [p(1:end-2,:) ;sum(p(end-1:end,:))]./n;
h0 = max(abs(p-the_p(:))); %h0 = max(abs(bsxfun(@minus,p,the_p(:))));