[英]Mablab/Octave - use cellfun to index one matrix with another
我有一个包含随机数矩阵的单元格,比如a = {[300*20],....,[300*20]};
。 我有相同的格式的另一个细胞,称之为b
,包含位置的逻辑值nan
来讲a
。
我想使用cellfun
循环遍历单元格,基本上让nan
项等于0
即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
里面的功能,所以它应该被视为“通过参考”。
第三种方法使用循环来使用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
来做到这一点,尽管每个方法都有很多循环。 如果我想要非常彻底,我应该使用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 = 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
或循环:
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中,矢量化操作通常要快得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.