arrayfun
これがとを使用した解決策ですcellfun
zarray = [1 2 3 4 5 6 7 8 9 10];
lengths = [1 3 2 1 3];
% Generate the indexes for the elements contained within each length specified
% subset. idx would be {[1], [4, 3, 2], [6, 5], [7], [10, 9, 8]} in this case
idx = arrayfun(@(a,b) a-(0:b-1), cumsum(lengths), lengths,'UniformOutput',false);
means = cellfun( @(a) mean(zarray(a)), idx);
希望する出力結果:
means =
1.0000 3.0000 5.5000 7.0000 9.0000
@tmpearceのコメントに続いて、上記のソリューション間でパフォーマンスをすばやく比較し、そこから次の関数を作成しました。subsetMeans1
function means = subsetMeans1( zarray, lengths)
% Generate the indexes for the elements contained within each length specified
% subset. idx would be {[1], [4, 3, 2], [6, 5], [7], [10, 9, 8]} in this case
idx = arrayfun(@(a,b) a-(0:b-1), cumsum(lengths), lengths,'UniformOutput',false);
means = cellfun( @(a) mean(zarray(a)), idx);
単純なforループの代替関数である関数subsetMeans2
。
function means = subsetMeans2( zarray, lengths)
% Method based on single loop
idx = 1;
N = length(lengths);
means = zeros( 1, N);
for i = 1:N
means(i) = mean( zarray(idx+(0:lengths(i)-1)) );
idx = idx+lengths(i);
end
TIMEITに基づく次のテストスクリプトを使用して、入力ベクトル上の要素の数とサブセットごとの要素のサイズを変化させてパフォーマンスをチェックできるようにします。
% Generate some data for the performance test
% Total of elements on the vector to test
nVec = 100000;
% Max of elements per subset
nSubset = 5;
% Data generation aux variables
lenghtsGen = randi( nSubset, 1, nVec);
accumLen = cumsum(lenghtsGen);
maxIdx = find( accumLen < nVec, 1, 'last' );
% % Original test data
% zarray = [1 2 3 4 5 6 7 8 9 10];
% lengths = [1 3 2 1 3];
% Vector to test
zarray = 1:nVec;
lengths = [ lenghtsGen(1:maxIdx) nVec-accumLen(maxIdx)] ;
% Double check that nVec is will be the max index
assert ( sum(lengths) == nVec)
t1(1) = timeit(@() subsetMeans1( zarray, lengths));
t1(2) = timeit(@() subsetMeans2( zarray, lengths));
fprintf('Time spent subsetMeans1: %f\n',t1(1));
fprintf('Time spent subsetMeans2: %f\n',t1(2));
おそらくこれらの関数の余分なオーバーヘッドが原因で、ベクトル化されていないバージョンの方が高速arrayfun
であることがわかります。cellfun
Time spent subsetMeans1: 2.082457
Time spent subsetMeans2: 1.278473