我有一个包含随机数矩阵的单元格,比如说a = {[300*20],....,[300*20]};
。我有另一个相同格式的单元格,称为它b
,其中包含nan
术语在 中位置的逻辑a
。
我想用来cellfun
循环遍历单元格,基本上让nan
术语等于0
ie a(b)=0
。
谢谢,j
我有一个包含随机数矩阵的单元格,比如说a = {[300*20],....,[300*20]};
。我有另一个相同格式的单元格,称为它b
,其中包含nan
术语在 中位置的逻辑a
。
我想用来cellfun
循环遍历单元格,基本上让nan
术语等于0
ie a(b)=0
。
谢谢,j
您可以定义一个将任何 NaN 替换为零的函数。
function a = nan2zero(a)
a(isnan(a)) = 0;
然后您可以使用cellfun
将此函数应用于您的单元格数组。
a0 = cellfun(@nan2zero, a, 'UniformOutput', 0)
这样,您甚至不需要任何矩阵b
。
首先,您可能应该给@s.bandara打勾,因为这是第一个正确答案并且它使用cellfun
(如您要求的那样)。不要给这个答案。这个答案的目的是提供一些额外的分析。
我想我会研究解决这个问题的一些可能方法的效率。
第一种方法是@s.bandara 提倡的方法。
第二种方法类似于@s.bandara 提倡的方法,但它使用b
转换nan
为0
,而不是使用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
. 但我不会因此而失眠。请记住,任何模拟的结果都特定于指定的输入。
请注意,这些结果在多次运行中是一致的,我使用tic
并toc
执行此操作,尽管每种方法都有许多循环。如果我想真正彻底,我应该使用timeit
FEX。如果有人感兴趣,这三种方法的代码如下:
%# 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 = 1000
、N = 100
、Q = 50
和M = 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 的解决方案设法领先。
唔。
鉴于元胞数组内容的性质,可能存在更快的解决方案:您可以将元胞数据转换为单个矩阵并使用向量索引NaN
一次替换其中的所有值,而无需cellfun
or 循环:
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 中,向量化操作通常要快得多。