快速列子集选择

Fast column subset selection

select 为每一列预定义的子集并将所有内容存储在一个单元格中的最快方法是什么?

这意味着我有一个双矩阵

DAT

维度为 n x m

和一个select离子矩阵

SEL

维度为 n x m。矩阵 'SEL' 是一个逻辑矩阵。

现在我想 select 为 'DAT' 的每一列根据 'SEL'。

一种可能的方式显然是:

arrayfun(@(idx) DAT(idx,SEL(idx,:)),(1:n)','uni',false); 

是否可以加快速度?

更新: 1.所有矩阵都是稀疏的 2. n = 1800000, m = 800

这可能是一种替代方法 -

%// Since we are storing elements from each row, we need to transpose them,
%// so that we could select elements from SEL along the first row, then second
%// row and so on.
DAT_t = DAT.';           %//'
allvals = DAT_t(SEL.');  %//'

%// Create an ID array to be used with ACCUMARRAY later on
cumlens = cumsum(sum(SEL,2));
id = zeros(cumlens(end),1); %// Faster with: id(cumlens(end),1)=0;
id([1 ; cumlens(1:end-1)+1])=1;

%// Finally use ACCUMARRAY for creating cells of output cell array based on
%// IDs from "id" and data from DAT
outc = accumarray(cumsum(id),allvals,[],@(x) {x});

显然,一些快速运行时测试证实,这种提议的方法在输入数据量非常大的情况下提供了边际性能提升。因此,对于 8000 x 8000 大小的输入数组,使用 timeit 计时的运行时间为 -

time_arrayfun =
    1.5076
time_accum =
    1.4776

此外,请注意,我们花费了大量时间将 DATSEL 转置为 allvals,因为我们只会在 allvals = DAT(SEL)那种情况。因此,如果您存储每一列而不是每一行的数据 DAT,性能提升会更加明显!

这是另一种方法。对于列:

s = bsxfun(@times, SEL, 1:size(SEL,2));
result = accumarray(nonzeros(s), DAT(SEL), [], @(x) {x});

对于行,只需转置 DATSEL:

DAT = DAT.';
SEL = SEL.';
s = bsxfun(@times, SEL, 1:size(SEL,2));
result = accumarray(nonzeros(s), DAT(SEL), [], @(x) {x});