3

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

我想用来cellfun循环遍历单元格,基本上让nan术语等于0ie a(b)=0

谢谢,j

4

3 回答 3

3

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

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

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

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

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

于 2013-01-15T04:30:02.797 回答
2

首先,您可能应该给@s.bandara打勾,因为这是第一个正确答案并且它使用cellfun(如您要求的那样)。不要给这个答案。这个答案的目的是提供一些额外的分析。

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

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

第二种方法类似于@s.bandara 提倡的方法,但它使用b转换nan0,而不是使用isnan. 从理论上讲,这种方法可能更快,因为b函数内部没有分配任何内容,因此应该“按引用”处理。

第三种方法使用循环来绕过 using cellfun,因为cellfun 通常比显式循环慢

快速速度测试的结果是:

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执行此操作,尽管每种方法都有许多循环。如果我想真正彻底,我应该使用timeitFEX。如果有人感兴趣,这三种方法的代码如下:

%# 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 = 10, N = 5, Q = 500, 并M = 100产生:

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

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

对于 OP 指出的问题规模,我发现基于循环的解决方案通常具有最佳性能。然而,对于一些Q,例如Q = 5,@EitanT 的解决方案设法领先。

于 2013-01-15T05:06:09.377 回答
1

唔。

鉴于元胞数组内容的性质,可能存在更快的解决方案:您可以将元胞数据转换为单个矩阵并使用向量索引NaN一次替换其中的所有值,而无需cellfunor 循环:

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

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

[M, N] = size(a{1});
mat2cell(a0, M, N * ones(size(a)))

PS
如果可能,使用 3-D 矩阵而不是元胞数组。在 MATLAB 中,向量化操作通常要快得多。

于 2013-01-15T08:41:47.960 回答