假设
x = [x1; x2; ...; xn]
其中每个xi是长度为l(i)
的列向量。我们可以设置L = sum(l)
的总长度x
。我想基于x生成2个矩阵:
我们称它们为A
和B
。例如,当x
仅作为2个块x1
和x2
时,则:
A = [x1 * x1'零(l(1),l(2)); zeros(l(2),l(1)),x2 * x2'];
B = [x1个零(l(1),1); zeros(l(2),1),x2];
在问题的表示中,A
始终是L
的{{1}},L
始终是B
的{{1}}。我可以使用循环在给定L
的情况下生成n
和A
,但这很繁琐。是否有一种聪明的(无循环)方式生成B
和x
。我正在使用MATLAB 2018b,但如有必要,您可以假定使用早期版本的MATLAB。
答案 0 :(得分:4)
以下应该起作用。在这种情况下,我无法高效转换为单元阵列,因此可能会有更有效的实现方式。
cuml = [0; cumsum(l(:))];
get_x = @(idx) x((1:l(idx))+cuml(idx));
x_cell = arrayfun(get_x, 1:numel(l), 'UniformOutput', false);
B = blkdiag(x_cell{:});
A = B*B';
修改
运行一些基准测试后,我发现基于直接循环的实现速度大约是上述基于单元的方法的两倍。
A = zeros(sum(l));
B = zeros(sum(l), numel(l));
prev = 0;
for idx = 1:numel(l)
xidx = (1:l(idx))+prev;
A(xidx, xidx) = x(xidx,1) * x(xidx,1)';
B(xidx, idx) = x(idx,1);
prev = prev + l(idx);
end
答案 1 :(得分:4)
这是另一种方法:
s = repelem(1:numel(l), l).';
t = accumarray(s, x, [], @(x){x*x'});
A = blkdiag(t{:});
t = accumarray(s, x, [], @(x){x});
B = blkdiag(t{:});
答案 2 :(得分:4)
我认为这既简短又快速:
B = x .* (repelem((1:numel(l)).',l)==(1:numel(l)));
A = B * B.';
如果数据量较大,最好使用稀疏矩阵:
B = sparse(1:numel(x), repelem(1:numel(l), l), x);
A = B * B.';