3

In accumarray() the first note about 'subs', first appeared in the MATLAB R14sp3 docs, says:

Note If the subscripts in subs are not sorted, fun should not depend on the order of the values in its input data.

It is not clear to me what is considered to be sorted. Suppose:

subs = [1 1
        2 1
        1 2
        2 2];
  1. shall subs be sorted in the sense issorted(subs,'rows'), or ...
  2. in the linear indexing sense, i.e. issorted(sub2ind([2 2],subs(:,1), subs(:,2)))

I would like to rely on:

accumarray(subs,val,[], @(x) x(end))

If somebody could also provide examples/tests from older releases (to check for backward compatibility) where e.g. 1) is false while 2) is true, that would be great.

PS. I am mostly not interested in alternatives to accumarray, unless very succinct and using the same subs and val.

4

1 に答える 1

3

わかりましたいくつかのテストを行いましたが、引用の「ソート」は線形インデックス付けの意味であると思います。(それが重要な場合、私はR2013aを使用しています)

accumarray指定された関数がどのように呼び出されるかを理解するために、適用される関数として指定することで値を cellarray にグループ化するトリックを使用します。fun = @(x) {x}

1) 1D インデックス

まず、いくつかの添え字と値を作成しましょう

N = 10; sz = 4;
subs = randi([1 sz], [N 1]);
vals = (1:N)'*100;

次に、ソートされていないインデックスで ACCUMARRAY を呼び出します (複数回)

C = cell(5,1);
for i=1:5
    C{i} = accumarray(subs, vals, [], @(x){x});
end

関数に渡される値の順序は任意ですが、複数回実行しても一貫しています。

>> assert(isequal(C{:}))
>> celldisp(C{1})
ans{1} =
   800
   900
   700
ans{2} =
   300
ans{3} =
        1000
         200
         100
ans{4} =
   400
   600
   500

funこれが、渡された値の順序に依存してはならないことをドキュメントが警告する理由です。

ここで、添字を事前にソートすると、次のようになります。

[~,ord] = sort(subs);
C = cell(5,1);
for i=1:5
    C{i} = accumarray(subs(ord), vals(ord), [], @(x){x});
end
assert(isequal(C{:}))
celldisp(C{1})

値がソートされた関数に渡されることがわかります。

ans{1} =
   700
   800
   900
ans{2} =
   300
ans{3} =
         100
         200
        1000
ans{4} =
   400
   500
   600

2) 2D インデックス

2D添え字インデックスの場合も同じことを試しました。まず、ランダム データから始めます。

%# some 2d subscripts and corresponding values
N = 10; sz = 2;
subs = randi([1 sz], [N 2]);
vals = (1:N)*100;
  • ソートされていないインデックスの場合は次のとおりです。

    C = cell(5,1);
    for i=1:5
        C{i} = accumarray(subs, vals, [], @(x){x});
    end
    assert(isequal(C{:}))
    celldisp(C{1})
    
  • 「行による並べ替え」を試みたときは次のとおりです。

    [~,ord] = sortrows(subs, [1 2]);
    C = cell(5,1);
    for i=1:5
        C{i} = accumarray(subs(ord,:), vals(ord), [], @(x){x});
    end
    assert(isequal(C{:}))
    celldisp(C{1})
    
  • そして最後に、 「線形インデックス」でソートすると次のようになります。

    [~,ord] = sort(sub2ind([sz sz], subs(:,1), subs(:,2)));
    C = cell(5,1);
    for i=1:5
        C{i} = accumarray(subs(ord,:), vals(ord), [], @(x){x});
    end
    assert(isequal(C{:}))
    celldisp(C{1})
    

長い出力は省略し、値が関数 orders に渡された最後のケースのみを報告します。したがって、「ソートされた」基準は線形インデックスに基づいていると結論付けています。

ans{1,1} =
     []
ans{2,1} =
   200
   600
   700
ans{1,2} =
         100
         300
         400
         500
        1000
ans{2,2} =
   800
   900

ボーナス:

代わりに次の関数を使用してみてください。

function out = fun(x)
    out = {x};
    disp('[')
    disp(x)
    disp(']')
end

関数が予測できない方法で呼び出されていることがわかります。このような動作を確認するには、データのサイズを大きくする必要があるかもしれません...


下位互換性に関する限り、ドキュメントでは、このメモは MATLAB R14sp3までさかのぼって言及されていますが、 R14sp2では言及されていません。2005 年以降に文書化されているという事実を考えると、この機能に頼っても安全だと思います (このような古いバージョンを使用している人は、新しいコードがとにかく機能することを期待しているとは思えません!)

于 2013-07-08T23:16:34.693 に答える