Labfans是一个针对大学生、工程师和科研工作者的技术社区。 | 论坛首页 | 联系我们(Contact Us) |
![]() |
![]() |
#1 |
高级会员
注册日期: 2019-11-21
帖子: 3,006
声望力: 66 ![]() |
![]()
我正在尝试使用“值”数组和“计数器”数组将多个值插入到数组中。例如,如果:
a=[1,3,2,5] b=[2,2,1,3] 我想要一些功能的输出 c=somefunction(a,b) 成为 c=[1,1,3,3,2,5,5,5] 其中a(1)重复b(1)次,a(2)重复b(2)次,依此类推... MATLAB中是否有内置函数可以执行此操作?如果可能,我想避免使用for循环。我已经尝试了'repmat()'和'kron()'的变体但无济于事。 这基本上是Run-length encoding 。 回答: 问题陈述 我们的价值观,数组vals和游程, runlens : vals = [1,3,2,5] runlens = [2,2,1,3] 我们需要以vals重复每个元素乘以runlens每个对应元素。因此,最终输出将是: output = [1,1,3,3,2,5,5,5] 前瞻性方法 cumsum是MATLAB最快的工具之一,在处理对不规则模式起作用的矢量化问题时非常有用。在陈述的问题中,不规则性带有runlens的不同元素。 现在,要利用cumsum ,我们需要在这里做两件事:初始化一个zeros数组并将“适当的”值放置在zeros数组的“关键”位置,这样,在应用“ cumsum ”后,我们最终得到一个重复的阵列天线的最终vals的runlens倍。 步骤:让我们对上述步骤进行编号,以使前瞻性方法更容易理解: 1)初始化零数组:长度必须是多少?由于我们要重复runlens时间,所以zeros数组的长度必须是所有runlens的总和。 2)查找关键位置/索引:现在这些关键位置是沿着Zeros数组放置的位置,其中vals中的每个元素都开始重复。因此,对于runlens = [2,2,1,3] ,映射到zeros数组的关键位置将是: [X 0 X 0 XX 0 0] % where X's are those key positions. 3)找到合适的值:使用cumsum之前要进行锤打的最后一个钉子是将“适当的”值放入这些关键位置。现在,因为我们会做cumsum后不久,如果你认真地思考,你会需要一个differentiated的版本values与diff ,使cumsum那些将带回我们的values 。由于这些微分值将被放置在由runlens距离分隔的位置处的零数组上,因此使用cumsum我们将让每个vals元素重复runlens次作为最终输出。 解决方案代码 这是将上述所有步骤组合在一起的实现- % Calculate cumsumed values of runLengths. % We would need this to initialize zeros array and find key positions later on. clens = cumsum(runlens) % Initalize zeros array array = zeros(1,(clens(end))) % Find key positions/indices key_pos = [1 clens(1:end-1)+1] % Find appropriate values app_vals = diff([0 vals]) % Map app_values at key_pos on array array(pos) = app_vals % cumsum array for final output output = cumsum(array) 预分配黑客 可以看出,上面列出的代码使用带有零的预分配。现在,根据这个UNDOCUMENTED MATLAB关于更快的预分配的博客 ,使用以下命令可以实现更快的预分配: array(clens(end)) = 0; % instead of array = zeros(1,(clens(end))) 总结:功能代码 要包装所有内容,我们将有一个紧凑的功能代码来实现这种游程长度解码,如下所示: function out = rle_cumsum_diff(vals,runlens) clens = cumsum(runlens); idx(clens(end))=0; idx([1 clens(1:end-1)+1]) = diff([0 vals]); out = cumsum(idx); return; 标杆管理 基准测试代码 接下来列出的是基准测试代码,用于比较本篇文章中所述的cumsum+diff 方法与MATLAB 2014B上的另cumsum-only基于cumsum-only的方法的运行时和加速- datasizes = [reshape(linspace(10,70,4).'*10.^(0:4),1,[]) 10^6 2*10^6]; % fcns = {'rld_cumsum','rld_cumsum_diff'}; % approaches to be benchmarked for k1 = 1:numel(datasizes) n = datasizes(k1); % Create random inputs vals = randi(200,1,n); runs = [5000 randi(200,1,n-1)]; % 5000 acts as an aberration for k2 = 1:numel(fcns) % Time approaches tsec(k2,k1) = timeit(@() feval(fcns{k2}, vals,runs), 1); end end figure, % Plot runtimes loglog(datasizes,tsec(1,:),'-bo'), hold on loglog(datasizes,tsec(2,:),'-k+') set(gca,'xgrid','on'),set(gca,'ygrid','on'), xlabel('Datasize ->'), ylabel('Runtimes (s)') legend(upper(strrep(fcns,'_',' '))),title('Runtime Plot') figure, % Plot speedups semilogx(datasizes,tsec(1,:)./tsec(2,:),'-rx') set(gca,'ygrid','on'), xlabel('Datasize ->') legend('Speedup(x) with cumsum+diff over cumsum-only'),title('Speedup Plot') rld_cumsum.m关联功能代码: function out = rld_cumsum(vals,runlens) index = zeros(1,sum(runlens)); index([1 cumsum(runlens(1:end-1))+1]) = 1; out = vals(cumsum(index)); return; 运行时和加速图 ![]() ![]() 结论 cumsum-only使用cumsum-only方法相比,建议的方法似乎使我们有了明显的提速,后者约为3倍 ! 为什么这种基于cumsum+diff的新方法比以前cumsum-only更好? 好了,原因就在于在了最后一步的本质cumsum-only做法,需要以“cumsumed”值映射到vals 。在新的cumsum+diff为基础的方法,我们正在做diff(vals)代替用于其MATLAB是处理只n元件相比的映射(其中n是游程长度的数量) sum(runLengths)的元素的数目为cumsum-only方法,并且该数字必须是n许多倍,因此,使用这种新方法的速度明显提高! 更多&回答... |
![]() |
![]() |