创建一个水平拉伸的上三角矩阵。

3
我想创建一个类似于上三角矩阵的4x12矩阵,它看起来像这样:
1 1 1 1 1 1 1 1 1 1 1 1  
0 0 0 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 1 1 1

所以我的问题是,创建它最有效的方法是什么?不使用循环或cellfun。谢谢。
4个回答

2

一种向量化的方法 -

nrows = 4;
ncols = 12;

row_idx = repmat(1:nrows,ncols/nrows,1)
out = bsxfun(@le,[1:nrows]',row_idx(:).')

2
创建一个由1组成的上三角矩阵,交换第二和第三维度,沿第二维度重复,再按所需形状进行重塑:
m = 4;
n = 12;
result = reshape(repmat(permute(triu(ones(m,m)), [1 3 2]), [1 n/m 1]), [m n]);

干得好!“repelem”似乎不仅方便,而且速度也很快! - Luis Mendo

2

使用新引入的repelem函数是Matlab R2015a及更高版本的做法:

n = 4;
m = 3;
out = repelem(triu(ones(n)),1,m);

out =

     1     1     1     1     1     1     1     1     1     1     1     1
     0     0     0     1     1     1     1     1     1     1     1     1
     0     0     0     0     0     0     1     1     1     1     1     1
     0     0     0     0     0     0     0     0     0     1     1     1

这个方法似乎比bsxfun更快,尽管我不太敢相信 ;)


基准测试

不幸的是,由于它不完整且我没有完全理解,所以我不能考虑andrew的解决方案

function [t] = bench()

   n = 4;
   m = 12;
   t = zeros(3,15);
   for ii = 1:15
        fcns = {
            @() thewaywewalk(ii*n,ii*m);
            @() Divakar(ii*n,ii*m);
            @() LuisMendo(ii*n,ii*m);
        };
        % timeit
        for jj = 1:100;
            t(:,ii) = t(:,ii) + cellfun(@timeit, fcns);
        end
   end

   plot(1:15,t(1,:)); hold on;
   plot(1:15,t(2,:)); hold on;
   plot(1:15,t(3,:)); hold on;
   xlabel('Matrix size: n = x*4, m = x*12')
   ylabel('timing')
   legend({'thewaywewalk','Divakar','Luis Mendo'},'location','northwest')

end
function Z = thewaywewalk(n,m) 
    Z = repelem(triu(ones(n)),1,m/n);
end
function Z = Divakar(n,m)  
    row_idx = repmat(1:n,m/n,1);
    Z = bsxfun(@le,[1:n]',row_idx(:).');
end
function Z = LuisMendo(n,m)
    Z = reshape(repmat(permute(triu(ones(n,n)), [1 3 2]), [1 m/n 1]), [n m]);
end

第一结论 - 小矩阵:

新的repelem表现很好,但reshape(repmat(permute...也不错。对于某些中等大小的矩阵,bsxfun方法稍逊一筹,但对于大矩阵,则成为领导者:

第二结论 - 大矩阵:

正如Divakar所预测的那样,对于较大的矩阵,bsxfun是最快的,事实上,这是可以预料的,因为bsxfun总是最快的!有趣的是,其他两个方法完全对齐,可以猜测它们在内部几乎是相同的。

enter image description here


尝试将数据大小再增加一些,例如 n = 40m = 120?那样的话图表会有很大的不同。 - Divakar
我看到了,但我仍然认为这些对于一个适当的基准测试来说太小了。 - Divakar
@Divakar 我将使用 for ii = 1:10:150 运行循环,让我们看看结果如何。我也对 bsxfun 的跳跃感到惊讶。 - Robert Seifert
别担心,惊喜已经消失了 :) - Divakar
不用谢,我受到了打败bsxfun的可能性的激励,但那是一项毫无意义的任务... - Robert Seifert
显示剩余4条评论

0

根据您的Matlab版本而定

m = 4;
n = 12;

dec2bin(bitshift(num,-1*[0:n/m:n-1])) %this prints out a string

这些应该是逻辑数组(我没有这两个,所以无法测试)

decimalToBinaryVector(bitshift(num,-1*[0:n/m:n-1]))

de2bi(bitshift(num,-1*[0:n/m:n-1]))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接