2

我有一个大矩阵 M (nxm)。我将把存储在向量中的索引指定的一些元素总结为单元格元素。有许多组索引,因此单元格具有多个元素。例如

M = rand(2103, 2030);
index{1} = [1 3 2 4 53 5 23 3];
index{2} = [2 3 1 3 23 10234 2032];
% ...
index{2032} = ...;

我要总结 index{1} 处的所有元素,总结 index{2} 处的所有元素 ...,现在我正在使用循环

sums = zeros(1, 2032);
for n=1:2032
  sums(n) = sum(M(index{n}));
end

我想知道是否有任何方法可以使用单行命令而不是循环来做到这一点。使用循环非常慢。

4

2 回答 2

6

可能是一个经典的用法cellfun

sums = cellfun(@(idx) sum(M(idx)), index);

编辑:这是一个大型案例的基准测试,表明这种方法比 for 循环稍慢,但比 Eitan T 的方法快

M = rand(2103, 2030);
index = cell(1, 2032);
index{1} = [1 3 2 4 53 5 23 3];
index{2} = [2 3 1 3 23 10234 2032];

for n=3:2032
    index{n} = randi(numel(M), 1, randi(10000));
end

N = 1e1;
sums = zeros(1, 2032);
tic
for kk = 1:N
    for n=1:2032
        sums(n) = sum(M(index{n}));
    end
end
toc

tic
for kk = 1:N
    sums = cellfun(@(idx) sum(M(idx)), index);
end
toc

tic
for kk = 1:N
    sums = cumsum(M([index{:}]));
    sums = diff([0, sums(cumsum(cellfun('length', index)))]);
end
toc

结果是

Elapsed time is 2.072292 seconds.
Elapsed time is 2.139882 seconds.
Elapsed time is 2.669894 seconds.
于 2013-10-02T06:55:27.273 回答
1

也许不像单线那么优雅cellfun,但运行速度快了一个数量级以上:

sums = cumsum(M([index{:}]));
sums = diff([0, sums(cumsum(cellfun('length', index)))]);

对于大型输入,它的运行速度甚至比 JIT 加速循环快大约 4 或 5 倍。请注意,当其中的每个单元格index包含一个包含超过 ~2000 个元素的向量时,与循环 (and cellfun) 相比,这种方法的性能开始下降。

基准

M = rand(2103, 2030);
I = ceil(numel(M) * rand(2032, 10));
index = mat2cell(I, ones(size(I, 1), 1), size(I, 2));
N = 100;

tic
for k = 1:N
    sums = zeros(1, numel(index));
    for n = 1:numel(sums)
        sums(n) = sum(M(index{n}));
    end
end
toc

tic
for k = 1:N
    sums = cellfun(@(idx) sum(M(idx)), index);
end
toc

tic
for k = 1:N
    sums = cumsum(M([index{:}]));
    sums2 = diff([0, sums(cumsum(cellfun('length', index)))]);
end
toc

在 MATLAB 2012a(在 2.27GHz 16 核 Intel Xeon 处理器上运行的 Windows Server 2008 R2)中执行此操作时,我得到:

Elapsed time is 0.579783 seconds.
Elapsed time is 1.789809 seconds.
Elapsed time is 0.111455 seconds.
于 2013-10-02T08:33:10.727 回答