查找超过给定值的数组元素的总和?
Finding sums of array elements that exceed a given value?
为此,我正在尝试利用 MATLAB 中的矢量化,但我可能不得不求助于 for
循环。我真的不想那样做!是时候学习算法了。
给定这个(11×3)数组:
x = [...
4.9000 -0.1000 -5.1000
4.6000 -0.4000 -5.4000
3.0000 -2.0000 -7.0000
2.9000 -2.1000 -7.1000
2.9000 -2.1000 -7.1000
2.9000 -2.1000 -7.1000
2.8000 -2.2000 -7.2000
2.7000 -2.3000 -7.3000
2.7000 -2.3000 -7.3000
2.2000 -2.8000 -7.8000
1.8000 -3.2000 -8.2000
];
我想找出数组中 11 个元素的所有 3^11 = 177147 个可能的总和,其中 11 个元素中的每一个都来自不同的行。然后,我想将超过阈值 16.0 的总和以及构成每个总和的 11 个元素存储在一个(12×?)数组中。
任何让我开始的想法?感谢您的帮助。
我认为没有比使用 for 循环更好的运气了。可能有一个用于生成所有 3^11 组合的 Matlab 函数,并将其用作一种索引,但那样会消耗大量内存。
代码也很难阅读。
但是,最新版本的 Matlab 对于 for 循环的表现并没有那么糟糕,因为它们 JIT 代码。在它只是被解释之前,或者 JIT-ing 用于特定目的。因此,您不想在 Matlab 中重新实现矩阵例程,但对于像这样的简单代码,它应该表现良好。
以下是如何以矢量化方式执行此操作:
TR = 16;
sets = num2cell(single(x),2);
c = cell(1, numel(sets));
[c{:}] = ndgrid( sets{:} );
cartProd = cell2mat( cellfun(@(v)v(:), c, 'UniformOutput',false) );
validRows = cartProd(sum(cartProd,2) > TR,:); % output is [353x11]
请注意我如何使用 single
来保存 space 并使计算速度稍快。
以上解决方案改编自 this 答案。
经过进一步的思考,我想我已经想出了一个既更快又更节省内存的方法。我们通过 索引 x
,然后在索引 上执行前面的过程 。为什么这样更好,你可能会问?这是因为我们可以将索引存储为 uint8
,这比 double
甚至 single
消耗的内存要少得多。我们还可以保持 x
的完整 double
精度。因此:
function validRows = q42933114(x,thresh)
%% Input handling
if nargin < 2
thresh = 16;
end
if nargin < 1
x = [...
4.9000 -0.1000 -5.1000
4.6000 -0.4000 -5.4000
3.0000 -2.0000 -7.0000
2.9000 -2.1000 -7.1000
2.9000 -2.1000 -7.1000
2.9000 -2.1000 -7.1000
2.8000 -2.2000 -7.2000
2.7000 -2.3000 -7.3000
2.7000 -2.3000 -7.3000
2.2000 -2.8000 -7.8000
1.8000 -3.2000 -8.2000
];
end
I = reshape(uint8(1:numel(x)),size(x));
sets = num2cell(I,2);
c = cell(1, numel(sets));
[c{:}] = ndgrid( sets{:} );
cartProd = cell2mat( cellfun(@(v)v(:), c, 'UniformOutput',false) );
validRows = x(cartProd(sum(x(cartProd),2) > thresh,:));
内存消耗比较:
方法一(旧):
>> whos
Name Size Bytes Class Attributes
c 1x11 7795700 cell
cartProd 177147x11 7794468 single
sets 11x1 1364 cell
validRows 353x11 15532 single
方法二(新):
>> whos
Name Size Bytes Class Attributes
c 1x11 1949849 cell
cartProd 177147x11 1948617 uint8
sets 11x1 1265 cell
validRows 353x11 31064 double
我们看到内存消耗确实较小(大约 4 倍),符合预期。
运行时比较:
Method 1 -- 0.0110
Method 2 -- 0.0186
这里我们看到2nd的方法其实慢了一点。在对此进行分析时,我们发现原因是 x(...)
相对昂贵。
我是这样做的。变量名显然还有改进的余地。
注意有353
行匹配,这与@Dev-iL的回答一致。
p = 11;
[a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11] = ...
ndgrid(x(1,:),x(2,:),x(3,:),x(4,:),x(5,:),x(6,:),x(7,:),x(8,:),x(9,:),x(10,:),x(11,:));
a = a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11;
y = spalloc(p+1,3^p,(p+1)*3^p);
for i = 1:3^p
if a(i) >= 16.1
y(:,i) = [a1(i),a2(i),a3(i),a4(i),a5(i),a6(i),a7(i),a8(i),a9(i),a10(i),a11(i),a(i)];
end
end
nnz(y(p+1,:)); % 353 rows matching the criteria
为此,我正在尝试利用 MATLAB 中的矢量化,但我可能不得不求助于 for
循环。我真的不想那样做!是时候学习算法了。
给定这个(11×3)数组:
x = [...
4.9000 -0.1000 -5.1000
4.6000 -0.4000 -5.4000
3.0000 -2.0000 -7.0000
2.9000 -2.1000 -7.1000
2.9000 -2.1000 -7.1000
2.9000 -2.1000 -7.1000
2.8000 -2.2000 -7.2000
2.7000 -2.3000 -7.3000
2.7000 -2.3000 -7.3000
2.2000 -2.8000 -7.8000
1.8000 -3.2000 -8.2000
];
我想找出数组中 11 个元素的所有 3^11 = 177147 个可能的总和,其中 11 个元素中的每一个都来自不同的行。然后,我想将超过阈值 16.0 的总和以及构成每个总和的 11 个元素存储在一个(12×?)数组中。
任何让我开始的想法?感谢您的帮助。
我认为没有比使用 for 循环更好的运气了。可能有一个用于生成所有 3^11 组合的 Matlab 函数,并将其用作一种索引,但那样会消耗大量内存。
代码也很难阅读。
但是,最新版本的 Matlab 对于 for 循环的表现并没有那么糟糕,因为它们 JIT 代码。在它只是被解释之前,或者 JIT-ing 用于特定目的。因此,您不想在 Matlab 中重新实现矩阵例程,但对于像这样的简单代码,它应该表现良好。
以下是如何以矢量化方式执行此操作:
TR = 16;
sets = num2cell(single(x),2);
c = cell(1, numel(sets));
[c{:}] = ndgrid( sets{:} );
cartProd = cell2mat( cellfun(@(v)v(:), c, 'UniformOutput',false) );
validRows = cartProd(sum(cartProd,2) > TR,:); % output is [353x11]
请注意我如何使用 single
来保存 space 并使计算速度稍快。
以上解决方案改编自 this 答案。
经过进一步的思考,我想我已经想出了一个既更快又更节省内存的方法。我们通过 索引 x
,然后在索引 上执行前面的过程 。为什么这样更好,你可能会问?这是因为我们可以将索引存储为 uint8
,这比 double
甚至 single
消耗的内存要少得多。我们还可以保持 x
的完整 double
精度。因此:
function validRows = q42933114(x,thresh)
%% Input handling
if nargin < 2
thresh = 16;
end
if nargin < 1
x = [...
4.9000 -0.1000 -5.1000
4.6000 -0.4000 -5.4000
3.0000 -2.0000 -7.0000
2.9000 -2.1000 -7.1000
2.9000 -2.1000 -7.1000
2.9000 -2.1000 -7.1000
2.8000 -2.2000 -7.2000
2.7000 -2.3000 -7.3000
2.7000 -2.3000 -7.3000
2.2000 -2.8000 -7.8000
1.8000 -3.2000 -8.2000
];
end
I = reshape(uint8(1:numel(x)),size(x));
sets = num2cell(I,2);
c = cell(1, numel(sets));
[c{:}] = ndgrid( sets{:} );
cartProd = cell2mat( cellfun(@(v)v(:), c, 'UniformOutput',false) );
validRows = x(cartProd(sum(x(cartProd),2) > thresh,:));
内存消耗比较:
方法一(旧):
>> whos
Name Size Bytes Class Attributes
c 1x11 7795700 cell
cartProd 177147x11 7794468 single
sets 11x1 1364 cell
validRows 353x11 15532 single
方法二(新):
>> whos
Name Size Bytes Class Attributes
c 1x11 1949849 cell
cartProd 177147x11 1948617 uint8
sets 11x1 1265 cell
validRows 353x11 31064 double
我们看到内存消耗确实较小(大约 4 倍),符合预期。
运行时比较:
Method 1 -- 0.0110
Method 2 -- 0.0186
这里我们看到2nd的方法其实慢了一点。在对此进行分析时,我们发现原因是 x(...)
相对昂贵。
我是这样做的。变量名显然还有改进的余地。
注意有353
行匹配,这与@Dev-iL的回答一致。
p = 11;
[a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11] = ...
ndgrid(x(1,:),x(2,:),x(3,:),x(4,:),x(5,:),x(6,:),x(7,:),x(8,:),x(9,:),x(10,:),x(11,:));
a = a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11;
y = spalloc(p+1,3^p,(p+1)*3^p);
for i = 1:3^p
if a(i) >= 16.1
y(:,i) = [a1(i),a2(i),a3(i),a4(i),a5(i),a6(i),a7(i),a8(i),a9(i),a10(i),a11(i),a(i)];
end
end
nnz(y(p+1,:)); % 353 rows matching the criteria