Matlab / Octave - 使用cellfun将一个矩阵与另一个矩阵索引

时间:2013-01-15 03:59:56

标签: matlab indexing cell octave matrix-indexing

我有一个包含随机数矩阵的单元格,比如a = {[300*20],....,[300*20]};。我有另一个格式相同的单元格,称之为b,其中包含nana字词位置的逻辑。

我想使用cellfun循环遍历单元格,基本上让nan字词等于0,即a(b)=0

谢谢, Ĵ

3 个答案:

答案 0 :(得分:3)

您可以定义一个用零替换任何NaN的函数。

function a = nan2zero(a)
  a(isnan(a)) = 0;

然后您可以使用cellfun将此函数应用于您的单元格数组。

a0 = cellfun(@nan2zero, a, 'UniformOutput', 0)

这样,你甚至不需要任何矩阵b

答案 1 :(得分:2)

首先,你应该给@ s.bandara打勾,因为这是第一个正确的答案,它使用了cellfun(按你的要求)。不要给它这个答案。这个答案的目的是提供一些额外的分析。

我以为我会研究解决这个问题的一些可能方法的效率。

第一种方法是@ s.bandara倡导的方法。

第二种方法类似于@ s.bandara提倡的方法,但它使用bnan转换为0,而不是使用isnan。从理论上讲,这种方法可能更快,因为函数内部没有赋值b,因此应该将其视为“By Ref”。

第三种方法使用循环来使用cellfun,因为cellfun is often slower than an explicit loop

快速测试的结果是:

Elapsed time is 3.882972 seconds. %# First approach (a, isnan, and cellfun, eg @s.bandara)
Elapsed time is 3.391190 seconds. %# Second approach (a, b, and cellfun)
Elapsed time is 3.041992 seconds. %# Third approach (loop-based solution)

换句话说,通过传递b而不是使用isnan可以节省(小额)。并且通过使用循环而不是cellfun可以进一步节省(小额)。但我不会因此而失眠。请记住,任何模拟的结果都特定于指定的输入。

请注意,这些结果在多次运行中都是一致的,我使用tictoc来执行此操作,尽管每个方法都有许多循环。如果我想要非常彻底,我应该使用FEX中的timeit。如果有人有兴趣,这三种方法的代码如下:

%# Build some example matrices
T = 1000; N = 100; Q = 50; M = 100;
a = cell(1, Q); b = cell(1, Q);
for q = 1:Q
    a{q} = randn(T, N);
    b{q} = logical(randi(2, T, N) - 1);
    a{q}(b{q}) = nan;
end

%# Solution using a, isnan, and cellfun (@s.bandara solution)
tic
for m = 1:M
    Soln2 = cellfun(@f1, a, 'UniformOutput', 0);
end
toc

%# Solution using a, b, and cellfun
tic
for m = 1:M
    Soln1 = cellfun(@f2, a, b, 'UniformOutput', 0);
end
toc


%# Solution using a loop to avoid cellfun
tic
for m = 1:M
    Soln3 = cell(1, Q);
    for q = 1:Q
        Soln3{q} = a{q};
        Soln3{q}(b{q}) = 0;
    end
end
toc

%# Solution proposed by @EitanT
[K, N] = size(a{1});
tic
for m = 1:M
    a0 = [a{:}];       %// Concatenate matrices along the 2nd dimension
    a0(isnan(a0)) = 0; %// Replace NaNs with zeroes    
    Soln4 = mat2cell(a0, K, N * ones(size(a)));
end
toc

其中:

function x1 = f1(x1)
x1(isnan(x1)) = 0;

function x1 = f2(x1, x2)
x1(x2) = 0;

更新: @EitanT建议采用第四种方法。这种方法将矩阵的单元阵列连接成一个大矩阵,对大矩阵执行操作,然后可选地将其转换回单元阵列。我已将此过程的代码添加到上面的测试例程中。对于我的测试代码中指定的输入,即T = 1000N = 100Q = 50M = 100,定时运行如下:

Elapsed time is 3.916690 seconds. %# @s.bandara
Elapsed time is 3.362319 seconds. %# a, b, and cellfun
Elapsed time is 2.906029 seconds. %# loop-based solution
Elapsed time is 4.986837 seconds. %# @EitanT

我对此感到有些惊讶,因为我认为@EitanT的方法会产生最好的效果。在纸面上,它似乎非常明智。注意,我们当然可以乱用输入参数来查找具有不同解决方案优势的特定设置。例如,如果矩阵很小,但它们的数量很大,那么@EitanT的方法就很好,例如T = 10N = 5Q = 500和{{1}产量:

M = 100

这里@EitanT的方法占主导地位。

对于OP指出的问题的规模,我发现基于循环的解决方案通常具有最佳性能。但是,对于某些Elapsed time is 0.362377 seconds. %# @s.bandara Elapsed time is 0.299595 seconds. %# a, b, and cellfun Elapsed time is 0.352112 seconds. %# loop-based solution Elapsed time is 0.030150 seconds. %# @EitanT ,例如Q,@ EitanT的解决方案成功地领先。

答案 2 :(得分:1)

嗯。

鉴于您的单元格数组的内容的性质,可能存在一个甚至更快的解决方案:您可以将您的单元格数据转换为单个矩阵并使用向量索引来替换所有{{1}其中的值一次,不需要NaN或循环:

cellfun

如果要将其转换回单元格数组,那很好:

a0 = [a{:}];       %// Concatenate matrices along the 2nd dimension
a0(isnan(a0)) = 0; %// Replace NaNs with zeroes

P.S。
如果可能的话,使用3-D矩阵而不是单元阵列。在MATLAB中,矢量化操作通常要快得多。